diff --git a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs index a670938..0955b25 100644 --- a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs +++ b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs @@ -1,95 +1,49 @@ -using Shadowsocks.Model; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using System.IO; using SimpleJson; +using Shadowsocks.Model; +using Shadowsocks.Util; + namespace Shadowsocks.Controller { public class UpdateChecker { private const string UpdateURL = "https://api.github.com/repos/shadowsocks/shadowsocks-windows/releases"; + private const string UserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36"; + private Configuration config; public bool NewVersionFound; public string LatestVersionNumber; + public string LatestVersionName; public string LatestVersionURL; + public string LatestVersionLocalName; public event EventHandler CheckUpdateCompleted; public const string Version = "2.5.8"; public void CheckUpdate(Configuration config) { - // TODO test failures - WebClient http = new WebClient(); - http.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36"); - http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); - http.DownloadStringCompleted += http_DownloadStringCompleted; - http.DownloadStringAsync(new Uri(UpdateURL)); - } + this.config = config; - public static int CompareVersion(string l, string r) - { - var ls = l.Split('.'); - var rs = r.Split('.'); - for (int i = 0; i < Math.Max(ls.Length, rs.Length); i++) + try { - int lp = (i < ls.Length) ? int.Parse(ls[i]) : 0; - int rp = (i < rs.Length) ? int.Parse(rs[i]) : 0; - if (lp != rp) - { - return lp - rp; - } + WebClient http = CreateWebClient(); + http.DownloadStringCompleted += http_DownloadStringCompleted; + http.DownloadStringAsync(new Uri(UpdateURL)); } - return 0; - } - - public class VersionComparer : IComparer - { - // Calls CaseInsensitiveComparer.Compare with the parameters reversed. - public int Compare(string x, string y) + catch (Exception ex) { - return CompareVersion(ParseVersionFromURL(x), ParseVersionFromURL(y)); + Logging.LogUsefulException(ex); } } - private static string ParseVersionFromURL(string url) - { - Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase); - if (match.Success) - { - if (match.Groups.Count == 2) - { - return match.Groups[1].Value; - } - } - return null; - } - - private void SortVersions(List versions) - { - versions.Sort(new VersionComparer()); - } - - private bool IsNewVersion(string url) - { - if (url.IndexOf("prerelease") >= 0) - { - return false; - } - string version = ParseVersionFromURL(url); - if (version == null) - { - return false; - } - string currentVersion = Version; - - return CompareVersion(version, currentVersion) > 0; - } - private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { try @@ -98,7 +52,7 @@ namespace Shadowsocks.Controller JsonArray result = (JsonArray)SimpleJson.SimpleJson.DeserializeObject(e.Result); - List versions = new List(); + List asserts = new List(); foreach (JsonObject release in result) { if ((bool)release["prerelease"]) @@ -107,21 +61,61 @@ namespace Shadowsocks.Controller } foreach (JsonObject asset in (JsonArray)release["assets"]) { - string url = (string)asset["browser_download_url"]; - if (IsNewVersion(url)) + Asset ass = new Asset(); + ass.Parse(asset); + if (ass.IsNewVersion(Version)) { - versions.Add(url); + asserts.Add(ass); } } } - if (versions.Count != 0) + if (asserts.Count != 0) { - // sort versions - SortVersions(versions); + SortByVersions(asserts); + Asset asset = asserts[asserts.Count - 1]; NewVersionFound = true; - LatestVersionURL = versions[versions.Count - 1]; - LatestVersionNumber = ParseVersionFromURL(LatestVersionURL); + LatestVersionURL = asset.browser_download_url; + LatestVersionNumber = asset.version; + LatestVersionName = asset.name; + + startDownload(); + } + else if (CheckUpdateCompleted != null) + { + CheckUpdateCompleted(this, new EventArgs()); + } + } + catch (Exception ex) + { + Logging.LogUsefulException(ex); + } + } + + private void startDownload() + { + try + { + string temppath = Utils.GetTempPath(); + LatestVersionLocalName = Path.Combine(temppath, LatestVersionName); + WebClient http = CreateWebClient(); + http.DownloadFileCompleted += Http_DownloadFileCompleted; + http.DownloadFileAsync(new Uri(LatestVersionURL), LatestVersionLocalName); + } + catch (Exception ex) + { + Logging.LogUsefulException(ex); + } + } + + private void Http_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) + { + try + { + if(e.Error != null) + { + Logging.LogUsefulException(e.Error); + return; } if (CheckUpdateCompleted != null) { @@ -130,9 +124,89 @@ namespace Shadowsocks.Controller } catch (Exception ex) { - Logging.Debug(ex.ToString()); - return; + Logging.LogUsefulException(ex); } } + + private WebClient CreateWebClient() + { + WebClient http = new WebClient(); + http.Headers.Add("User-Agent", UserAgent); + http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort); + return http; + } + + private void SortByVersions(List asserts) + { + asserts.Sort(new VersionComparer()); + } + + class Asset + { + public bool prerelease; + public string name; + public string version; + public string browser_download_url; + + public bool IsNewVersion(string currentVersion) + { + if (prerelease) + { + return false; + } + if (version == null) + { + return false; + } + return CompareVersion(version, currentVersion) > 0; + } + + public void Parse(JsonObject asset) + { + name = (string)asset["name"]; + browser_download_url = (string)asset["browser_download_url"]; + version = ParseVersionFromURL(browser_download_url); + prerelease = browser_download_url.IndexOf("prerelease") >= 0; + } + + private static string ParseVersionFromURL(string url) + { + Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase); + if (match.Success) + { + if (match.Groups.Count == 2) + { + return match.Groups[1].Value; + } + } + return null; + } + + public static int CompareVersion(string l, string r) + { + var ls = l.Split('.'); + var rs = r.Split('.'); + for (int i = 0; i < Math.Max(ls.Length, rs.Length); i++) + { + int lp = (i < ls.Length) ? int.Parse(ls[i]) : 0; + int rp = (i < rs.Length) ? int.Parse(rs[i]) : 0; + if (lp != rp) + { + return lp - rp; + } + } + return 0; + } + } + + class VersionComparer : IComparer + { + // Calls CaseInsensitiveComparer.Compare with the parameters reversed. + public int Compare(Asset x, Asset y) + { + return Asset.CompareVersion(x.version, y.version); + } + } + } } diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index 3a64195..f2accf5 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -82,7 +82,7 @@ Port out of range=端口超出范围 Port can't be 8123=端口不能为 8123 Shadowsocks {0} Update Found=Shadowsocks {0} 更新 No update is available=没有可用的更新 -Click here to download=点击这里下载 +Click here to update=点击这里升级 Shadowsocks is here=Shadowsocks 在这里 You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks System Proxy Enabled=系统代理已启用 diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 441a27b..e729d94 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -255,7 +255,7 @@ namespace Shadowsocks.View { if (updateChecker.NewVersionFound) { - ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to download"), ToolTipIcon.Info, 5000); + ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000); _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; _isFirstRun = false; } @@ -269,8 +269,9 @@ namespace Shadowsocks.View void notifyIcon1_BalloonTipClicked(object sender, EventArgs e) { - System.Diagnostics.Process.Start(updateChecker.LatestVersionURL); _notifyIcon.BalloonTipClicked -= notifyIcon1_BalloonTipClicked; + string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\""; + System.Diagnostics.Process.Start("explorer.exe", argument); }