diff --git a/CHANGES b/CHANGES
index 6b0c6322..d95eac53 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2.5.2 2015-08-04
+- Add log viewer
+
2.5.1 2015-07-26
- Prevent HA from switching servers too frequently
- Fix server settings can not be updated when using HA
diff --git a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs
index 9979dcd9..3a9b9d25 100644
--- a/shadowsocks-csharp/Controller/Service/UpdateChecker.cs
+++ b/shadowsocks-csharp/Controller/Service/UpdateChecker.cs
@@ -18,7 +18,7 @@ namespace Shadowsocks.Controller
public string LatestVersionURL;
public event EventHandler NewVersionFound;
- public const string Version = "2.5.1";
+ public const string Version = "2.5.2";
public void CheckUpdate(Configuration config)
{
diff --git a/shadowsocks-csharp/View/LogForm.Designer.cs b/shadowsocks-csharp/View/LogForm.Designer.cs
new file mode 100644
index 00000000..e9a0cfbc
--- /dev/null
+++ b/shadowsocks-csharp/View/LogForm.Designer.cs
@@ -0,0 +1,112 @@
+namespace Shadowsocks.View
+{
+ partial class LogForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
+ this.menuItem1 = new System.Windows.Forms.MenuItem();
+ this.menuItem2 = new System.Windows.Forms.MenuItem();
+ this.menuItem4 = new System.Windows.Forms.MenuItem();
+ this.SuspendLayout();
+ //
+ // textBox1
+ //
+ this.textBox1.BackColor = System.Drawing.Color.Black;
+ this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.textBox1.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBox1.ForeColor = System.Drawing.Color.White;
+ this.textBox1.Location = new System.Drawing.Point(0, 0);
+ this.textBox1.MaxLength = 2147483647;
+ this.textBox1.Multiline = true;
+ this.textBox1.Name = "textBox1";
+ this.textBox1.ReadOnly = true;
+ this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+ this.textBox1.Size = new System.Drawing.Size(547, 382);
+ this.textBox1.TabIndex = 0;
+ this.textBox1.WordWrap = false;
+ //
+ // contextMenuStrip1
+ //
+ this.contextMenuStrip1.Name = "contextMenuStrip1";
+ this.contextMenuStrip1.Size = new System.Drawing.Size(61, 4);
+ //
+ // mainMenu1
+ //
+ this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.menuItem1});
+ //
+ // menuItem1
+ //
+ this.menuItem1.Index = 0;
+ this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.menuItem2,
+ this.menuItem4});
+ this.menuItem1.Text = "&File";
+ //
+ // menuItem2
+ //
+ this.menuItem2.Index = 0;
+ this.menuItem2.Text = "&Open Location";
+ this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
+ //
+ // menuItem4
+ //
+ this.menuItem4.Index = 1;
+ this.menuItem4.Text = "E&xit";
+ this.menuItem4.Click += new System.EventHandler(this.menuItem4_Click);
+ //
+ // LogForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(547, 382);
+ this.Controls.Add(this.textBox1);
+ this.Menu = this.mainMenu1;
+ this.Name = "LogForm";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "Log Viewer";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.LogForm_FormClosing);
+ this.Load += new System.EventHandler(this.LogForm_Load);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
+ private System.Windows.Forms.MainMenu mainMenu1;
+ private System.Windows.Forms.MenuItem menuItem1;
+ private System.Windows.Forms.MenuItem menuItem2;
+ private System.Windows.Forms.MenuItem menuItem4;
+ }
+}
\ No newline at end of file
diff --git a/shadowsocks-csharp/View/LogForm.cs b/shadowsocks-csharp/View/LogForm.cs
new file mode 100644
index 00000000..3f20dd50
--- /dev/null
+++ b/shadowsocks-csharp/View/LogForm.cs
@@ -0,0 +1,109 @@
+using Shadowsocks.Properties;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Shadowsocks.View
+{
+ public partial class LogForm : Form
+ {
+ FileSystemWatcher watcher;
+ long lastOffset;
+ string filename;
+ Timer timer;
+ const int BACK_OFFSET = 65536;
+
+ public LogForm(string filename)
+ {
+ this.filename = filename;
+ InitializeComponent();
+ this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon());
+ }
+
+ private void Timer_Tick(object sender, EventArgs e)
+ {
+ UpdateContent();
+ }
+
+ private void InitContent()
+ {
+ using (StreamReader reader = new StreamReader(new FileStream(filename,
+ FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
+ {
+ if (reader.BaseStream.Length > BACK_OFFSET)
+ {
+ reader.BaseStream.Seek(-BACK_OFFSET, SeekOrigin.End);
+ reader.ReadLine();
+ }
+
+ string line = "";
+ while ((line = reader.ReadLine()) != null)
+ textBox1.AppendText(line + "\r\n");
+
+ textBox1.ScrollToCaret();
+
+ lastOffset = reader.BaseStream.Position;
+ }
+ }
+
+ private void UpdateContent()
+ {
+ using (StreamReader reader = new StreamReader(new FileStream(filename,
+ FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
+ {
+ reader.BaseStream.Seek(lastOffset, SeekOrigin.Begin);
+
+ string line = "";
+ bool changed = false;
+ while ((line = reader.ReadLine()) != null)
+ {
+ changed = true;
+ textBox1.AppendText(line + "\r\n");
+ }
+
+ if (changed)
+ {
+ textBox1.ScrollToCaret();
+ }
+
+ lastOffset = reader.BaseStream.Position;
+ }
+ }
+
+ private void LogForm_Load(object sender, EventArgs e)
+ {
+ InitContent();
+ timer = new Timer();
+ timer.Interval = 300;
+ timer.Tick += Timer_Tick;
+ timer.Start();
+ }
+
+ private void LogForm_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ timer.Stop();
+ }
+
+ private void menuItem2_Click(object sender, EventArgs e)
+ {
+ string argument = @"/select, " + filename;
+ System.Diagnostics.Process.Start("explorer.exe", argument);
+ }
+
+ private void menuItem3_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void menuItem4_Click(object sender, EventArgs e)
+ {
+ this.Close();
+ }
+ }
+}
diff --git a/shadowsocks-csharp/View/LogForm.resx b/shadowsocks-csharp/View/LogForm.resx
new file mode 100644
index 00000000..34b690ce
--- /dev/null
+++ b/shadowsocks-csharp/View/LogForm.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 172, 17
+
+
\ No newline at end of file