@@ -18,12 +18,14 @@ namespace Shadowsocks.Controller | |||||
private Configuration config; | private Configuration config; | ||||
public bool NewVersionFound; | public bool NewVersionFound; | ||||
public string LatestVersionNumber; | public string LatestVersionNumber; | ||||
public string LatestVersionSuffix; | |||||
public string LatestVersionName; | public string LatestVersionName; | ||||
public string LatestVersionURL; | public string LatestVersionURL; | ||||
public string LatestVersionLocalName; | public string LatestVersionLocalName; | ||||
public event EventHandler CheckUpdateCompleted; | public event EventHandler CheckUpdateCompleted; | ||||
public const string Version = "3.3.5"; | public const string Version = "3.3.5"; | ||||
public const bool PreRelease = false; | |||||
private class CheckUpdateTimer : System.Timers.Timer | private class CheckUpdateTimer : System.Timers.Timer | ||||
{ | { | ||||
@@ -83,17 +85,21 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
foreach (JObject release in result) | foreach (JObject release in result) | ||||
{ | { | ||||
if ((bool)release["prerelease"]) | |||||
var isPreRelease = (bool) release["prerelease"]; | |||||
if (isPreRelease && !config.checkPreRelease) | |||||
{ | { | ||||
continue; | continue; | ||||
} | } | ||||
foreach (JObject asset in (JArray)release["assets"]) | foreach (JObject asset in (JArray)release["assets"]) | ||||
{ | { | ||||
Asset ass = new Asset(); | |||||
ass.Parse(asset); | |||||
if (ass.IsNewVersion(Version)) | |||||
Asset ass = Asset.ParseAsset(asset); | |||||
if (ass != null) | |||||
{ | { | ||||
asserts.Add(ass); | |||||
ass.prerelease = isPreRelease; | |||||
if (ass.IsNewVersion(Version, PreRelease, config.checkPreRelease)) | |||||
{ | |||||
asserts.Add(ass); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -106,6 +112,7 @@ namespace Shadowsocks.Controller | |||||
LatestVersionURL = asset.browser_download_url; | LatestVersionURL = asset.browser_download_url; | ||||
LatestVersionNumber = asset.version; | LatestVersionNumber = asset.version; | ||||
LatestVersionName = asset.name; | LatestVersionName = asset.name; | ||||
LatestVersionSuffix = asset.suffix == null ? "" : $"-{asset.suffix}"; | |||||
startDownload(); | startDownload(); | ||||
} | } | ||||
@@ -148,7 +155,7 @@ namespace Shadowsocks.Controller | |||||
Logging.LogUsefulException(e.Error); | Logging.LogUsefulException(e.Error); | ||||
return; | return; | ||||
} | } | ||||
Logging.Debug($"New version {LatestVersionNumber} found: {LatestVersionLocalName}"); | |||||
Logging.Debug($"New version {LatestVersionNumber}{LatestVersionSuffix} found: {LatestVersionLocalName}"); | |||||
if (CheckUpdateCompleted != null) | if (CheckUpdateCompleted != null) | ||||
{ | { | ||||
CheckUpdateCompleted(this, new EventArgs()); | CheckUpdateCompleted(this, new EventArgs()); | ||||
@@ -179,10 +186,38 @@ namespace Shadowsocks.Controller | |||||
public string name; | public string name; | ||||
public string version; | public string version; | ||||
public string browser_download_url; | public string browser_download_url; | ||||
public string suffix; | |||||
public bool IsNewVersion(string currentVersion) | |||||
public static Asset ParseAsset(JObject aJObject) | |||||
{ | { | ||||
if (prerelease) | |||||
var name = (string) aJObject["name"]; | |||||
Match match = Regex.Match(name, @"^Shadowsocks-(?<version>\d+(?:\.\d+)*)(?:|-(?<suffix>.+))\.\w+$", | |||||
RegexOptions.IgnoreCase); | |||||
if (match.Success) | |||||
{ | |||||
string version = match.Groups["version"].Value; | |||||
var asset = new Asset | |||||
{ | |||||
browser_download_url = (string) aJObject["browser_download_url"], | |||||
name = name, | |||||
version = version | |||||
}; | |||||
if (match.Groups["suffix"].Success) | |||||
{ | |||||
asset.suffix = match.Groups["suffix"].Value; | |||||
} | |||||
return asset; | |||||
} | |||||
return null; | |||||
} | |||||
public bool IsNewVersion(string currentVersion, bool isPreRelease, bool checkPreRelease) | |||||
{ | |||||
if (prerelease && !checkPreRelease) | |||||
{ | { | ||||
return false; | return false; | ||||
} | } | ||||
@@ -190,28 +225,13 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
return false; | return false; | ||||
} | } | ||||
return CompareVersion(version, currentVersion) > 0; | |||||
} | |||||
public void Parse(JObject asset) | |||||
{ | |||||
name = (string)asset["name"]; | |||||
browser_download_url = (string)asset["browser_download_url"]; | |||||
version = ParseVersionFromURL(browser_download_url); | |||||
prerelease = browser_download_url.IndexOf("prerelease", StringComparison.Ordinal) >= 0; | |||||
} | |||||
private static string ParseVersionFromURL(string url) | |||||
{ | |||||
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase); | |||||
if (match.Success) | |||||
var cmp = CompareVersion(version, currentVersion); | |||||
if (cmp == 0) | |||||
{ | { | ||||
if (match.Groups.Count == 2) | |||||
{ | |||||
return match.Groups[1].Value; | |||||
} | |||||
// If current version is pre-release and we find non-prerelease version online, then the non-prelease version is newer. | |||||
return !prerelease && isPreRelease; | |||||
} | } | ||||
return null; | |||||
return cmp > 0; | |||||
} | } | ||||
public static int CompareVersion(string l, string r) | public static int CompareVersion(string l, string r) | ||||
@@ -357,6 +357,16 @@ namespace Shadowsocks.Controller | |||||
} | } | ||||
} | } | ||||
public void ToggleCheckingPreRelease(bool enabled) | |||||
{ | |||||
_config.checkPreRelease = enabled; | |||||
Configuration.Save(_config); | |||||
if (ConfigChanged != null) | |||||
{ | |||||
ConfigChanged(this, new EventArgs()); | |||||
} | |||||
} | |||||
public void SaveLogViewerConfig(LogViewerConfig newConfig) | public void SaveLogViewerConfig(LogViewerConfig newConfig) | ||||
{ | { | ||||
_config.logViewer = newConfig; | _config.logViewer = newConfig; | ||||
@@ -27,6 +27,7 @@ Verbose Logging=详细记录日志 | |||||
Updates...=更新... | Updates...=更新... | ||||
Check for Updates...=检查更新 | Check for Updates...=检查更新 | ||||
Check for Updates at Startup=启动时检查更新 | Check for Updates at Startup=启动时检查更新 | ||||
Check Pre-release Version=检查测试版更新 | |||||
Edit Hotkeys...=编辑快捷键... | Edit Hotkeys...=编辑快捷键... | ||||
About...=关于... | About...=关于... | ||||
Quit=退出 | Quit=退出 | ||||
@@ -27,6 +27,7 @@ Verbose Logging=詳細記錄日誌 | |||||
Updates...=更新... | Updates...=更新... | ||||
Check for Updates...=檢查更新 | Check for Updates...=檢查更新 | ||||
Check for Updates at Startup=啟動時檢查更新 | Check for Updates at Startup=啟動時檢查更新 | ||||
Check Pre-release Version=檢查測試版更新 | |||||
Edit Hotkeys...=編輯捷徑鍵... | Edit Hotkeys...=編輯捷徑鍵... | ||||
About...=關於... | About...=關於... | ||||
Quit=退出 | Quit=退出 | ||||
@@ -24,6 +24,7 @@ namespace Shadowsocks.Model | |||||
public bool useOnlinePac; | public bool useOnlinePac; | ||||
public bool availabilityStatistics; | public bool availabilityStatistics; | ||||
public bool autoCheckUpdate; | public bool autoCheckUpdate; | ||||
public bool checkPreRelease; | |||||
public bool isVerboseLogging; | public bool isVerboseLogging; | ||||
public LogViewerConfig logViewer; | public LogViewerConfig logViewer; | ||||
public ProxyConfig proxy; | public ProxyConfig proxy; | ||||
@@ -48,6 +48,7 @@ namespace Shadowsocks.View | |||||
private MenuItem editGFWUserRuleItem; | private MenuItem editGFWUserRuleItem; | ||||
private MenuItem editOnlinePACItem; | private MenuItem editOnlinePACItem; | ||||
private MenuItem autoCheckUpdatesToggleItem; | private MenuItem autoCheckUpdatesToggleItem; | ||||
private MenuItem checkPreReleaseToggleItem; | |||||
private MenuItem proxyItem; | private MenuItem proxyItem; | ||||
private MenuItem hotKeyItem; | private MenuItem hotKeyItem; | ||||
private MenuItem VerboseLoggingToggleItem; | private MenuItem VerboseLoggingToggleItem; | ||||
@@ -283,6 +284,7 @@ namespace Shadowsocks.View | |||||
CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)), | CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)), | this.autoCheckUpdatesToggleItem = CreateMenuItem("Check for Updates at Startup", new EventHandler(this.autoCheckUpdatesToggleItem_Click)), | ||||
this.checkPreReleaseToggleItem = CreateMenuItem("Check Pre-release Version", new EventHandler(this.checkPreReleaseToggleItem_Click)), | |||||
}), | }), | ||||
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)), | CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
@@ -352,7 +354,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
if (updateChecker.NewVersionFound) | if (updateChecker.NewVersionFound) | ||||
{ | { | ||||
ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000); | |||||
ShowBalloonTip(String.Format(I18N.GetString("Shadowsocks {0} Update Found"), updateChecker.LatestVersionNumber + updateChecker.LatestVersionSuffix), I18N.GetString("Click here to update"), ToolTipIcon.Info, 5000); | |||||
} | } | ||||
else if (!_isStartupChecking) | else if (!_isStartupChecking) | ||||
{ | { | ||||
@@ -816,6 +818,7 @@ namespace Shadowsocks.View | |||||
{ | { | ||||
Configuration configuration = controller.GetConfigurationCopy(); | Configuration configuration = controller.GetConfigurationCopy(); | ||||
autoCheckUpdatesToggleItem.Checked = configuration.autoCheckUpdate; | autoCheckUpdatesToggleItem.Checked = configuration.autoCheckUpdate; | ||||
checkPreReleaseToggleItem.Checked = configuration.checkPreRelease; | |||||
} | } | ||||
private void autoCheckUpdatesToggleItem_Click(object sender, EventArgs e) | private void autoCheckUpdatesToggleItem_Click(object sender, EventArgs e) | ||||
@@ -825,6 +828,13 @@ namespace Shadowsocks.View | |||||
UpdateUpdateMenu(); | UpdateUpdateMenu(); | ||||
} | } | ||||
private void checkPreReleaseToggleItem_Click(object sender, EventArgs e) | |||||
{ | |||||
Configuration configuration = controller.GetConfigurationCopy(); | |||||
controller.ToggleCheckingPreRelease(!configuration.checkPreRelease); | |||||
UpdateUpdateMenu(); | |||||
} | |||||
private void checkUpdatesItem_Click(object sender, EventArgs e) | private void checkUpdatesItem_Click(object sender, EventArgs e) | ||||
{ | { | ||||
updateChecker.CheckUpdate(controller.GetConfigurationCopy()); | updateChecker.CheckUpdate(controller.GetConfigurationCopy()); | ||||