Browse Source

add an option for Ping tests (disabled by default) and improve the readability of the code

tags/3.0
icylogic 8 years ago
parent
commit
bec1f808b3
5 changed files with 137 additions and 221 deletions
  1. +74
    -107
      shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs
  2. +2
    -10
      shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs
  3. +7
    -43
      shadowsocks-csharp/Model/StatisticsStrategyConfiguration.cs
  4. +48
    -60
      shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs
  5. +6
    -1
      shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs

+ 74
- 107
shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs View File

@@ -19,84 +19,87 @@ namespace Shadowsocks.Controller
public sealed class AvailabilityStatistics : IDisposable
{
public const string DateTimePattern = "yyyy-MM-dd HH:mm:ss";
public static readonly DateTime UnknownDateTime;
private const string StatisticsFilesName = "shadowsocks.availability.json";
private const int TimeoutMilliseconds = 500;
public static string AvailabilityStatisticsFile;
//static constructor to initialize every public static fields before refereced
static AvailabilityStatistics()
{
AvailabilityStatisticsFile = Utils.GetTempPath(StatisticsFilesName);
UnknownDateTime = new DateTime(1970, 1, 1);
}

public static readonly DateTime UnknownDateTime = new DateTime(1970, 1, 1);
//arguments for ICMP tests
private int Repeat => Config.RepeatTimesNum;
private const int TimeoutMilliseconds = 500;

public static string AvailabilityStatisticsFile;
private readonly TimeSpan _delayBeforeStart = TimeSpan.FromSeconds(1);
private readonly TimeSpan _monitorInterval = TimeSpan.FromSeconds(1);
private readonly TimeSpan _retryInterval = TimeSpan.FromMinutes(2); //retry 2 minutes after failed
private readonly TimeSpan _writingInterval = TimeSpan.FromMinutes(1);
private StatisticsStrategyConfiguration _config;
private ShadowsocksController _controller;
private Server _currentServer;
//records cache for current server in {_monitorInterval} minutes
private List<int> _latencyRecords;
//speed in KiB/s
private List<int> _inboundSpeedRecords;
private long _lastInboundCounter;
private List<int> _inboundSpeedRecords;
private long _lastOutboundCounter;
private List<int> _latencyRecords;
private List<int> _outboundSpeedRecords;
private Timer _recorder;
private List<Server> _servers;
private Timer _speedMonior;
private Timer _writer;

//static constructor to initialize every public static fields before refereced
static AvailabilityStatistics()
{
AvailabilityStatisticsFile = Utils.GetTempPath(StatisticsFilesName);
}
//tasks
private readonly TimeSpan _delayBeforeStart = TimeSpan.FromSeconds(1);
private readonly TimeSpan _retryInterval = TimeSpan.FromMinutes(2);
private Timer _recorder; //analyze and save cached records to RawStatistics and filter records
private TimeSpan RecordingInterval => TimeSpan.FromMinutes(Config.DataCollectionMinutes);
private Timer _speedMonior;
private readonly TimeSpan _monitorInterval = TimeSpan.FromSeconds(1);
private Timer _writer; //write RawStatistics to file
private readonly TimeSpan _writingInterval = TimeSpan.FromMinutes(1);

private AvailabilityStatistics()
{
RawStatistics = new Statistics();
}
private ShadowsocksController _controller;
private StatisticsStrategyConfiguration Config => _controller.StatisticsConfiguration;
private Server CurrentServer => _controller.GetCurrentServer();

// Static Singleton Initialization
public static AvailabilityStatistics Instance { get; } = new AvailabilityStatistics();
public Statistics RawStatistics { get; private set; }
public Statistics FilteredStatistics { get; private set; }
private int Repeat => _config.RepeatTimesNum;
private TimeSpan RecordingInterval => TimeSpan.FromMinutes(_config.DataCollectionMinutes);

public bool Set(StatisticsStrategyConfiguration config)
private AvailabilityStatistics()
{
RawStatistics = new Statistics();
}

internal void UpdateConfiguration(ShadowsocksController controller)
{
_config = config;
_controller = controller;
Reset();
try
{
if (config.StatisticsEnabled)
if (Config.StatisticsEnabled)
{
if (_recorder?.Change(_delayBeforeStart, RecordingInterval) == null)
{
_recorder = new Timer(Run, null, _delayBeforeStart, RecordingInterval);
}
StartTimerWithoutState(ref _recorder, Run, RecordingInterval);
LoadRawStatistics();
if (_speedMonior?.Change(_delayBeforeStart, _monitorInterval) == null)
{
_speedMonior = new Timer(UpdateSpeed, null, _delayBeforeStart, _monitorInterval);
}
if (_writer?.Change(_delayBeforeStart, RecordingInterval) == null)
{
_writer = new Timer(Save, null, _delayBeforeStart, RecordingInterval);
}
StartTimerWithoutState(ref _speedMonior, UpdateSpeed, _monitorInterval);
StartTimerWithoutState(ref _writer, Save, _writingInterval);
}
else
{
_recorder?.Dispose();
_speedMonior?.Dispose();
_writer?.Dispose();
}
return true;
}
catch (Exception e)
{
Logging.LogUsefulException(e);
return false;
}
}

private void UpdateSpeed(object state)
private void StartTimerWithoutState(ref Timer timer, TimerCallback callback, TimeSpan interval)
{
if (timer?.Change(_delayBeforeStart, interval) == null)
{
timer = new Timer(callback, null, _delayBeforeStart, interval);
}
}

private void UpdateSpeed(object _)
{
var bytes = _controller.inboundCounter - _lastInboundCounter;
_lastInboundCounter = _controller.inboundCounter;
@@ -109,7 +112,7 @@ namespace Shadowsocks.Controller
_outboundSpeedRecords.Add(outboundSpeed);

Logging.Debug(
$"{_currentServer.FriendlyName()}: current/max inbound {inboundSpeed}/{_inboundSpeedRecords.Max()} KiB/s, current/max outbound {outboundSpeed}/{_outboundSpeedRecords.Max()} KiB/s");
$"{CurrentServer.FriendlyName()}: current/max inbound {inboundSpeed}/{_inboundSpeedRecords.Max()} KiB/s, current/max outbound {outboundSpeed}/{_outboundSpeedRecords.Max()} KiB/s");
}

private async Task<ICMPResult> ICMPTest(Server server)
@@ -168,94 +171,66 @@ namespace Shadowsocks.Controller

private void Run(object _)
{
AppendRecord();
UpdateRecords();
Reset();
FilterRawStatistics();
}

private async void AppendRecord()
private async void UpdateRecords()
{
//todo: option for icmp test
var icmpResults = TaskEx.WhenAll(_servers.Select(ICMPTest));
var currentServerRecord = new StatisticsRecord(CurrentServer.Identifier(), _inboundSpeedRecords, _outboundSpeedRecords, _latencyRecords);

var currentServerRecord = new StatisticsRecord(_currentServer.Identifier(),
_inboundSpeedRecords, _outboundSpeedRecords, _latencyRecords);
if (!Config.Ping)
{
AppendRecord(CurrentServer, currentServerRecord);
return;
}

var icmpResults = TaskEx.WhenAll(_controller.GetCurrentConfiguration().configs.Select(ICMPTest));

foreach (var result in (await icmpResults).Where(result => result != null))
{
List<StatisticsRecord> records;
if (!RawStatistics.TryGetValue(result.Server.Identifier(), out records))
{
records = new List<StatisticsRecord>();
}

if (result.Server.Equals(_currentServer))
if (result.Server.Equals(CurrentServer))
{
currentServerRecord.setResponse(result.RoundtripTime);
records.Add(currentServerRecord);
AppendRecord(CurrentServer, currentServerRecord);
}
else
{
records.Add(new StatisticsRecord(result.Server.Identifier(), result.RoundtripTime));
AppendRecord(result.Server, new StatisticsRecord(result.Server.Identifier(), result.RoundtripTime));
}
RawStatistics[result.Server.Identifier()] = records;
}
}

private void Save(object _)
private void AppendRecord(Server server, StatisticsRecord record)
{
try
List<StatisticsRecord> records;
if (!RawStatistics.TryGetValue(server.Identifier(), out records))
{
File.WriteAllText(AvailabilityStatisticsFile,
JsonConvert.SerializeObject(RawStatistics, Formatting.None));
}
catch (IOException e)
{
Logging.LogUsefulException(e);
_writer.Change(_retryInterval, _writingInterval);
records = new List<StatisticsRecord>();
}
records.Add(record);
RawStatistics[server.Identifier()] = records;
}

/*
private static void Append(DataList dataList, IEnumerable<DataUnit> extra)
private void Save(object _)
{
var data = dataList.Concat(extra);
var dataLine = string.Join(Delimiter, data.Select(kv => kv.Value).ToArray());
string[] lines;
if (!File.Exists(AvailabilityStatisticsFile))
{
var headerLine = string.Join(Delimiter, data.Select(kv => kv.Key).ToArray());
lines = new[] { headerLine, dataLine };
}
else
{
lines = new[] { dataLine };
}
try
{
File.AppendAllLines(AvailabilityStatisticsFile, lines);
File.WriteAllText(AvailabilityStatisticsFile,
JsonConvert.SerializeObject(RawStatistics, Formatting.None));
}
catch (IOException e)
{
Logging.LogUsefulException(e);
_writer.Change(_retryInterval, _writingInterval);
}
}
*/

internal void UpdateConfiguration(ShadowsocksController controller)
{
_controller = controller;
_currentServer = _controller.GetCurrentServer();
Reset();
Set(controller.StatisticsConfiguration);
_servers = _controller.GetCurrentConfiguration().configs;
}

private bool IsValidRecord(StatisticsRecord record)
{
if (_config.ByHourOfDay)
if (Config.ByHourOfDay)
{
var currentHour = DateTime.Now.Hour;
if (record.Timestamp == UnknownDateTime) return false;
if (!record.Timestamp.Hour.Equals(DateTime.Now.Hour)) return false;
}
@@ -288,7 +263,7 @@ namespace Shadowsocks.Controller
{
try
{
using (var fs = File.Create(path))
using (File.Create(path))
{
//do nothing
}
@@ -313,14 +288,6 @@ namespace Shadowsocks.Controller
}
}

private DateTime ParseExactOrUnknown(string str)
{
DateTime dateTime;
return !DateTime.TryParseExact(str, DateTimePattern, null, DateTimeStyles.None, out dateTime)
? UnknownDateTime
: dateTime;
}

public void UpdateLatency(int latency)
{
_latencyRecords.Add(latency);


+ 2
- 10
shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;

using Newtonsoft.Json;
@@ -27,7 +26,7 @@ namespace Shadowsocks.Controller.Strategy
{
_controller = controller;
var servers = controller.GetCurrentConfiguration().configs;
var randomIndex = new Random().Next() % servers.Count();
var randomIndex = new Random().Next() % servers.Count;
_currentServer = servers[randomIndex]; //choose a server randomly at first
_timer = new Timer(ReloadStatisticsAndChooseAServer);
}
@@ -117,14 +116,10 @@ namespace Shadowsocks.Controller.Strategy

public Server GetAServer(IStrategyCallerType type, IPEndPoint localIPEndPoint)
{
var oldServer = _currentServer;
if (oldServer == null)
if (_currentServer == null)
{
ChooseNewServer(_controller.GetCurrentConfiguration().configs);
}
if (oldServer != _currentServer)
{
}
return _currentServer; //current server cached for CachedInterval
}

@@ -141,17 +136,14 @@ namespace Shadowsocks.Controller.Strategy

public void UpdateLastRead(Server server)
{
//TODO: combine this part of data with ICMP statics
}

public void UpdateLastWrite(Server server)
{
//TODO: combine this part of data with ICMP statics
}

public void UpdateLatency(Server server, TimeSpan latency)
{
//TODO: combine this part of data with ICMP statics
}

public void Dispose()


+ 7
- 43
shadowsocks-csharp/Model/StatisticsStrategyConfiguration.cs View File

@@ -13,13 +13,13 @@ namespace Shadowsocks.Model
[Serializable]
public class StatisticsStrategyConfiguration
{
public static readonly string ID = "com.shadowsocks.strategy.statistics";
private bool _statisticsEnabled = true;
private bool _byIsp = false;
private bool _byHourOfDay = false;
private int _choiceKeptMinutes = 10;
private int _dataCollectionMinutes = 10;
private int _repeatTimesNum = 4;
public static readonly string ID = "com.shadowsocks.strategy.statistics";
public bool StatisticsEnabled { get; } = true;
public bool ByHourOfDay { get; } = true;
public bool Ping { get; set; }
public int ChoiceKeptMinutes { get; } = 10;
public int DataCollectionMinutes { get; } = 10;
public int RepeatTimesNum { get; } = 4;

private const string ConfigFile = "statistics-config.json";

@@ -64,41 +64,5 @@ namespace Shadowsocks.Model
var properties = typeof(StatisticsRecord).GetFields(BindingFlags.Instance | BindingFlags.Public);
Calculations = properties.ToDictionary(p => p.Name, _ => (float)0);
}

public bool StatisticsEnabled
{
get { return _statisticsEnabled; }
set { _statisticsEnabled = value; }
}

public bool ByIsp
{
get { return _byIsp; }
set { _byIsp = value; }
}

public bool ByHourOfDay
{
get { return _byHourOfDay; }
set { _byHourOfDay = value; }
}

public int ChoiceKeptMinutes
{
get { return _choiceKeptMinutes; }
set { _choiceKeptMinutes = value; }
}

public int DataCollectionMinutes
{
get { return _dataCollectionMinutes; }
set { _dataCollectionMinutes = value; }
}

public int RepeatTimesNum
{
get { return _repeatTimesNum; }
set { _repeatTimesNum = value; }
}
}
}

+ 48
- 60
shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs View File

@@ -34,10 +34,9 @@
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series();
this.StatisticsChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
this.byISPCheckBox = new System.Windows.Forms.CheckBox();
this.PingCheckBox = new System.Windows.Forms.CheckBox();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.chartModeSelector = new System.Windows.Forms.GroupBox();
this.allMode = new System.Windows.Forms.RadioButton();
this.dayMode = new System.Windows.Forms.RadioButton();
@@ -111,57 +110,48 @@
series2.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.DateTime;
this.StatisticsChart.Series.Add(series1);
this.StatisticsChart.Series.Add(series2);
this.StatisticsChart.Size = new System.Drawing.Size(1077, 303);
this.StatisticsChart.Size = new System.Drawing.Size(1089, 303);
this.StatisticsChart.TabIndex = 2;
//
// byISPCheckBox
// PingCheckBox
//
this.byISPCheckBox.AutoSize = true;
this.byISPCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this.bindingConfiguration, "ByIsp", true));
this.byISPCheckBox.Location = new System.Drawing.Point(13, 54);
this.byISPCheckBox.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.byISPCheckBox.Name = "byISPCheckBox";
this.byISPCheckBox.Size = new System.Drawing.Size(220, 31);
this.byISPCheckBox.TabIndex = 5;
this.byISPCheckBox.Text = "By ISP/geolocation";
this.byISPCheckBox.UseVisualStyleBackColor = true;
this.PingCheckBox.AutoSize = true;
this.PingCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this.bindingConfiguration, "Ping", true));
this.PingCheckBox.Location = new System.Drawing.Point(13, 54);
this.PingCheckBox.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.PingCheckBox.Name = "PingCheckBox";
this.PingCheckBox.Size = new System.Drawing.Size(107, 27);
this.PingCheckBox.TabIndex = 5;
this.PingCheckBox.Text = "Ping Test";
this.PingCheckBox.UseVisualStyleBackColor = true;
this.PingCheckBox.CheckedChanged += new System.EventHandler(this.PingCheckBox_CheckedChanged);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(8, 136);
this.label2.Location = new System.Drawing.Point(9, 267);
this.label2.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(167, 27);
this.label2.Size = new System.Drawing.Size(144, 23);
this.label2.TabIndex = 8;
this.label2.Text = "Keep choice for ";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(285, 136);
this.label3.Location = new System.Drawing.Point(286, 267);
this.label3.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(87, 27);
this.label3.Size = new System.Drawing.Size(75, 23);
this.label3.TabIndex = 9;
this.label3.Text = "minutes";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(8, 218);
this.label4.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(54, 27);
this.label4.TabIndex = 10;
this.label4.Text = "Ping";
//
// chartModeSelector
//
this.chartModeSelector.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.chartModeSelector.Controls.Add(this.allMode);
this.chartModeSelector.Controls.Add(this.dayMode);
this.chartModeSelector.Location = new System.Drawing.Point(801, 104);
this.chartModeSelector.Location = new System.Drawing.Point(813, 98);
this.chartModeSelector.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.chartModeSelector.Name = "chartModeSelector";
this.chartModeSelector.Padding = new System.Windows.Forms.Padding(5, 10, 5, 10);
@@ -178,7 +168,7 @@
this.allMode.Location = new System.Drawing.Point(11, 61);
this.allMode.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.allMode.Name = "allMode";
this.allMode.Size = new System.Drawing.Size(58, 31);
this.allMode.Size = new System.Drawing.Size(50, 27);
this.allMode.TabIndex = 1;
this.allMode.TabStop = true;
this.allMode.Text = "all";
@@ -191,7 +181,7 @@
this.dayMode.Location = new System.Drawing.Point(11, 29);
this.dayMode.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.dayMode.Name = "dayMode";
this.dayMode.Size = new System.Drawing.Size(73, 31);
this.dayMode.Size = new System.Drawing.Size(61, 27);
this.dayMode.TabIndex = 0;
this.dayMode.Text = "24h";
this.dayMode.UseVisualStyleBackColor = true;
@@ -217,7 +207,7 @@
this.splitContainer1.Panel2.Controls.Add(this.OKButton);
this.splitContainer1.Panel2.Controls.Add(this.chartModeSelector);
this.splitContainer1.Panel2.Controls.Add(this.StatisticsChart);
this.splitContainer1.Size = new System.Drawing.Size(1077, 614);
this.splitContainer1.Size = new System.Drawing.Size(1089, 614);
this.splitContainer1.SplitterDistance = 301;
this.splitContainer1.SplitterWidth = 10;
this.splitContainer1.TabIndex = 12;
@@ -242,14 +232,13 @@
this.splitContainer2.Panel1.Controls.Add(this.repeatTimesNum);
this.splitContainer2.Panel1.Controls.Add(this.label6);
this.splitContainer2.Panel1.Controls.Add(this.label2);
this.splitContainer2.Panel1.Controls.Add(this.label4);
this.splitContainer2.Panel1.Controls.Add(this.byISPCheckBox);
this.splitContainer2.Panel1.Controls.Add(this.PingCheckBox);
this.splitContainer2.Panel1.Controls.Add(this.label3);
//
// splitContainer2.Panel2
//
this.splitContainer2.Panel2.Controls.Add(this.splitContainer3);
this.splitContainer2.Size = new System.Drawing.Size(1077, 301);
this.splitContainer2.Size = new System.Drawing.Size(1089, 301);
this.splitContainer2.SplitterDistance = 384;
this.splitContainer2.SplitterWidth = 5;
this.splitContainer2.TabIndex = 7;
@@ -257,10 +246,10 @@
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(8, 175);
this.label9.Location = new System.Drawing.Point(9, 164);
this.label9.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(162, 27);
this.label9.Size = new System.Drawing.Size(139, 23);
this.label9.TabIndex = 20;
this.label9.Text = "Collect data per";
//
@@ -268,10 +257,10 @@
//
this.label8.AutoSize = true;
this.label8.Font = new System.Drawing.Font("Microsoft YaHei", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label8.Location = new System.Drawing.Point(285, 176);
this.label8.Location = new System.Drawing.Point(286, 165);
this.label8.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(87, 27);
this.label8.Size = new System.Drawing.Size(75, 23);
this.label8.TabIndex = 19;
this.label8.Text = "minutes";
//
@@ -283,7 +272,7 @@
0,
0,
0});
this.dataCollectionMinutesNum.Location = new System.Drawing.Point(176, 173);
this.dataCollectionMinutesNum.Location = new System.Drawing.Point(177, 162);
this.dataCollectionMinutesNum.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.dataCollectionMinutesNum.Maximum = new decimal(new int[] {
120,
@@ -296,7 +285,7 @@
0,
0});
this.dataCollectionMinutesNum.Name = "dataCollectionMinutesNum";
this.dataCollectionMinutesNum.Size = new System.Drawing.Size(100, 34);
this.dataCollectionMinutesNum.Size = new System.Drawing.Size(100, 29);
this.dataCollectionMinutesNum.TabIndex = 18;
this.dataCollectionMinutesNum.Value = new decimal(new int[] {
10,
@@ -311,7 +300,7 @@
this.StatisticsEnabledCheckBox.Location = new System.Drawing.Point(13, 12);
this.StatisticsEnabledCheckBox.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.StatisticsEnabledCheckBox.Name = "StatisticsEnabledCheckBox";
this.StatisticsEnabledCheckBox.Size = new System.Drawing.Size(189, 31);
this.StatisticsEnabledCheckBox.Size = new System.Drawing.Size(163, 27);
this.StatisticsEnabledCheckBox.TabIndex = 17;
this.StatisticsEnabledCheckBox.Text = "Enable Statistics";
this.StatisticsEnabledCheckBox.UseVisualStyleBackColor = true;
@@ -324,7 +313,7 @@
0,
0,
0});
this.choiceKeptMinutesNum.Location = new System.Drawing.Point(176, 134);
this.choiceKeptMinutesNum.Location = new System.Drawing.Point(177, 265);
this.choiceKeptMinutesNum.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.choiceKeptMinutesNum.Maximum = new decimal(new int[] {
120,
@@ -337,7 +326,7 @@
0,
0});
this.choiceKeptMinutesNum.Name = "choiceKeptMinutesNum";
this.choiceKeptMinutesNum.Size = new System.Drawing.Size(100, 34);
this.choiceKeptMinutesNum.Size = new System.Drawing.Size(100, 29);
this.choiceKeptMinutesNum.TabIndex = 16;
this.choiceKeptMinutesNum.Value = new decimal(new int[] {
10,
@@ -349,10 +338,10 @@
//
this.byHourOfDayCheckBox.AutoSize = true;
this.byHourOfDayCheckBox.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this.bindingConfiguration, "ByHourOfDay", true));
this.byHourOfDayCheckBox.Location = new System.Drawing.Point(13, 95);
this.byHourOfDayCheckBox.Location = new System.Drawing.Point(13, 127);
this.byHourOfDayCheckBox.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.byHourOfDayCheckBox.Name = "byHourOfDayCheckBox";
this.byHourOfDayCheckBox.Size = new System.Drawing.Size(180, 31);
this.byHourOfDayCheckBox.Size = new System.Drawing.Size(150, 27);
this.byHourOfDayCheckBox.TabIndex = 15;
this.byHourOfDayCheckBox.Text = "By hour of day";
this.byHourOfDayCheckBox.UseVisualStyleBackColor = true;
@@ -360,7 +349,7 @@
// repeatTimesNum
//
this.repeatTimesNum.DataBindings.Add(new System.Windows.Forms.Binding("Value", this.bindingConfiguration, "RepeatTimesNum", true));
this.repeatTimesNum.Location = new System.Drawing.Point(72, 216);
this.repeatTimesNum.Location = new System.Drawing.Point(34, 84);
this.repeatTimesNum.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.repeatTimesNum.Maximum = new decimal(new int[] {
10,
@@ -368,7 +357,7 @@
0,
0});
this.repeatTimesNum.Name = "repeatTimesNum";
this.repeatTimesNum.Size = new System.Drawing.Size(99, 34);
this.repeatTimesNum.Size = new System.Drawing.Size(99, 29);
this.repeatTimesNum.TabIndex = 14;
this.repeatTimesNum.Value = new decimal(new int[] {
4,
@@ -380,9 +369,9 @@
//
this.label6.AutoSize = true;
this.label6.Font = new System.Drawing.Font("Microsoft YaHei", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label6.Location = new System.Drawing.Point(178, 218);
this.label6.Location = new System.Drawing.Point(139, 86);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(201, 27);
this.label6.Size = new System.Drawing.Size(172, 23);
this.label6.TabIndex = 13;
this.label6.Text = "packages everytime";
//
@@ -403,7 +392,7 @@
// splitContainer3.Panel2
//
this.splitContainer3.Panel2.Controls.Add(this.calculationContainer);
this.splitContainer3.Size = new System.Drawing.Size(688, 301);
this.splitContainer3.Size = new System.Drawing.Size(700, 301);
this.splitContainer3.SplitterDistance = 46;
this.splitContainer3.SplitterWidth = 10;
this.splitContainer3.TabIndex = 6;
@@ -414,7 +403,7 @@
this.label1.Location = new System.Drawing.Point(5, 12);
this.label1.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(262, 27);
this.label1.Size = new System.Drawing.Size(225, 23);
this.label1.TabIndex = 0;
this.label1.Text = "Design evaluation method";
//
@@ -425,23 +414,23 @@
this.calculationContainer.Location = new System.Drawing.Point(0, 0);
this.calculationContainer.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
this.calculationContainer.Name = "calculationContainer";
this.calculationContainer.Size = new System.Drawing.Size(688, 245);
this.calculationContainer.Size = new System.Drawing.Size(700, 245);
this.calculationContainer.TabIndex = 1;
//
// serverSelector
//
this.serverSelector.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.serverSelector.FormattingEnabled = true;
this.serverSelector.Location = new System.Drawing.Point(801, 67);
this.serverSelector.Location = new System.Drawing.Point(813, 61);
this.serverSelector.Name = "serverSelector";
this.serverSelector.Size = new System.Drawing.Size(260, 35);
this.serverSelector.Size = new System.Drawing.Size(260, 31);
this.serverSelector.TabIndex = 6;
this.serverSelector.SelectedIndexChanged += new System.EventHandler(this.serverSelector_SelectedIndexChanged);
//
// CancelButton
//
this.CancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.CancelButton.Location = new System.Drawing.Point(960, 220);
this.CancelButton.Location = new System.Drawing.Point(972, 214);
this.CancelButton.Name = "CancelButton";
this.CancelButton.Size = new System.Drawing.Size(101, 41);
this.CancelButton.TabIndex = 5;
@@ -452,7 +441,7 @@
// OKButton
//
this.OKButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OKButton.Location = new System.Drawing.Point(852, 220);
this.OKButton.Location = new System.Drawing.Point(864, 214);
this.OKButton.Name = "OKButton";
this.OKButton.Size = new System.Drawing.Size(101, 41);
this.OKButton.TabIndex = 4;
@@ -466,10 +455,10 @@
//
// StatisticsStrategyConfigurationForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 27F);
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 23F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSize = true;
this.ClientSize = new System.Drawing.Size(1077, 614);
this.ClientSize = new System.Drawing.Size(1089, 614);
this.Controls.Add(this.splitContainer1);
this.Font = new System.Drawing.Font("Microsoft YaHei", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10);
@@ -503,10 +492,9 @@

#endregion
private System.Windows.Forms.DataVisualization.Charting.Chart StatisticsChart;
private System.Windows.Forms.CheckBox byISPCheckBox;
private System.Windows.Forms.CheckBox PingCheckBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.GroupBox chartModeSelector;
private System.Windows.Forms.RadioButton allMode;
private System.Windows.Forms.RadioButton dayMode;


+ 6
- 1
shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs View File

@@ -15,7 +15,7 @@ namespace Shadowsocks.View
{
private readonly ShadowsocksController _controller;
private StatisticsStrategyConfiguration _configuration;
private DataTable _dataTable = new DataTable();
private readonly DataTable _dataTable = new DataTable();
private List<string> _servers;

public StatisticsStrategyConfigurationForm(ShadowsocksController controller)
@@ -135,5 +135,10 @@ namespace Shadowsocks.View
{
loadChartData();
}

private void PingCheckBox_CheckedChanged(object sender, EventArgs e)
{
repeatTimesNum.ReadOnly = !PingCheckBox.Checked;
}
}
}

Loading…
Cancel
Save