|
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Net;
- using System.Text;
-
- using Newtonsoft.Json;
-
- using Shadowsocks.Model;
- using Shadowsocks.Properties;
- using Shadowsocks.Util;
-
- namespace Shadowsocks.Controller
- {
- public class GFWListUpdater
- {
- private const string GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt";
-
- public event EventHandler<ResultEventArgs> UpdateCompleted;
-
- public event ErrorEventHandler Error;
-
- public class ResultEventArgs : EventArgs
- {
- public bool Success;
-
- public ResultEventArgs(bool success)
- {
- this.Success = success;
- }
- }
-
- private static readonly IEnumerable<char> IgnoredLineBegins = new[] { '!', '[' };
- private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
- {
- try
- {
- File.WriteAllText(Utils.GetTempPath("gfwlist.txt"), e.Result, Encoding.UTF8);
- bool pacFileChanged = MergeAndWritePACFile(e.Result);
- UpdateCompleted?.Invoke(this, new ResultEventArgs(pacFileChanged));
- }
- catch (Exception ex)
- {
- Error?.Invoke(this, new ErrorEventArgs(ex));
- }
- }
-
- public static bool MergeAndWritePACFile(string gfwListResult)
- {
- string abpContent = MergePACFile(gfwListResult);
- if (File.Exists(PACServer.PAC_FILE))
- {
- string original = FileManager.NonExclusiveReadAllText(PACServer.PAC_FILE, Encoding.UTF8);
- if (original == abpContent)
- {
- return false;
- }
- }
- File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8);
- return true;
- }
-
- private static string MergePACFile(string gfwListResult)
- {
- string abpContent;
- if (File.Exists(PACServer.USER_ABP_FILE))
- {
- abpContent = FileManager.NonExclusiveReadAllText(PACServer.USER_ABP_FILE, Encoding.UTF8);
- }
- else
- {
- abpContent = Utils.UnGzip(Resources.abp_js);
- }
-
- List<string> userruleLines = new List<string>();
- if (File.Exists(PACServer.USER_RULE_FILE))
- {
- string userrulesString = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);
- userruleLines = ParseToValidList(userrulesString);
- }
-
- List<string> gfwLines = new List<string>();
- gfwLines = ParseBase64ToValidList(gfwListResult);
-
- abpContent = abpContent.Replace("__USERRULES__", JsonConvert.SerializeObject(userruleLines, Formatting.Indented))
- .Replace("__RULES__", JsonConvert.SerializeObject(gfwLines, Formatting.Indented));
- return abpContent;
- }
-
- public void UpdatePACFromGFWList(Configuration config)
- {
- Logging.Info($"Checking GFWList from {GFWLIST_URL}");
- WebClient http = new WebClient();
- http.Proxy = new WebProxy(IPAddress.Loopback.ToString(), config.localPort);
- http.DownloadStringCompleted += http_DownloadStringCompleted;
- http.DownloadStringAsync(new Uri(GFWLIST_URL));
- }
-
- public static List<string> ParseBase64ToValidList(string response)
- {
- byte[] bytes = Convert.FromBase64String(response);
- string content = Encoding.ASCII.GetString(bytes);
- return ParseToValidList(content);
- }
-
- private static List<string> ParseToValidList(string content)
- {
- List<string> valid_lines = new List<string>();
- using (var sr = new StringReader(content))
- {
- foreach (var line in sr.NonWhiteSpaceLines())
- {
- if (line.BeginWithAny(IgnoredLineBegins))
- continue;
- valid_lines.Add(line);
- }
- }
- return valid_lines;
- }
- }
- }
|