Browse Source

Download updates automatically

tags/3.0
Gang Zhuo 9 years ago
parent
commit
ab79dbce0e
3 changed files with 149 additions and 74 deletions
  1. +145
    -71
      shadowsocks-csharp/Controller/Service/UpdateChecker.cs
  2. +1
    -1
      shadowsocks-csharp/Data/cn.txt
  3. +3
    -2
      shadowsocks-csharp/View/MenuViewController.cs

+ 145
- 71
shadowsocks-csharp/Controller/Service/UpdateChecker.cs View File

@@ -1,138 +1,212 @@
using Shadowsocks.Model;
using System;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.IO;
using SimpleJson; using SimpleJson;
using Shadowsocks.Model;
using Shadowsocks.Util;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
public class UpdateChecker public class UpdateChecker
{ {
private const string UpdateURL = "https://api.github.com/repos/shadowsocks/shadowsocks-windows/releases"; 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 bool NewVersionFound;
public string LatestVersionNumber; public string LatestVersionNumber;
public string LatestVersionName;
public string LatestVersionURL; public string LatestVersionURL;
public string LatestVersionLocalName;
public event EventHandler CheckUpdateCompleted; public event EventHandler CheckUpdateCompleted;
public const string Version = "2.5.8"; public const string Version = "2.5.8";
public void CheckUpdate(Configuration config) 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;
try
{
WebClient http = CreateWebClient();
http.DownloadStringCompleted += http_DownloadStringCompleted;
http.DownloadStringAsync(new Uri(UpdateURL));
}
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
} }
public static int CompareVersion(string l, string r)
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{ {
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)
string response = e.Result;
JsonArray result = (JsonArray)SimpleJson.SimpleJson.DeserializeObject(e.Result);
List<Asset> asserts = new List<Asset>();
foreach (JsonObject release in result)
{ {
return lp - rp;
if ((bool)release["prerelease"])
{
continue;
}
foreach (JsonObject asset in (JsonArray)release["assets"])
{
Asset ass = new Asset();
ass.Parse(asset);
if (ass.IsNewVersion(Version))
{
asserts.Add(ass);
}
}
}
if (asserts.Count != 0)
{
SortByVersions(asserts);
Asset asset = asserts[asserts.Count - 1];
NewVersionFound = true;
LatestVersionURL = asset.browser_download_url;
LatestVersionNumber = asset.version;
LatestVersionName = asset.name;
startDownload();
}
else if (CheckUpdateCompleted != null)
{
CheckUpdateCompleted(this, new EventArgs());
} }
} }
return 0;
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
} }
public class VersionComparer : IComparer<string>
private void startDownload()
{ {
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
public int Compare(string x, string y)
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)
{ {
return CompareVersion(ParseVersionFromURL(x), ParseVersionFromURL(y));
Logging.LogUsefulException(ex);
} }
} }
private static string ParseVersionFromURL(string url)
private void Http_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{ {
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase);
if (match.Success)
try
{ {
if (match.Groups.Count == 2)
if(e.Error != null)
{ {
return match.Groups[1].Value;
Logging.LogUsefulException(e.Error);
return;
}
if (CheckUpdateCompleted != null)
{
CheckUpdateCompleted(this, new EventArgs());
} }
} }
return null;
catch (Exception ex)
{
Logging.LogUsefulException(ex);
}
} }
private void SortVersions(List<string> versions)
private WebClient CreateWebClient()
{ {
versions.Sort(new VersionComparer());
WebClient http = new WebClient();
http.Headers.Add("User-Agent", UserAgent);
http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort);
return http;
} }
private bool IsNewVersion(string url)
private void SortByVersions(List<Asset> asserts)
{ {
if (url.IndexOf("prerelease") >= 0)
{
return false;
}
string version = ParseVersionFromURL(url);
if (version == null)
{
return false;
}
string currentVersion = Version;
return CompareVersion(version, currentVersion) > 0;
asserts.Sort(new VersionComparer());
} }
private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
class Asset
{ {
try
public bool prerelease;
public string name;
public string version;
public string browser_download_url;
public bool IsNewVersion(string currentVersion)
{ {
string response = e.Result;
if (prerelease)
{
return false;
}
if (version == null)
{
return false;
}
return CompareVersion(version, currentVersion) > 0;
}
JsonArray result = (JsonArray)SimpleJson.SimpleJson.DeserializeObject(e.Result);
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;
}
List<string> versions = new List<string>();
foreach (JsonObject release in result)
private static string ParseVersionFromURL(string url)
{
Match match = Regex.Match(url, @".*Shadowsocks-win.*?-([\d\.]+)\.\w+", RegexOptions.IgnoreCase);
if (match.Success)
{ {
if ((bool)release["prerelease"])
{
continue;
}
foreach (JsonObject asset in (JsonArray)release["assets"])
if (match.Groups.Count == 2)
{ {
string url = (string)asset["browser_download_url"];
if (IsNewVersion(url))
{
versions.Add(url);
}
return match.Groups[1].Value;
} }
} }
return null;
}
if (versions.Count != 0)
{
// sort versions
SortVersions(versions);
NewVersionFound = true;
LatestVersionURL = versions[versions.Count - 1];
LatestVersionNumber = ParseVersionFromURL(LatestVersionURL);
}
if (CheckUpdateCompleted != 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++)
{ {
CheckUpdateCompleted(this, new EventArgs());
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;
} }
catch (Exception ex)
}
class VersionComparer : IComparer<Asset>
{
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
public int Compare(Asset x, Asset y)
{ {
Logging.Debug(ex.ToString());
return;
return Asset.CompareVersion(x.version, y.version);
} }
} }
} }
} }

+ 1
- 1
shadowsocks-csharp/Data/cn.txt View File

@@ -82,7 +82,7 @@ Port out of range=端口超出范围
Port can't be 8123=端口不能为 8123 Port can't be 8123=端口不能为 8123
Shadowsocks {0} Update Found=Shadowsocks {0} 更新 Shadowsocks {0} Update Found=Shadowsocks {0} 更新
No update is available=没有可用的更新 No update is available=没有可用的更新
Click here to download=点击这里下载
Click here to update=点击这里升级
Shadowsocks is here=Shadowsocks 在这里 Shadowsocks is here=Shadowsocks 在这里
You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks You can turn on/off Shadowsocks in the context menu=可以在右键菜单中开关 Shadowsocks
System Proxy Enabled=系统代理已启用 System Proxy Enabled=系统代理已启用


+ 3
- 2
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -255,7 +255,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 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; _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked;
_isFirstRun = false; _isFirstRun = false;
} }
@@ -269,8 +269,9 @@ namespace Shadowsocks.View
void notifyIcon1_BalloonTipClicked(object sender, EventArgs e) void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
{ {
System.Diagnostics.Process.Start(updateChecker.LatestVersionURL);
_notifyIcon.BalloonTipClicked -= notifyIcon1_BalloonTipClicked; _notifyIcon.BalloonTipClicked -= notifyIcon1_BalloonTipClicked;
string argument = "/select, \"" + updateChecker.LatestVersionLocalName + "\"";
System.Diagnostics.Process.Start("explorer.exe", argument);
} }


Loading…
Cancel
Save