diff --git a/shadowsocks-csharp/Controller/Logging.cs b/shadowsocks-csharp/Controller/Logging.cs index d77a3fbe..fb07dcae 100755 --- a/shadowsocks-csharp/Controller/Logging.cs +++ b/shadowsocks-csharp/Controller/Logging.cs @@ -32,11 +32,20 @@ namespace Shadowsocks.Controller } } - public static void Debug(object o) + public static void Error(object o) { + Console.WriteLine("[E] "+ o); + } -#if DEBUG + public static void Info(object o) + { Console.WriteLine(o); + } + + public static void Debug(object o) + { +#if DEBUG + Console.WriteLine("[D] " + o); #endif } diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index aca7e022..4d3bc119 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -126,8 +126,7 @@ namespace Shadowsocks.Controller var IP = Dns.GetHostAddresses(server.server).First(ip => (ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6)); var ping = new Ping(); var ret = new List(); - foreach ( - var timestamp in Enumerable.Range(0, Repeat).Select(_ => DateTime.Now.ToString(DateTimePattern))) + foreach (var timestamp in Enumerable.Range(0, Repeat).Select(_ => DateTime.Now.ToString(DateTimePattern))) { //ICMP echo. we can also set options and special bytes try @@ -146,7 +145,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - Console.WriteLine($"An exception occured when eveluating {server.FriendlyName()}"); + Logging.Error($"An exception occured while eveluating {server.FriendlyName()}"); Logging.LogUsefulException(e); } } diff --git a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs index 0185cc28..96d86ba0 100644 --- a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs @@ -38,6 +38,7 @@ namespace Shadowsocks.Controller { try { + File.WriteAllText(Utils.GetTempPath() + "\\gfwlist.txt", e.Result, Encoding.UTF8); List lines = ParseResult(e.Result); if (File.Exists(USER_RULE_FILE)) { @@ -92,7 +93,7 @@ namespace Shadowsocks.Controller http.DownloadStringAsync(new Uri(GFWLIST_URL)); } - public List ParseResult(string response) + public static List ParseResult(string response) { byte[] bytes = Convert.FromBase64String(response); string content = Encoding.ASCII.GetString(bytes); diff --git a/shadowsocks-csharp/Controller/Service/Listener.cs b/shadowsocks-csharp/Controller/Service/Listener.cs index fe59fe98..06994787 100644 --- a/shadowsocks-csharp/Controller/Service/Listener.cs +++ b/shadowsocks-csharp/Controller/Service/Listener.cs @@ -78,7 +78,7 @@ namespace Shadowsocks.Controller _tcpSocket.Listen(1024); // Start an asynchronous socket to listen for connections. - Console.WriteLine("Shadowsocks started"); + Logging.Info("Shadowsocks started"); _tcpSocket.BeginAccept( new AsyncCallback(AcceptCallback), _tcpSocket); @@ -163,7 +163,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - Console.WriteLine(e); + Logging.LogUsefulException(e); } finally { @@ -208,7 +208,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - Console.WriteLine(e); + Logging.LogUsefulException(e); conn.Close(); } } diff --git a/shadowsocks-csharp/Controller/Service/PACServer.cs b/shadowsocks-csharp/Controller/Service/PACServer.cs index e2d23658..c428fe0c 100644 --- a/shadowsocks-csharp/Controller/Service/PACServer.cs +++ b/shadowsocks-csharp/Controller/Service/PACServer.cs @@ -2,6 +2,7 @@ using Shadowsocks.Properties; using Shadowsocks.Util; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -15,19 +16,20 @@ namespace Shadowsocks.Controller class PACServer : Listener.Service { public static string PAC_FILE = "pac.txt"; - public static string USER_RULE_FILE = "user-rule.txt"; - public static string USER_ABP_FILE = "abp.txt"; - FileSystemWatcher watcher; + FileSystemWatcher PACFileWatcher; + FileSystemWatcher UserRuleFileWatcher; private Configuration _config; public event EventHandler PACFileChanged; + public event EventHandler UserRuleFileChanged; public PACServer() { this.WatchPacFile(); + this.WatchUserRuleFile(); } public void UpdateConfiguration(Configuration config) @@ -151,7 +153,7 @@ Connection: Close } catch (Exception e) { - Console.WriteLine(e); + Logging.LogUsefulException(e); socket.Close(); } } @@ -169,28 +171,81 @@ Connection: Close private void WatchPacFile() { - if (watcher != null) - { - watcher.Dispose(); - } - watcher = new FileSystemWatcher(Directory.GetCurrentDirectory()); - watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; - watcher.Filter = PAC_FILE; - watcher.Changed += Watcher_Changed; - watcher.Created += Watcher_Changed; - watcher.Deleted += Watcher_Changed; - watcher.Renamed += Watcher_Changed; - watcher.EnableRaisingEvents = true; + if (PACFileWatcher != null) + { + PACFileWatcher.Dispose(); + } + PACFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()); + PACFileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; + PACFileWatcher.Filter = PAC_FILE; + PACFileWatcher.Changed += PACFileWatcher_Changed; + PACFileWatcher.Created += PACFileWatcher_Changed; + PACFileWatcher.Deleted += PACFileWatcher_Changed; + PACFileWatcher.Renamed += PACFileWatcher_Changed; + PACFileWatcher.EnableRaisingEvents = true; + } + + private void WatchUserRuleFile() + { + if (UserRuleFileWatcher != null) + { + UserRuleFileWatcher.Dispose(); + } + UserRuleFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory()); + UserRuleFileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; + UserRuleFileWatcher.Filter = USER_RULE_FILE; + UserRuleFileWatcher.Changed += UserRuleFileWatcher_Changed; + UserRuleFileWatcher.Created += UserRuleFileWatcher_Changed; + UserRuleFileWatcher.Deleted += UserRuleFileWatcher_Changed; + UserRuleFileWatcher.Renamed += UserRuleFileWatcher_Changed; + UserRuleFileWatcher.EnableRaisingEvents = true; + } + + #region FileSystemWatcher.OnChanged() + + // FileSystemWatcher Changed event is raised twice + // http://stackoverflow.com/questions/1764809/filesystemwatcher-changed-event-is-raised-twice + private static Hashtable fileChangedTime = new Hashtable(); + + private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e) + { + string path = e.FullPath.ToString(); + string currentLastWriteTime = File.GetLastWriteTime(e.FullPath).ToString(); + + // if there is no path info stored yet or stored path has different time of write then the one now is inspected + if (!fileChangedTime.ContainsKey(path) || fileChangedTime[path].ToString() != currentLastWriteTime) + { + if (PACFileChanged != null) + { + Logging.Info($"Detected: PAC file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); + PACFileChanged(this, new EventArgs()); + } + + //lastly we update the last write time in the hashtable + fileChangedTime[path] = currentLastWriteTime; + } } - private void Watcher_Changed(object sender, FileSystemEventArgs e) + private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e) { - if (PACFileChanged != null) + string path = e.FullPath.ToString(); + string currentLastWriteTime = File.GetLastWriteTime(e.FullPath).ToString(); + + // if there is no path info stored yet or stored path has different time of write then the one now is inspected + if (!fileChangedTime.ContainsKey(path) || fileChangedTime[path].ToString() != currentLastWriteTime) { - PACFileChanged(this, new EventArgs()); + if (UserRuleFileChanged != null) + { + Logging.Info($"Detected: User Rule file '{e.Name}' was {e.ChangeType.ToString().ToLower()}."); + UserRuleFileChanged(this, new EventArgs()); + } + //lastly we update the last write time in the hashtable + fileChangedTime[path] = currentLastWriteTime; } } + #endregion + private string GetPACAddress(byte[] requestBuf, int length, IPEndPoint localEndPoint, bool useSocks) { //try @@ -204,7 +259,7 @@ Connection: Close //} //catch (Exception e) //{ - // Console.WriteLine(e); + // Logging.LogUsefulException(e); //} return (useSocks ? "SOCKS5 " : "PROXY ") + localEndPoint.Address + ":" + this._config.localPort + ";"; } diff --git a/shadowsocks-csharp/Controller/Service/PolipoRunner.cs b/shadowsocks-csharp/Controller/Service/PolipoRunner.cs index 5b784bcd..ad582d1e 100644 --- a/shadowsocks-csharp/Controller/Service/PolipoRunner.cs +++ b/shadowsocks-csharp/Controller/Service/PolipoRunner.cs @@ -56,7 +56,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logging.LogUsefulException(e); } } string polipoConfig = Resources.privoxy_conf; @@ -94,7 +94,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logging.LogUsefulException(e); } _process = null; } diff --git a/shadowsocks-csharp/Controller/Service/PortForwarder.cs b/shadowsocks-csharp/Controller/Service/PortForwarder.cs index 63848079..e577b535 100644 --- a/shadowsocks-csharp/Controller/Service/PortForwarder.cs +++ b/shadowsocks-csharp/Controller/Service/PortForwarder.cs @@ -140,7 +140,6 @@ namespace Shadowsocks.Controller } else { - //Console.WriteLine("bytesRead: " + bytesRead.ToString()); _local.Shutdown(SocketShutdown.Send); _localShutdown = true; CheckClose(); diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index c0989085..061345dc 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -49,7 +49,7 @@ namespace Shadowsocks.Controller lock (this.Handlers) { this.Handlers.Add(handler); - Logging.Debug($"connections: {Handlers.Count}"); + Logging.Debug($"TCP connections: {Handlers.Count}"); DateTime now = DateTime.Now; if (now - _lastSweepTime > TimeSpan.FromSeconds(1)) { @@ -65,10 +65,10 @@ namespace Shadowsocks.Controller } foreach (Handler handler1 in handlersToClose) { - Logging.Debug("Closing timed out connection"); + Logging.Debug("Closing timed out TCP connection."); handler1.Close(); } - return true; + return true; } } @@ -149,7 +149,7 @@ namespace Shadowsocks.Controller { lock (relay.Handlers) { - Logging.Debug($"connections: {relay.Handlers.Count}"); + Logging.Debug($"TCP connections: {relay.Handlers.Count}"); relay.Handlers.Remove(this); } lock (this) @@ -213,7 +213,7 @@ namespace Shadowsocks.Controller { // reject socks 4 response = new byte[] { 0, 91 }; - Console.WriteLine("socks 5 protocol error"); + Logging.Error("socks 5 protocol error"); } Logging.Debug($"======Send Local Port, size:" + response.Length); connection.BeginSend(response, 0, response.Length, 0, new AsyncCallback(HandshakeSendCallback), null); @@ -284,7 +284,7 @@ namespace Shadowsocks.Controller } else { - Console.WriteLine("failed to recv data in handshakeReceive2Callback"); + Logging.Error("failed to recv data in handshakeReceive2Callback"); this.Close(); } } @@ -431,7 +431,7 @@ namespace Shadowsocks.Controller { strategy.SetFailure(server); } - Console.WriteLine(String.Format("{0} timed out", server.FriendlyName())); + Logging.Info($"{server.FriendlyName()} timed out"); remote.Close(); RetryConnect(); } @@ -470,8 +470,7 @@ namespace Shadowsocks.Controller connected = true; - //Console.WriteLine("Socket connected to {0}", - // remote.RemoteEndPoint.ToString()); + Logging.Debug($"Socket connected to {remote.RemoteEndPoint}"); var latency = DateTime.Now - _startConnectTime; IStrategy strategy = controller.GetCurrentStrategy(); @@ -556,7 +555,6 @@ namespace Shadowsocks.Controller } else { - //Console.WriteLine("bytesRead: " + bytesRead.ToString()); connection.Shutdown(SocketShutdown.Send); connectionShutdown = true; CheckClose(); diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 7761e3f8..9e1693c4 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -7,6 +7,8 @@ using System.Threading; using System.Net.Sockets; using Shadowsocks.Controller.Strategy; using System.Net; +using Shadowsocks.Util; +using Shadowsocks.Properties; namespace Shadowsocks.Controller { @@ -314,6 +316,7 @@ namespace Shadowsocks.Controller { _pacServer = new PACServer(); _pacServer.PACFileChanged += pacServer_PACFileChanged; + _pacServer.UserRuleFileChanged += pacServer_UserRuleFileChanged; } _pacServer.UpdateConfiguration(_config); if (gfwListUpdater == null) @@ -424,6 +427,39 @@ namespace Shadowsocks.Controller UpdatePACFromGFWListError(this, e); } + private void pacServer_UserRuleFileChanged(object sender, EventArgs e) + { + // TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted()) + if (!File.Exists(Utils.GetTempPath() + "\\gfwlist.txt")) + { + UpdatePACFromGFWList(); + return; + } + List lines = GFWListUpdater.ParseResult(File.ReadAllText(Utils.GetTempPath() + "\\gfwlist.txt")); + if (File.Exists(PACServer.USER_RULE_FILE)) + { + string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); + string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string rule in rules) + { + if (rule.StartsWith("!") || rule.StartsWith("[")) + continue; + lines.Add(rule); + } + } + string abpContent = Utils.UnGzip(Resources.abp_js); + abpContent = abpContent.Replace("__RULES__", SimpleJson.SimpleJson.SerializeObject(lines)); + if (File.Exists(PACServer.PAC_FILE)) + { + string original = File.ReadAllText(PACServer.PAC_FILE, Encoding.UTF8); + if (original == abpContent) + { + return; + } + } + File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8); + } + private void StartReleasingMemory() { _ramThread = new Thread(new ThreadStart(ReleaseMemory)); diff --git a/shadowsocks-csharp/Controller/Strategy/HighAvailabilityStrategy.cs b/shadowsocks-csharp/Controller/Strategy/HighAvailabilityStrategy.cs index fa05a0c1..ba25ee18 100644 --- a/shadowsocks-csharp/Controller/Strategy/HighAvailabilityStrategy.cs +++ b/shadowsocks-csharp/Controller/Strategy/HighAvailabilityStrategy.cs @@ -132,14 +132,14 @@ namespace Shadowsocks.Controller.Strategy if (_currentServer == null || max.score - _currentServer.score > 200) { _currentServer = max; - Console.WriteLine("HA switching to server: {0}", _currentServer.server.FriendlyName()); + Logging.Info($"HA switching to server: {_currentServer.server.FriendlyName()}"); } } } public void UpdateLatency(Model.Server server, TimeSpan latency) { - Logging.Debug(String.Format("latency: {0} {1}", server.FriendlyName(), latency)); + Logging.Debug($"latency: {server.FriendlyName()} {latency}"); ServerStatus status; if (_serverStatus.TryGetValue(server, out status)) @@ -151,7 +151,7 @@ namespace Shadowsocks.Controller.Strategy public void UpdateLastRead(Model.Server server) { - Logging.Debug(String.Format("last read: {0}", server.FriendlyName())); + Logging.Debug($"last read: {server.FriendlyName()}"); ServerStatus status; if (_serverStatus.TryGetValue(server, out status)) @@ -162,7 +162,7 @@ namespace Shadowsocks.Controller.Strategy public void UpdateLastWrite(Model.Server server) { - Logging.Debug(String.Format("last write: {0}", server.FriendlyName())); + Logging.Debug($"last write: {server.FriendlyName()}"); ServerStatus status; if (_serverStatus.TryGetValue(server, out status)) @@ -173,7 +173,7 @@ namespace Shadowsocks.Controller.Strategy public void SetFailure(Model.Server server) { - Logging.Debug(String.Format("failure: {0}", server.FriendlyName())); + Logging.Debug($"failure: {server.FriendlyName()}"); ServerStatus status; if (_serverStatus.TryGetValue(server, out status)) diff --git a/shadowsocks-csharp/Encryption/PolarSSL.cs b/shadowsocks-csharp/Encryption/PolarSSL.cs index 42ce5bf7..3c1d8831 100755 --- a/shadowsocks-csharp/Encryption/PolarSSL.cs +++ b/shadowsocks-csharp/Encryption/PolarSSL.cs @@ -30,7 +30,7 @@ namespace Shadowsocks.Encryption } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logging.LogUsefulException(e); } LoadLibrary(dllPath); } diff --git a/shadowsocks-csharp/Encryption/Sodium.cs b/shadowsocks-csharp/Encryption/Sodium.cs index dc564ace..7a9d0c3c 100755 --- a/shadowsocks-csharp/Encryption/Sodium.cs +++ b/shadowsocks-csharp/Encryption/Sodium.cs @@ -26,7 +26,7 @@ namespace Shadowsocks.Encryption } catch (Exception e) { - Console.WriteLine(e.ToString()); + Logging.LogUsefulException(e); } LoadLibrary(dllPath); } diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index 58f9f941..c62ac090 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -72,7 +72,7 @@ namespace Shadowsocks.Model { if (!(e is FileNotFoundException)) { - Console.WriteLine(e); + Logging.LogUsefulException(e); } return new Configuration { @@ -167,6 +167,7 @@ namespace Shadowsocks.Model } } + // internal class private class JsonSerializerStrategy : SimpleJson.PocoJsonSerializerStrategy { // convert string to int diff --git a/shadowsocks-csharp/Model/LogViewerConfig.cs b/shadowsocks-csharp/Model/LogViewerConfig.cs index c82f1b22..4fe8f828 100644 --- a/shadowsocks-csharp/Model/LogViewerConfig.cs +++ b/shadowsocks-csharp/Model/LogViewerConfig.cs @@ -1,5 +1,7 @@ -using System; +using Shadowsocks.View; +using System; using System.Drawing; +using System.Windows.Forms; namespace Shadowsocks.Model { @@ -13,16 +15,37 @@ namespace Shadowsocks.Model public bool topMost; public bool wrapText; public bool toolbarShown; + public int width; + public int height; + public int top; + public int left; public LogViewerConfig() { - this.fontName = "Consolas"; - this.fontSize = 8; - this.bgColor = "black"; - this.textColor = "white"; - this.topMost = false; - this.wrapText = false; - this.toolbarShown = false; + fontName = "Consolas"; + fontSize = 8; + bgColor = "black"; + textColor = "white"; + topMost = false; + wrapText = false; + toolbarShown = false; + width = 600; + height = 400; + left = GetBestLeft(); + top = GetBestTop(); + } + + // Use GetBestTop() and GetBestLeft() to ensure the log viwer form can be always display IN screen. + public int GetBestLeft() + { + width = (width >= 400) ? width : 400; // set up the minimum size + return Screen.PrimaryScreen.WorkingArea.Width - width; + } + + public int GetBestTop() + { + height = (height >= 200) ? height : 200; // set up the minimum size + return Screen.PrimaryScreen.WorkingArea.Height - height; } public Font GetFont() diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index 1858ee90..eaa79501 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -7,6 +7,8 @@ using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; +using Shadowsocks.Controller; + namespace Shadowsocks.Util { public class Utils @@ -19,9 +21,10 @@ namespace Shadowsocks.Util try { Directory.CreateDirectory(Application.StartupPath + "\\temp"); - } catch (Exception e) + } + catch (Exception e) { - Console.WriteLine(e); + Logging.LogUsefulException(e); } // don't use "/", it will fail when we call explorer /select xxx/temp\xxx.log return Application.StartupPath + "\\temp"; diff --git a/shadowsocks-csharp/View/LogForm.Designer.cs b/shadowsocks-csharp/View/LogForm.Designer.cs index a4fcfad1..8f5e35c7 100644 --- a/shadowsocks-csharp/View/LogForm.Designer.cs +++ b/shadowsocks-csharp/View/LogForm.Designer.cs @@ -63,7 +63,7 @@ this.LogMessageTextBox.Name = "LogMessageTextBox"; this.LogMessageTextBox.ReadOnly = true; this.LogMessageTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.LogMessageTextBox.Size = new System.Drawing.Size(584, 377); + this.LogMessageTextBox.Size = new System.Drawing.Size(378, 99); this.LogMessageTextBox.TabIndex = 0; // // MainMenu @@ -141,7 +141,7 @@ // // TopMostCheckBox // - this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.TopMostCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.TopMostCheckBox.AutoSize = true; this.TopMostCheckBox.Location = new System.Drawing.Point(249, 3); @@ -176,7 +176,7 @@ // // WrapTextCheckBox // - this.WrapTextCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.WrapTextCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left))); this.WrapTextCheckBox.AutoSize = true; this.WrapTextCheckBox.Location = new System.Drawing.Point(165, 3); @@ -199,7 +199,7 @@ this.tableLayoutPanel1.RowCount = 2; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.Size = new System.Drawing.Size(590, 418); + this.tableLayoutPanel1.Size = new System.Drawing.Size(384, 140); this.tableLayoutPanel1.TabIndex = 2; // // ToolbarFlowLayoutPanel @@ -212,16 +212,17 @@ this.ToolbarFlowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; this.ToolbarFlowLayoutPanel.Location = new System.Drawing.Point(3, 3); this.ToolbarFlowLayoutPanel.Name = "ToolbarFlowLayoutPanel"; - this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(584, 29); + this.ToolbarFlowLayoutPanel.Size = new System.Drawing.Size(378, 29); this.ToolbarFlowLayoutPanel.TabIndex = 2; // // LogForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(590, 418); + this.ClientSize = new System.Drawing.Size(384, 140); this.Controls.Add(this.tableLayoutPanel1); this.Menu = this.MainMenu; + this.MinimumSize = new System.Drawing.Size(400, 200); this.Name = "LogForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Log Viewer"; diff --git a/shadowsocks-csharp/View/LogForm.cs b/shadowsocks-csharp/View/LogForm.cs index e2bf9fdd..a8fe2e4c 100644 --- a/shadowsocks-csharp/View/LogForm.cs +++ b/shadowsocks-csharp/View/LogForm.cs @@ -27,17 +27,21 @@ namespace Shadowsocks.View this.controller = controller; this.filename = filename; InitializeComponent(); - this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); + Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); LogViewerConfig config = controller.GetConfigurationCopy().logViewer; if (config == null) + { config = new LogViewerConfig(); - topMostTrigger = config.topMost; - wrapTextTrigger = config.wrapText; - toolbarTrigger = config.toolbarShown; - LogMessageTextBox.BackColor = config.GetBackgroundColor(); - LogMessageTextBox.ForeColor = config.GetTextColor(); - LogMessageTextBox.Font = config.GetFont(); + } + else { + topMostTrigger = config.topMost; + wrapTextTrigger = config.wrapText; + toolbarTrigger = config.toolbarShown; + LogMessageTextBox.BackColor = config.GetBackgroundColor(); + LogMessageTextBox.ForeColor = config.GetTextColor(); + LogMessageTextBox.Font = config.GetFont(); + } UpdateTexts(); } @@ -57,7 +61,7 @@ namespace Shadowsocks.View WrapTextMenuItem.Text = I18N.GetString("&Wrap Text"); TopMostMenuItem.Text = I18N.GetString("&Top Most"); ShowToolbarMenuItem.Text = I18N.GetString("&Show Toolbar"); - this.Text = I18N.GetString("Log Viewer"); + Text = I18N.GetString("Log Viewer"); } private void Timer_Tick(object sender, EventArgs e) @@ -118,8 +122,16 @@ namespace Shadowsocks.View timer.Tick += Timer_Tick; timer.Start(); + LogViewerConfig config = controller.GetConfigurationCopy().logViewer; + if (config == null) + config = new LogViewerConfig(); + Height = config.height; + Width = config.width; + Top = config.GetBestTop(); + Left = config.GetBestLeft(); + topMostTriggerLock = true; - this.TopMost = TopMostMenuItem.Checked = TopMostCheckBox.Checked = topMostTrigger; + TopMost = TopMostMenuItem.Checked = TopMostCheckBox.Checked = topMostTrigger; topMostTriggerLock = false; wrapTextTriggerLock = true; @@ -141,19 +153,23 @@ namespace Shadowsocks.View config.SetFont(LogMessageTextBox.Font); config.SetBackgroundColor(LogMessageTextBox.BackColor); config.SetTextColor(LogMessageTextBox.ForeColor); + config.top = Top; + config.left = Left; + config.height = Height; + config.width = Width; controller.SaveLogViewerConfig(config); } private void OpenLocationMenuItem_Click(object sender, EventArgs e) { string argument = "/select, \"" + filename + "\""; - Console.WriteLine(argument); + Logging.Debug(argument); System.Diagnostics.Process.Start("explorer.exe", argument); } private void ExitMenuItem_Click(object sender, EventArgs e) { - this.Close(); + Close(); } private void LogForm_Shown(object sender, EventArgs e) @@ -208,7 +224,7 @@ namespace Shadowsocks.View } #endregion - #region Trigger the log messages wrapable, or not. + #region Trigger the log messages to wrapable, or not. bool wrapTextTrigger = false; bool wrapTextTriggerLock = false; @@ -241,7 +257,7 @@ namespace Shadowsocks.View } #endregion - #region Trigger this window top most, or not. + #region Trigger the window to top most, or not. bool topMostTrigger = false; bool topMostTriggerLock = false; @@ -250,7 +266,7 @@ namespace Shadowsocks.View topMostTriggerLock = true; topMostTrigger = !topMostTrigger; - this.TopMost = topMostTrigger; + TopMost = topMostTrigger; TopMostMenuItem.Checked = TopMostCheckBox.Checked = topMostTrigger; topMostTriggerLock = false; diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 03bdcb36..b47fe038 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -44,6 +44,8 @@ namespace Shadowsocks.View private MenuItem editOnlinePACItem; private MenuItem autoCheckUpdatesToggleItem; private ConfigForm configForm; + private List logForms = new List(); + private bool logFormsVisible = false; private string _urlToOpen; public MenuViewController(ShadowsocksController controller) @@ -289,7 +291,6 @@ namespace Shadowsocks.View } } - private void LoadCurrentConfiguration() { Configuration config = controller.GetConfigurationCopy(); @@ -357,6 +358,32 @@ namespace Shadowsocks.View } } + private void ShowLogForms() + { + if (logForms.Count == 0) + { + LogForm f = new LogForm(controller, Logging.LogFile); + f.Show(); + f.FormClosed += logForm_FormClosed; + + logForms.Add(f); + logFormsVisible = true; + } + else + { + logFormsVisible = !logFormsVisible; + foreach (LogForm f in logForms) + { + f.Visible = logFormsVisible; + } + } + } + + void logForm_FormClosed(object sender, FormClosedEventArgs e) + { + logForms.Remove((LogForm)sender); + } + void configForm_FormClosed(object sender, FormClosedEventArgs e) { configForm = null; @@ -451,11 +478,13 @@ namespace Shadowsocks.View private void ShowLogItem_Click(object sender, EventArgs e) { - string argument = Logging.LogFile; + LogForm f = new LogForm(controller, Logging.LogFile); + f.Show(); + f.FormClosed += logForm_FormClosed; - new LogForm(controller, argument).Show(); + logForms.Add(f); } - + private void StatisticsConfigItem_Click(object sender, EventArgs e) { StatisticsStrategyConfigurationForm form = new StatisticsStrategyConfigurationForm(controller); @@ -564,9 +593,11 @@ namespace Shadowsocks.View Process.Start(_urlToOpen); } - private void AutoStartupItem_Click(object sender, EventArgs e) { + private void AutoStartupItem_Click(object sender, EventArgs e) + { AutoStartupItem.Checked = !AutoStartupItem.Checked; - if (!AutoStartup.Set(AutoStartupItem.Checked)) { + if (!AutoStartup.Set(AutoStartupItem.Checked)) + { MessageBox.Show(I18N.GetString("Failed to update registry")); } } diff --git a/test/packages.config b/test/packages.config index 8f91c0e4..7d90c6e3 100644 --- a/test/packages.config +++ b/test/packages.config @@ -1,5 +1,8 @@ - - - - + + + + + + + \ No newline at end of file diff --git a/test/test.csproj b/test/test.csproj index 55798adc..e441b8c2 100755 --- a/test/test.csproj +++ b/test/test.csproj @@ -17,6 +17,8 @@ False UnitTest + + bin\x86\Debug\ @@ -30,8 +32,29 @@ + + ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\shadowsocks-csharp\3rd\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + + ..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\shadowsocks-csharp\3rd\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + True + @@ -79,6 +102,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +