From be1639257155d96e99611658bef8d242fdbf147b Mon Sep 17 00:00:00 2001 From: dovholuknf <46322585+dovholuknf@users.noreply.github.com> Date: Sun, 1 Nov 2020 23:03:59 -0500 Subject: [PATCH] wip auto-update --- Installer/ZitiDesktopEdge.aip | 15 +- ZitiUpdateService/IUpdateCheck.cs | 15 ++ ZitiUpdateService/UpdateCheckers.cs | 88 +++++++++++ ZitiUpdateService/UpdateService.cs | 176 ++++++--------------- ZitiUpdateService/ZitiUpdateService.csproj | 2 + 5 files changed, 162 insertions(+), 134 deletions(-) create mode 100644 ZitiUpdateService/IUpdateCheck.cs create mode 100644 ZitiUpdateService/UpdateCheckers.cs diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip index 0a6bc5a8..20c3834b 100644 --- a/Installer/ZitiDesktopEdge.aip +++ b/Installer/ZitiDesktopEdge.aip @@ -8,7 +8,6 @@ - @@ -50,10 +49,12 @@ - + + + @@ -68,7 +69,6 @@ - @@ -80,9 +80,10 @@ + + - @@ -213,6 +214,8 @@ + + @@ -267,11 +270,11 @@ - + - + diff --git a/ZitiUpdateService/IUpdateCheck.cs b/ZitiUpdateService/IUpdateCheck.cs new file mode 100644 index 00000000..fb0a472d --- /dev/null +++ b/ZitiUpdateService/IUpdateCheck.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZitiUpdateService { + interface IUpdateCheck { + bool IsUpdateAvailable(Version current); + string FileName(); + void CopyUpdatePackage(string destinationFolder, string destinationName); + + bool AlreadyDownloaded(string destinationFolder, string destinationName); + } +} diff --git a/ZitiUpdateService/UpdateCheckers.cs b/ZitiUpdateService/UpdateCheckers.cs new file mode 100644 index 00000000..c70c5e46 --- /dev/null +++ b/ZitiUpdateService/UpdateCheckers.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using System.Net; + +using NLog; +using Newtonsoft.Json.Linq; + +namespace ZitiUpdateService { + internal class GithubCheck : IUpdateCheck { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + string url; + string downloadUrl = null; + string downloadFileName = null; + + public GithubCheck(string url) { + this.url = url; + } + + public bool AlreadyDownloaded(string destinationFolder, string destinationName) { + return File.Exists(Path.Combine(destinationFolder, destinationName)); + } + + public void CopyUpdatePackage(string destinationFolder, string destinationName) { + WebClient webClient = new WebClient(); + string dest = Path.Combine(destinationFolder, destinationName); + Logger.Info("download started: {0}", downloadUrl); + webClient.DownloadFile(downloadUrl, dest); + Logger.Info("download complete. file at {0}", dest); + } + + public string FileName() { + return downloadFileName; + } + + public bool IsUpdateAvailable(Version current) { + HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url); + httpWebRequest.Method = "GET"; + httpWebRequest.ContentType = "application/json"; + httpWebRequest.UserAgent = "OpenZiti UpdateService"; + HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()); + string result = streamReader.ReadToEnd(); + JObject json = JObject.Parse(result); + string serverVersion = json.Property("tag_name").Value.ToString() + ".0"; + + Version published = new Version(serverVersion); + int compare = current.CompareTo(published); + if (compare < 0) { + Logger.Info("an upgrade is available."); + } else if (compare > 0) { + Logger.Info("the version installed is newer than the released version"); + return false; + } + JArray assets = JArray.Parse(json.Property("assets").Value.ToString()); + foreach (JObject asset in assets.Children()) { + downloadUrl = asset.Property("browser_download_url").Value.ToString(); + break; + } + + if (downloadUrl == null) { + Logger.Error("DOWNLOAD URL not found at: {0}", url); + return false; + } + downloadFileName = downloadUrl.Substring(downloadUrl.LastIndexOf('/') + 1); + + return true; + } + } + + internal class FilesystemCheck : IUpdateCheck { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + public bool AlreadyDownloaded(string destinationFolder, string destinationName) { + return File.Exists(Path.Combine(destinationFolder, destinationName)); + } + + public void CopyUpdatePackage(string destinationFolder, string destinationName) { + throw new NotImplementedException(); + } + + public string FileName() { + return downloadFileName; + } + + public bool IsUpdateAvailable(Version current) { + throw new NotImplementedException(); + } + } +} diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs index 48d86951..d99dcd2e 100644 --- a/ZitiUpdateService/UpdateService.cs +++ b/ZitiUpdateService/UpdateService.cs @@ -18,6 +18,7 @@ using ZitiDesktopEdge.ServiceClient; using NLog; using Newtonsoft.Json.Linq; using System.Reflection; +using NLog.Config; namespace ZitiUpdateService { public partial class UpdateService : ServiceBase { @@ -25,29 +26,25 @@ namespace ZitiUpdateService { private string _version = ""; private bool _isNew = true; - + private System.Timers.Timer _updateTimer = new System.Timers.Timer(); private bool inUpdateCheck = false; private string _rootDirectory = ""; private string _logDirectory = ""; private string _versionType = "latest"; + private Client svc = new Client(); + private bool running = false; + ServiceController controller; public UpdateService() { InitializeComponent(); - Client svc = new Client(); + Logger.Info("Initializing"); svc.OnClientConnected += Svc_OnClientConnected; svc.OnTunnelStatusEvent += Svc_OnTunnelStatusEvent; svc.OnClientDisconnected += Svc_OnClientDisconnected; svc.OnShutdownEvent += Svc_OnShutdownEvent; - try { - svc.Connect(); - } catch { - svc.Reconnect(); - } - - svc.WaitForConnection(); } public void Debug() { @@ -55,6 +52,7 @@ namespace ZitiUpdateService { } protected override void OnStart(string[] args) { + try { if (ConfigurationManager.AppSettings.Get("Version") != null) _versionType = ConfigurationManager.AppSettings.Get("Version"); } catch (Exception e) { @@ -64,16 +62,29 @@ namespace ZitiUpdateService { if (!Directory.Exists(_rootDirectory)) Directory.CreateDirectory(_rootDirectory); _logDirectory = Path.Combine(_rootDirectory, "Logs"); if (!Directory.Exists(_logDirectory)) Directory.CreateDirectory(_logDirectory); - Logger.Info("Setup Watchers"); - SetupServiceWatchers(); + if (!running) { + running = true; + Task.Run(() => { + SetupServiceWatchers(); + }); + } + Logger.Info("initialized and running"); } protected override void OnStop() { - Logger.Info("Stopping update Service"); + Logger.Info("stopping update service"); } private void SetupServiceWatchers() { - Logger.Info("Setting Up Watchers"); + Logger.Info("setting up watches"); + + try { + svc.Connect(); + } catch { + //svc.Reconnect(); + } + + //svc.WaitForConnection(); var updateTimerInterval = ConfigurationManager.AppSettings.Get("UpdateTimer"); var upInt = TimeSpan.Zero; @@ -95,142 +106,51 @@ namespace ZitiUpdateService { private void CheckUpdate(object sender, ElapsedEventArgs e) { if (inUpdateCheck) return; inUpdateCheck = true; //simple semaphone + try { + Logger.Info("checking for update"); + var updateUrl = ConfigurationManager.AppSettings.Get("UpdateUrl"); + if (string.IsNullOrEmpty(updateUrl)) { + updateUrl = "https://api.github.com/repos/openziti/desktop-edge-win/releases/latest"; + } + IUpdateCheck check = new GithubCheck(updateUrl); - var updateUrl = ConfigurationManager.AppSettings.Get("UpdateUrl"); - if (string.IsNullOrEmpty(updateUrl)) { - updateUrl = "https://api.github.com/repos/openziti/desktop-edge-win/releases/latest"; - } - - try {/* - HttpWebRequest httpWebRequest = WebRequest.CreateHttp(updateUrl); - httpWebRequest.Method = "GET"; - httpWebRequest.ContentType = "application/json"; - httpWebRequest.UserAgent = "OpenZiti UpdateService"; - HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); - StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()); - string result = streamReader.ReadToEnd(); - JObject json = JObject.Parse(result); - string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - string serverVersion = json.Property("tag_name").Value.ToString() + ".0"; - + string currentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); //fetch from ziti? Version installed = new Version(currentVersion); - Version published = new Version(serverVersion); - int compare = installed.CompareTo(published); - if (compare < 0) { - Logger.Info("an upgrade is available. starting update process."); - } else if (compare > 0) { - Logger.Info("the version installed is newer than the released version"); + if (!check.IsUpdateAvailable(installed)) { + Logger.Debug("update check complete. no update available"); + inUpdateCheck = false; return; } - JArray assets = JArray.Parse(json.Property("assets").Value.ToString()); - string downloadUrl = null; - foreach (JObject asset in assets.Children()) { - downloadUrl = asset.Property("browser_download_url").Value.ToString(); - break; - } - if(downloadUrl == null) { - Logger.Error("DOWNLOAD URL not found at: {0}", updateUrl); - return; - } - */ + Logger.Info("update is available."); + var curdir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var updateFolder = $"{curdir}{Path.DirectorySeparatorChar}updates"; Directory.CreateDirectory(updateFolder); - var downloadUrl = "https://github.com/openziti/desktop-edge-win/releases/download/1.2.12/Ziti.Desktop.Edge.Client-1.2.13.exe"; - string filename = downloadUrl.Substring(downloadUrl.LastIndexOf('/') + 1); + Logger.Info("copying update package"); + string filename = check.FileName(); - if (string.IsNullOrEmpty(filename)) { - Logger.Warn("filename not found from web request. using generic filename {0}", "Ziti.Desktop.Edge.Client.exe"); - } - - string fileDestination = Path.Combine(updateFolder, filename); - Logger.Info("Checking to see if the file has been downloaded previously"); - if (File.Exists(fileDestination)) { - Logger.Info("file already exists at {0}. not downloading again", fileDestination); - } else { - Logger.Info("update found. downloading update from {0} to {1}", downloadUrl, fileDestination); - WebClient myWebClient = new WebClient(); - myWebClient.DownloadFile(downloadUrl, fileDestination); - Logger.Info("update downloaded"); + if (check.AlreadyDownloaded(updateFolder, filename)) { + Logger.Info("package has already been downloaded - moving to install phase"); + } else { + Logger.Info("copying update package begins"); + check.CopyUpdatePackage(updateFolder, filename); + Logger.Info("copying update package complete"); } StopZiti(); // shell out to a new process and run the uninstall, reinstall steps which SHOULD stop this current process as well - + string fileDestination = Path.Combine(updateFolder, filename); + Process.Start(fileDestination, "/passive"); } catch (Exception ex) { Logger.Error(ex, "Unexpected error has occurred"); - } + } inUpdateCheck = false; } - private void UpdateServiceFiles(string currentVersion, string _versionUrl, string _serviceUrl) { - var request = WebRequest.Create(_versionUrl) as HttpWebRequest; - var response = request.GetResponse(); - Stream receiveStream = response.GetResponseStream(); - StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8); - var result = readStream.ReadToEnd(); - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(result); - XmlNode node = xmlDoc.SelectSingleNode("metadata/versioning/"+_versionType); - string version = node.InnerText; - Logger.Info("Got Version: " + version+" from "+_versionType); - - if (_version.Trim() == currentVersion.Trim()) { - _version = currentVersion; - Logger.Info("Version local is the same as the version remote: " + version); - return; - } - - StopZiti(); - string remoteService = _serviceUrl.Replace("${version}", version); - - if (!Directory.Exists(Path.Combine(_rootDirectory, "Service"))) Directory.CreateDirectory(Path.Combine(_rootDirectory, "Service")); - string[] files = Directory.GetFiles(Path.Combine(_rootDirectory, "Service")); - foreach (string file in files) { - try { - Logger.Info("Delete: " + file); - File.Delete(file); - } catch (Exception e) { - EventLog.WriteEntry("Ziti", e.ToString(), EventLogEntryType.Error); - } - } - WebClient webClient = new WebClient(); - Logger.Info("Get From: "+remoteService); - webClient.DownloadFile(remoteService, Path.Combine(_rootDirectory, "Service") + @"\windows-tunneler.zip"); - Logger.Info("Zip Downloaded"); - ZipFile.ExtractToDirectory(Path.Combine(_rootDirectory, "Service") + @"\windows-tunneler.zip", Path.Combine(_rootDirectory, "Service")); - - Logger.Info("Zip UnZipped"); - File.WriteAllText(Path.Combine(_rootDirectory, @"Service\Version.txt"), version); - _version = version; - - if (_isNew) { - Logger.Info("Installing Service " + _version); - ProcessStartInfo installService = new ProcessStartInfo(); - installService.CreateNoWindow = true; - installService.UseShellExecute = true; - installService.FileName = Path.Combine(_rootDirectory, "Service") + @"\ziti-tunnel.exe"; - installService.WindowStyle = ProcessWindowStyle.Hidden; - installService.Arguments = "install"; - Logger.Info("Install Using " + installService.FileName + " " + installService.Arguments); - try { - Process exeProcess = Process.Start(installService); - exeProcess.WaitForExit(); - Logger.Info("Installed " + installService.FileName + " " + installService.Arguments); - - } catch (Exception e) { - Logger.Info("Cannot Install Service - " + e.ToString()); - } - } else { - // nothing to do - } - StartZiti(); - } - private void StartZiti() { controller = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName == "ziti"); if (controller != null && controller.Status != ServiceControllerStatus.Running && controller.Status != ServiceControllerStatus.StartPending && controller.Status != ServiceControllerStatus.ContinuePending) { diff --git a/ZitiUpdateService/ZitiUpdateService.csproj b/ZitiUpdateService/ZitiUpdateService.csproj index 76db24c4..9b676c36 100644 --- a/ZitiUpdateService/ZitiUpdateService.csproj +++ b/ZitiUpdateService/ZitiUpdateService.csproj @@ -103,6 +103,7 @@ + Component @@ -110,6 +111,7 @@ ProjectInstaller.cs + Component