@@ -14,21 +14,22 @@ using System.Net; | |||
namespace Shadowsocks.Controller | |||
{ | |||
static class GeositeUpdater | |||
public class GeositeResultEventArgs : EventArgs | |||
{ | |||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||
public static event EventHandler<ResultEventArgs> UpdateCompleted; | |||
public bool Success; | |||
public class ResultEventArgs : EventArgs | |||
public GeositeResultEventArgs(bool success) | |||
{ | |||
public bool Success; | |||
public ResultEventArgs(bool success) | |||
{ | |||
this.Success = success; | |||
} | |||
this.Success = success; | |||
} | |||
} | |||
public static class GeositeUpdater | |||
{ | |||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||
public static event EventHandler<GeositeResultEventArgs> UpdateCompleted; | |||
public static event ErrorEventHandler Error; | |||
private static readonly string DATABASE_PATH = Utils.GetTempPath("dlc.dat"); | |||
@@ -57,6 +58,12 @@ namespace Shadowsocks.Controller | |||
} | |||
} | |||
public static void ResetEvent() | |||
{ | |||
UpdateCompleted = null; | |||
Error = null; | |||
} | |||
public static void UpdatePACFromGeosite(Configuration config) | |||
{ | |||
string gfwListUrl = GEOSITE_URL; | |||
@@ -83,7 +90,7 @@ namespace Shadowsocks.Controller | |||
LoadGeositeList(); | |||
bool pacFileChanged = MergeAndWritePACFile(); | |||
UpdateCompleted?.Invoke(null, new ResultEventArgs(pacFileChanged)); | |||
UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged)); | |||
} | |||
catch (Exception ex) | |||
{ | |||
@@ -1,137 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Net; | |||
using System.Text; | |||
using Newtonsoft.Json; | |||
using NLog; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.Properties; | |||
using Shadowsocks.Util; | |||
namespace Shadowsocks.Controller | |||
{ | |||
public class GFWListUpdater | |||
{ | |||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||
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(PACDaemon.PAC_FILE)) | |||
{ | |||
string original = FileManager.NonExclusiveReadAllText(PACDaemon.PAC_FILE, Encoding.UTF8); | |||
if (original == abpContent) | |||
{ | |||
return false; | |||
} | |||
} | |||
File.WriteAllText(PACDaemon.PAC_FILE, abpContent, Encoding.UTF8); | |||
return true; | |||
} | |||
private static string MergePACFile(string gfwListResult) | |||
{ | |||
string abpContent; | |||
if (File.Exists(PACDaemon.USER_ABP_FILE)) | |||
{ | |||
abpContent = FileManager.NonExclusiveReadAllText(PACDaemon.USER_ABP_FILE, Encoding.UTF8); | |||
} | |||
else | |||
{ | |||
abpContent = Resources.abp_js; | |||
} | |||
List<string> userruleLines = new List<string>(); | |||
if (File.Exists(PACDaemon.USER_RULE_FILE)) | |||
{ | |||
string userrulesString = FileManager.NonExclusiveReadAllText(PACDaemon.USER_RULE_FILE, Encoding.UTF8); | |||
userruleLines = ParseToValidList(userrulesString); | |||
} | |||
List<string> gfwLines = new List<string>(); | |||
gfwLines = ParseBase64ToValidList(gfwListResult); | |||
abpContent = | |||
$@"var __USERRULES__ = {JsonConvert.SerializeObject(userruleLines, Formatting.Indented)}; | |||
var __RULES__ = {JsonConvert.SerializeObject(gfwLines, Formatting.Indented)}; | |||
{abpContent}"; | |||
return abpContent; | |||
} | |||
public void UpdatePACFromGFWList(Configuration config) | |||
{ | |||
string gfwListUrl = GFWLIST_URL; | |||
if (!string.IsNullOrWhiteSpace(config.gfwListUrl)) | |||
{ | |||
logger.Info("Found custom GFWListURL in config file"); | |||
gfwListUrl = config.gfwListUrl; | |||
} | |||
logger.Info($"Checking GFWList from {gfwListUrl}"); | |||
WebClient http = new WebClient(); | |||
if (config.enabled) | |||
{ | |||
http.Proxy = new WebProxy( | |||
config.isIPv6Enabled | |||
? $"[{IPAddress.IPv6Loopback.ToString()}]" | |||
: IPAddress.Loopback.ToString(), | |||
config.localPort); | |||
} | |||
http.DownloadStringCompleted += http_DownloadStringCompleted; | |||
http.DownloadStringAsync(new Uri(gfwListUrl)); | |||
} | |||
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; | |||
} | |||
} | |||
} |
@@ -35,7 +35,6 @@ namespace Shadowsocks.Controller | |||
private Configuration _config; | |||
private StrategyManager _strategyManager; | |||
private PrivoxyRunner privoxyRunner; | |||
private GFWListUpdater gfwListUpdater; | |||
private readonly ConcurrentDictionary<Server, Sip003Plugin> _pluginsByServer; | |||
public AvailabilityStatistics availabilityStatistics = AvailabilityStatistics.Instance; | |||
@@ -80,7 +79,7 @@ namespace Shadowsocks.Controller | |||
public event EventHandler<PathEventArgs> PACFileReadyToOpen; | |||
public event EventHandler<PathEventArgs> UserRuleFileReadyToOpen; | |||
public event EventHandler<GFWListUpdater.ResultEventArgs> UpdatePACFromGFWListCompleted; | |||
public event EventHandler<GeositeResultEventArgs> UpdatePACFromGFWListCompleted; | |||
public event ErrorEventHandler UpdatePACFromGFWListError; | |||
@@ -418,10 +417,7 @@ namespace Shadowsocks.Controller | |||
public void UpdatePACFromGFWList() | |||
{ | |||
if (gfwListUpdater != null) | |||
{ | |||
gfwListUpdater.UpdatePACFromGFWList(_config); | |||
} | |||
GeositeUpdater.UpdatePACFromGeosite(_config); | |||
} | |||
public void UpdateStatisticsConfiguration(bool enabled) | |||
@@ -534,9 +530,9 @@ namespace Shadowsocks.Controller | |||
_pacServer = _pacServer ?? new PACServer(_pacDaemon); | |||
_pacServer.UpdatePACURL(_config); // So PACServer works when system proxy disabled. | |||
gfwListUpdater = gfwListUpdater ?? new GFWListUpdater(); | |||
gfwListUpdater.UpdateCompleted += PacServer_PACUpdateCompleted; | |||
gfwListUpdater.Error += PacServer_PACUpdateError; | |||
GeositeUpdater.ResetEvent(); | |||
GeositeUpdater.UpdateCompleted += PacServer_PACUpdateCompleted; | |||
GeositeUpdater.Error += PacServer_PACUpdateError; | |||
availabilityStatistics.UpdateConfiguration(this); | |||
_listener?.Stop(); | |||
@@ -613,7 +609,7 @@ namespace Shadowsocks.Controller | |||
UpdateSystemProxy(); | |||
} | |||
private void PacServer_PACUpdateCompleted(object sender, GFWListUpdater.ResultEventArgs e) | |||
private void PacServer_PACUpdateCompleted(object sender, GeositeResultEventArgs e) | |||
{ | |||
UpdatePACFromGFWListCompleted?.Invoke(this, e); | |||
} | |||
@@ -632,7 +628,7 @@ namespace Shadowsocks.Controller | |||
} | |||
else | |||
{ | |||
GFWListUpdater.MergeAndWritePACFile(FileManager.NonExclusiveReadAllText(Utils.GetTempPath("gfwlist.txt"))); | |||
GeositeUpdater.MergeAndWritePACFile(); | |||
} | |||
UpdateSystemProxy(); | |||
} | |||
@@ -393,7 +393,7 @@ namespace Shadowsocks.View | |||
logger.LogUsefulException(e.GetException()); | |||
} | |||
void controller_UpdatePACFromGFWListCompleted(object sender, GFWListUpdater.ResultEventArgs e) | |||
void controller_UpdatePACFromGFWListCompleted(object sender, GeositeResultEventArgs e) | |||
{ | |||
string result = e.Success | |||
? I18N.GetString("PAC updated") | |||
@@ -173,7 +173,6 @@ | |||
<Compile Include="Controller\Strategy\StatisticsStrategy.cs" /> | |||
<Compile Include="Controller\System\AutoStartup.cs" /> | |||
<Compile Include="Controller\FileManager.cs" /> | |||
<Compile Include="Controller\Service\GFWListUpdater.cs" /> | |||
<Compile Include="Controller\I18N.cs" /> | |||
<Compile Include="Controller\Service\Listener.cs" /> | |||
<Compile Include="Controller\Service\PortForwarder.cs" /> | |||