public static void SaveLocalRunInfo(LocalRunInfo localRunInfo) { var filePath = GetRunInfoJsonFile(); var jss = new JavaScriptSerializer(); File.WriteAllText(filePath, jss.Serialize(localRunInfo), Encoding.UTF8); }
public static void RunMainApp(LocalRunInfo localRunInfo, string msg = null) { try { var cmds = localRunInfo.AppRunCmd.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var exeDir = Path.GetFullPath(Path.GetDirectoryName(cmds[0])); var exeName = Path.GetFileName(cmds[0]); var fileName = Path.Combine(exeDir, exeName); if (!File.Exists(fileName)) { OnMainAppNotExists?.Invoke(localRunInfo); return; } var args = cmds.Skip(1).Concat(new string[] { "started_by_updater" }) .Aggregate(string.Empty, (_args, a) => _args += " " + a); RunFile(fileName, args); OnMainAppStarted?.Invoke(localRunInfo, msg); } catch (Exception ex) { LogHelper.LogErrorToServer($"程序启动失败({msg})", ex, localRunInfo); OnError?.Invoke(localRunInfo, ex); } }
private void OnNotSpecifyUpdateUrl(LocalRunInfo localRunInfo) { this.Invoke((Action)(() => { InputUpdateUrl(localRunInfo); })); }
private void OnMainAppStarted(LocalRunInfo localRunInfo, string msg) { this.Invoke((Action)(() => { if (string.IsNullOrEmpty(localRunInfo.ClientId)) { localRunInfo.ClientId = InputClientId(); } UpdateHelper.SaveLocalRunInfo(localRunInfo); _mainAppPath = localRunInfo.AppRunCmd.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0]; var urlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); this._config = UpdateHelper.GetSystemConfig(urlInfo.Host, urlInfo.SystemId); //var urlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); //this._config = UpdateHelper.GetSystemConfig(urlInfo.Host, urlInfo.SystemId); if (UpdateHelper.IsThisAppRunning() || !this._config.DetectEnabled) {// 保证更新程序只有一个在后台运行 Exit(localRunInfo); } else { StartUpdateDetect(localRunInfo, this._config); StartMainAppStateDetect(_mainAppPath, localRunInfo, this._config); } var appName = Path.GetFileName(_mainAppPath); notifyIcon.Text = this.Text = "更新检测-" + appName; LogHelper.LogInfoToServer($"程序启动成功({msg})", localRunInfo); })); }
private static bool IsMainAppRunning(LocalRunInfo localRunInfo) { var cmds = localRunInfo.AppRunCmd.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return(IsAppRunning(cmds[0])); }
private void OnUpdateError(LocalRunInfo localRunInfo, Exception ex) { this.Invoke((Action)(() => { LogHelper.LogError("更新出错", ex); _frmProgress.Hide(); if (MessageBox.Show(string.Format("{0}\r\n是否继续运行?", ex.Message), "错误", MessageBoxButtons.YesNo) == DialogResult.Yes) { if (string.IsNullOrEmpty(localRunInfo.AppRunCmd)) { InputStartApp(localRunInfo); } else { UpdateHelper.RunMainApp(localRunInfo); } } else { Exit(localRunInfo); } })); }
public static void LogInfoToServer(string info, LocalRunInfo localRunInfo) { var updateUrlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); string url = $"{updateUrlInfo.Host}/api/LogInfo/{updateUrlInfo.SystemId}?clientId={Util.GetClientId(localRunInfo.ClientId)}&info={info}"; Util.SendHttpRequest(url); }
private void OnBeginUpdate(LocalRunInfo obj) { this.Invoke((Action)(() => { Hide(); _frmProgress.Show(); })); }
private void OnMainAppNotExists(LocalRunInfo localRunInfo) { this.Invoke((Action)(() => { MessageBox.Show("启动程序不存在"); InputStartApp(localRunInfo); })); }
private void OnMainAppAlreadyRunning(LocalRunInfo localRunInfo) { this.Invoke((Action)(() => { MessageBox.Show("程序正在运行,请退出后再更新。", "提示", MessageBoxButtons.OK); Exit(localRunInfo); })); }
public MainAppStateDetector(string mainAppPath, LocalRunInfo localRunInfo, Config config) : base(config.PingInterval * 1000, true) { this.localRunInfo = localRunInfo; this.mainAppPath = mainAppPath; this.updateUrlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); this.clientId = Util.GetClientId(localRunInfo.ClientId); this.config = config; }
private void OnInvalidUpdateUrl(LocalRunInfo localRunInfo) { this.Invoke((Action)(() => { MessageBox.Show("更新地址有误"); InputUpdateUrl(localRunInfo); })); }
public static void LogErrorToServer(string msg, Exception ex, LocalRunInfo localRunInfo) { var updateUrlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); var error = $"{msg}:{ex.Message}{Environment.NewLine}{ex.StackTrace}"; string url = $"{updateUrlInfo.Host}/api/LogError/{updateUrlInfo.SystemId}?clientId={Util.GetClientId(localRunInfo.ClientId)}&error={error}"; Util.SendHttpRequest(url); }
/// <summary> /// 启动主程序状态检测 /// </summary> /// <param name="mainAppPath"></param> private void StartMainAppStateDetect(string mainAppPath, LocalRunInfo localRunInfo, Config config) { if (_mainAppStateDetector != null) { _mainAppStateDetector.Stop(); _mainAppStateDetector.OnMainAppsClose -= OnMainAppsClose; _mainAppStateDetector.OnCommandRequest -= OnServerCommandRequest; } _mainAppStateDetector = new MainAppStateDetector(mainAppPath, localRunInfo, config); _mainAppStateDetector.OnMainAppsClose += OnMainAppsClose; _mainAppStateDetector.OnCommandRequest += OnServerCommandRequest; _mainAppStateDetector.Start(); }
private void InputStartApp(LocalRunInfo localRunInfo) { FrmInput frm = new FrmInput("输入启动程序:", localRunInfo.AppRunCmd); if (frm.ShowDialog() == DialogResult.OK) { localRunInfo.AppRunCmd = frm.Value; UpdateHelper.RunMainApp(localRunInfo); } else { Exit(localRunInfo); } }
private void InputUpdateUrl(LocalRunInfo localRunInfo) { FrmInput frm = new FrmInput("输入更新地址:", localRunInfo.UpdateUrl); if (frm.ShowDialog() == DialogResult.OK) { localRunInfo.UpdateUrl = frm.Value; UpdateHelper.SaveLocalRunInfo(localRunInfo); UpdateHelper.Update("正常启动"); } else { Exit(localRunInfo); } }
/// <summary> /// 所有主程序关闭事件 /// </summary> /// <param name="detector"></param> private void OnMainAppsClose(MainAppStateDetector detector, LocalRunInfo localRunInfo) { this.Invoke((Action)(() => { if (!this._config.KeepUpdaterRunning) { Exit(null); } else if (this._config.KeepAppRunning) { if (!UpdateHelper.IsAppRunning(_mainAppPath)) { UpdateHelper.RunMainApp(localRunInfo, "由更新程序启动"); } } })); }
/// <summary> /// 启动更新检测 /// </summary> /// <param name="localRunInfo"></param> /// <param name="config"></param> private void StartUpdateDetect(LocalRunInfo localRunInfo, Config config) { if (_updateDetector != null) { _updateDetector.Stop(); _updateDetector.OnStart -= OnUpdateDetectorStart; _updateDetector.OnStop -= OnUpdateDetectorStop; _updateDetector.OnNotifyUpdate -= OnUpdateNotification; } UpdateUrlInfo info = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl); _updateDetector = new UpdateDetector(config.DetectInterval * 1000, info); _updateDetector.OnStart += OnUpdateDetectorStart; _updateDetector.OnStop += OnUpdateDetectorStop; _updateDetector.OnNotifyUpdate += OnUpdateNotification; _updateDetector.Start(); }
/// <summary> /// 运行服务端命令 /// </summary> /// <param name="cmd"></param> /// <param name="localRunInfo"></param> private void OnServerCommandRequest(ClientCommand cmd, LocalRunInfo localRunInfo) { switch (cmd.Type) { case ClientCommandType.Start: if (!UpdateHelper.IsAppRunning(_mainAppPath)) { UpdateHelper.RunMainApp(localRunInfo, "由服务端启动"); } break; case ClientCommandType.Stop: if (UpdateHelper.IsAppRunning(_mainAppPath)) { UpdateHelper.KillRunningApps(_mainAppPath); } break; default: break; } }
private void OnUpdateComplete( LocalRunInfo localRunInfo, IEnumerable <UpdateRunFile> fileDiff, List <string> failedUpdateFiles, List <string> failedDeleteFiles, bool initStart, bool runBat, string msg) { this.Invoke((Action)(() => { _frmProgress.Hide(); Show(); OnUpdateStatus("正在保存配置信息..."); UpdateHelper.SaveLocalRunInfo(localRunInfo); if (runBat) { OnUpdateStatus("正在做初始化工作..."); UpdateHelper.RunBat(); } if (!initStart && fileDiff.Count() > 0) { // 由于首次运行的时候更新的文件较多,不写更新日志 OnUpdateStatus("正在写更新日志..."); LogHelper.WriteUpdateLog(localRunInfo.Ver, fileDiff, failedUpdateFiles, failedDeleteFiles); } OnUpdateStatus("正在启动主程序..."); if (string.IsNullOrEmpty(localRunInfo.AppRunCmd)) { InputStartApp(localRunInfo); } else { UpdateHelper.RunMainApp(localRunInfo, msg); } })); }
internal static void Exit(LocalRunInfo localRunInfo) { Environment.Exit(0); }
/// <summary> /// 计算文件差异 /// </summary> /// <returns></returns> private static IEnumerable <UpdateRunFile> CalcDiff(LocalRunInfo localRunInfo, RemoteRunInfo remoteRunInfo) { var remoteVer = remoteRunInfo.Ver; //if(!string.IsNullOrEmpty(remoteVer) && // !remoteVer.Equals(localRunInfo.Ver)) //{ // 为提高效率,只有在版本不同时,才进行文件的差异比较 var runDir = Path.GetDirectoryName(Application.ExecutablePath); var localRunFiles = localRunInfo.RunFiles; var remoteRunFiles = remoteRunInfo.RunFiles; foreach (var rf in remoteRunFiles) { // 本地不存在或者MD5不同 var needUpdate = !localRunFiles.TryGetValue(rf.Key, out string localTag) || !rf.Value.Equals(localTag) || !File.Exists(Path.Combine(runDir, rf.Key)); if (needUpdate) { // update yield return(new UpdateRunFile { Path = rf.Key, Status = (Constants.RunInfoJsonFile.Equals(rf.Key, StringComparison.OrdinalIgnoreCase) || Constants.UpdateLogFile.Equals(rf.Key, StringComparison.OrdinalIgnoreCase)) ? UpdateRunFileStatus.SkipUpdate : UpdateRunFileStatus.Update, NewTag = rf.Value, OldTag = localTag }); } else { yield return(new UpdateRunFile { Path = rf.Key, Status = UpdateRunFileStatus.NotModified, OldTag = localTag, }); } if (localTag != null) { localRunFiles.Remove(rf.Key); } } // 剩下的本地文件需要删除 var thisExeName = Path.GetFileName(Application.ExecutablePath); foreach (var lf in localRunFiles) { yield return(new UpdateRunFile { Path = lf.Key, Status = lf.Key.Equals(thisExeName, StringComparison.OrdinalIgnoreCase) ? UpdateRunFileStatus.SkipDelete : UpdateRunFileStatus.Delete, OldTag = lf.Value, }); } //} //else //{ // foreach (var lf in localRunInfo.RunFiles) // { // yield return new UpdateRunFile // { // Path = lf.Key, // Status = UpdateRunFileStatus.NotModified, // Tag = lf.Value, // }; // } //} }
private static void UpdateInternal(string msg) { LocalRunInfo localRunInfo = null; UpdateUrlInfo updateUrlInfo = null; try { OnStatus?.Invoke("正在读取本地配置..."); localRunInfo = GetLocalRunInfo(); OnStatus?.Invoke("正在验证更新地址..."); if (string.IsNullOrEmpty(localRunInfo.UpdateUrl)) { OnNotSpecifyUpdateUrl?.Invoke(localRunInfo); return; } if ((updateUrlInfo = UpdateUrlInfo.Parse(localRunInfo.UpdateUrl)) == null) { OnInvalidUpdateUrl?.Invoke(localRunInfo); return; } OnStatus?.Invoke("正在读取服务器..."); var host = updateUrlInfo.Host; var systemId = updateUrlInfo.SystemId; var remoteRunInfo = GetRemoteRunInfo(GetRemoteInfoUrl(host, systemId)); OnStatus?.Invoke("正在检测差异..."); var initStart = (localRunInfo.RunFiles.Count == 0); var fileDiffResults = CalcDiff(localRunInfo, remoteRunInfo).ToList(); var filesToUpdate = fileDiffResults.Where(f => f.Status == UpdateRunFileStatus.Update || f.Status == UpdateRunFileStatus.Delete).ToList(); var progress = 0; var total = filesToUpdate.Count; if (total > 0) { OnStatus?.Invoke("正在检测运行程序..."); if (IsThisAppRunning() || (!string.IsNullOrEmpty(localRunInfo.AppRunCmd) && IsMainAppRunning(localRunInfo))) { OnMainAppAlreadyRunning?.Invoke(localRunInfo); return; } } OnStatus?.Invoke("开始更新程序..."); OnBeginUpdate?.Invoke(localRunInfo); var runDir = Path.GetDirectoryName(Application.ExecutablePath); var thisExeName = Path.GetFileName(Application.ExecutablePath); var runBat = false; var runFileResults = new DicIgnoreCase <string>(); var failedUpdateFiles = new List <string>(); var failedDeleteFiles = new List <string>(); foreach (var file in filesToUpdate) { if (Constants.BatFile.Equals(file.Path, StringComparison.OrdinalIgnoreCase)) { runBat = true; } if (file.Status == UpdateRunFileStatus.Update) { var url = GetRunFileUrl(host, systemId, file.Path); var localPath = Path.Combine(runDir, file.Path); var updateSelf = file.Path.Equals(thisExeName, StringComparison.OrdinalIgnoreCase); // 自更新 OnProcessFile?.Invoke("正在安装文件:" + localPath); var success = DownloadRunFile(url, localPath, possibllyInUse: updateSelf); if (!success) { failedUpdateFiles.Add(file.Path); // 对于更新失败的文件(非新增),新的配置文件应该仍包含更新前的文件标识 if (!string.IsNullOrEmpty(file.OldTag)) { runFileResults.Add(file.Path, file.OldTag); } } else { runFileResults.Add(file.Path, file.NewTag); } } else if (file.Status == UpdateRunFileStatus.Delete) { // 删除文件 var localPath = Path.Combine(runDir, file.Path); OnProcessFile?.Invoke("正在删除文件:" + localPath); if (!DeleteRunFile(localPath)) { failedDeleteFiles.Add(file.Path); // 对于删除失败的文件,新的配置文件应该仍包含旧的文件标识 runFileResults.Add(file.Path, file.OldTag); } } OnProgress?.Invoke((++progress) * 1.0 / total); } foreach (var f in fileDiffResults.Where(f => f.Status == UpdateRunFileStatus.NotModified)) { runFileResults.Add(f.Path, f.OldTag); } localRunInfo.Ver = remoteRunInfo.Ver; localRunInfo.RunFiles = runFileResults; OnComplete?.Invoke(localRunInfo, fileDiffResults, failedUpdateFiles, failedDeleteFiles, initStart, runBat, msg); } catch (Exception ex) { if (localRunInfo != null) { LogHelper.LogErrorToServer($"客户端更新失败({msg})", ex, localRunInfo); } OnError?.Invoke(localRunInfo, ex); } }