diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index d3a7ecce..97afc477 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -28,6 +28,7 @@ namespace Shadowsocks.Controller private const int DelayBeforeStart = 1000; public Statistics RawStatistics { get; private set; } public Statistics FilteredStatistics { get; private set; } + public static readonly DateTime UnknownDateTime = new DateTime(1970, 1, 1); private int Repeat => _config.RepeatTimesNum; private const int RetryInterval = 2*60*1000; //retry 2 minutes after failed private int Interval => (int) TimeSpan.FromMinutes(_config.DataCollectionMinutes).TotalMilliseconds; @@ -220,13 +221,8 @@ namespace Shadowsocks.Controller { var currentHour = DateTime.Now.Hour; filteredData = filteredData.Where(data => - { - DateTime dateTime; - DateTime.TryParseExact(data.Timestamp, DateTimePattern, null, - DateTimeStyles.None, out dateTime); - var result = dateTime.Hour.Equals(currentHour); - return result; - }); + data.Timestamp != UnknownDateTime && data.Timestamp.Hour.Equals(currentHour) + ); if (filteredData.LongCount() == 0) return; } var dataList = filteredData as List ?? filteredData.ToList(); @@ -252,7 +248,7 @@ namespace Shadowsocks.Controller let strings = l.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) let rawData = new RawStatisticsData { - Timestamp = strings[0], + Timestamp = ParseExactOrUnknown(strings[0]), ServerName = strings[1], ICMPStatus = strings[2], RoundtripTime = int.Parse(strings[3]), @@ -274,6 +270,12 @@ namespace Shadowsocks.Controller } } + private DateTime ParseExactOrUnknown(string str) + { + DateTime dateTime; + return !DateTime.TryParseExact(str, DateTimePattern, null, DateTimeStyles.None, out dateTime) ? UnknownDateTime : dateTime; + } + public class State { public DataList dataList = new DataList(); @@ -284,7 +286,7 @@ namespace Shadowsocks.Controller public class RawStatisticsData { - public string Timestamp; + public DateTime Timestamp; public string ServerName; public string ICMPStatus; public int RoundtripTime; diff --git a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs index cc31ddc3..44c8a872 100644 --- a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs +++ b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.Designer.cs @@ -29,13 +29,12 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); - System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend(); - 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(); + System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea3 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); + System.Windows.Forms.DataVisualization.Charting.Legend legend3 = new System.Windows.Forms.DataVisualization.Charting.Legend(); + System.Windows.Forms.DataVisualization.Charting.Series series5 = new System.Windows.Forms.DataVisualization.Charting.Series(); + System.Windows.Forms.DataVisualization.Charting.Series series6 = new System.Windows.Forms.DataVisualization.Charting.Series(); this.StatisticsChart = new System.Windows.Forms.DataVisualization.Charting.Chart(); this.byISPCheckBox = new System.Windows.Forms.CheckBox(); - this.bindingConfiguration = new System.Windows.Forms.BindingSource(this.components); this.label2 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); @@ -57,8 +56,9 @@ this.calculationContainer = new System.Windows.Forms.FlowLayoutPanel(); this.CancelButton = new System.Windows.Forms.Button(); this.OKButton = new System.Windows.Forms.Button(); + this.bindingConfiguration = new System.Windows.Forms.BindingSource(this.components); + this.serverSelector = new System.Windows.Forms.ComboBox(); ((System.ComponentModel.ISupportInitialize)(this.StatisticsChart)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.bindingConfiguration)).BeginInit(); this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); this.splitContainer1.Panel1.SuspendLayout(); @@ -75,39 +75,40 @@ this.splitContainer3.Panel1.SuspendLayout(); this.splitContainer3.Panel2.SuspendLayout(); this.splitContainer3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bindingConfiguration)).BeginInit(); this.SuspendLayout(); // // StatisticsChart // this.StatisticsChart.BackColor = System.Drawing.Color.Transparent; - chartArea1.AxisX.MajorGrid.Enabled = false; - chartArea1.AxisY.MajorGrid.Enabled = false; - chartArea1.AxisY2.MajorGrid.Enabled = false; - chartArea1.BackColor = System.Drawing.Color.Transparent; - chartArea1.Name = "ChartArea"; - this.StatisticsChart.ChartAreas.Add(chartArea1); + chartArea3.AxisX.MajorGrid.Enabled = false; + chartArea3.AxisY.MajorGrid.Enabled = false; + chartArea3.AxisY2.MajorGrid.Enabled = false; + chartArea3.BackColor = System.Drawing.Color.Transparent; + chartArea3.Name = "ChartArea"; + this.StatisticsChart.ChartAreas.Add(chartArea3); this.StatisticsChart.Dock = System.Windows.Forms.DockStyle.Fill; - legend1.BackColor = System.Drawing.Color.Transparent; - legend1.Name = "ChartLegend"; - this.StatisticsChart.Legends.Add(legend1); + legend3.BackColor = System.Drawing.Color.Transparent; + legend3.Name = "ChartLegend"; + this.StatisticsChart.Legends.Add(legend3); this.StatisticsChart.Location = new System.Drawing.Point(0, 0); this.StatisticsChart.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10); this.StatisticsChart.Name = "StatisticsChart"; this.StatisticsChart.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.Pastel; - series1.ChartArea = "ChartArea"; - series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bubble; - series1.Color = System.Drawing.Color.FromArgb(((int)(((byte)(221)))), ((int)(((byte)(88)))), ((int)(((byte)(0))))); - series1.Legend = "ChartLegend"; - series1.Name = "Package Loss"; - series1.YValuesPerPoint = 4; - series2.BorderWidth = 4; - series2.ChartArea = "ChartArea"; - series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line; - series2.Color = System.Drawing.Color.FromArgb(((int)(((byte)(155)))), ((int)(((byte)(77)))), ((int)(((byte)(150))))); - series2.Legend = "ChartLegend"; - series2.Name = "Ping"; - this.StatisticsChart.Series.Add(series1); - this.StatisticsChart.Series.Add(series2); + series5.ChartArea = "ChartArea"; + series5.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Bubble; + series5.Color = System.Drawing.Color.FromArgb(((int)(((byte)(221)))), ((int)(((byte)(88)))), ((int)(((byte)(0))))); + series5.Legend = "ChartLegend"; + series5.Name = "Package Loss"; + series5.YValuesPerPoint = 4; + series6.BorderWidth = 4; + series6.ChartArea = "ChartArea"; + series6.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line; + series6.Color = System.Drawing.Color.FromArgb(((int)(((byte)(155)))), ((int)(((byte)(77)))), ((int)(((byte)(150))))); + series6.Legend = "ChartLegend"; + series6.Name = "Ping"; + this.StatisticsChart.Series.Add(series5); + this.StatisticsChart.Series.Add(series6); this.StatisticsChart.Size = new System.Drawing.Size(1061, 314); this.StatisticsChart.TabIndex = 2; // @@ -123,10 +124,6 @@ this.byISPCheckBox.Text = "By ISP/geolocation"; this.byISPCheckBox.UseVisualStyleBackColor = true; // - // bindingConfiguration - // - this.bindingConfiguration.DataSource = typeof(Shadowsocks.Model.StatisticsStrategyConfiguration); - // // label2 // this.label2.AutoSize = true; @@ -162,7 +159,7 @@ this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.groupBox1.Controls.Add(this.radioButton2); this.groupBox1.Controls.Add(this.radioButton1); - this.groupBox1.Location = new System.Drawing.Point(808, 81); + this.groupBox1.Location = new System.Drawing.Point(808, 114); this.groupBox1.Margin = new System.Windows.Forms.Padding(5, 10, 5, 10); this.groupBox1.Name = "groupBox1"; this.groupBox1.Padding = new System.Windows.Forms.Padding(5, 10, 5, 10); @@ -210,6 +207,7 @@ // // splitContainer1.Panel2 // + this.splitContainer1.Panel2.Controls.Add(this.serverSelector); this.splitContainer1.Panel2.Controls.Add(this.CancelButton); this.splitContainer1.Panel2.Controls.Add(this.OKButton); this.splitContainer1.Panel2.Controls.Add(this.groupBox1); @@ -426,7 +424,7 @@ // 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(954, 240); + this.CancelButton.Location = new System.Drawing.Point(954, 234); this.CancelButton.Name = "CancelButton"; this.CancelButton.Size = new System.Drawing.Size(93, 43); this.CancelButton.TabIndex = 5; @@ -437,7 +435,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(855, 240); + this.OKButton.Location = new System.Drawing.Point(855, 234); this.OKButton.Name = "OKButton"; this.OKButton.Size = new System.Drawing.Size(93, 43); this.OKButton.TabIndex = 4; @@ -445,6 +443,19 @@ this.OKButton.UseVisualStyleBackColor = true; this.OKButton.Click += new System.EventHandler(this.OKButton_Click); // + // bindingConfiguration + // + this.bindingConfiguration.DataSource = typeof(Shadowsocks.Model.StatisticsStrategyConfiguration); + // + // serverSelector + // + this.serverSelector.FormattingEnabled = true; + this.serverSelector.Location = new System.Drawing.Point(808, 75); + this.serverSelector.Name = "serverSelector"; + this.serverSelector.Size = new System.Drawing.Size(239, 36); + this.serverSelector.TabIndex = 6; + this.serverSelector.SelectedIndexChanged += new System.EventHandler(this.serverSelector_SelectedIndexChanged); + // // StatisticsStrategyConfigurationForm // this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 28F); @@ -458,7 +469,6 @@ this.Name = "StatisticsStrategyConfigurationForm"; this.Text = "StatisticsStrategyConfigurationForm"; ((System.ComponentModel.ISupportInitialize)(this.StatisticsChart)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.bindingConfiguration)).EndInit(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.splitContainer1.Panel1.ResumeLayout(false); @@ -478,6 +488,7 @@ this.splitContainer3.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.splitContainer3)).EndInit(); this.splitContainer3.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.bindingConfiguration)).EndInit(); this.ResumeLayout(false); } @@ -507,5 +518,6 @@ private System.Windows.Forms.BindingSource bindingConfiguration; private new System.Windows.Forms.Button CancelButton; private System.Windows.Forms.Button OKButton; + private System.Windows.Forms.ComboBox serverSelector; } } \ No newline at end of file diff --git a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs index a4cb18a2..936cf719 100644 --- a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs +++ b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Windows.Forms; +using System.Windows.Forms.DataVisualization.Charting; using Shadowsocks.Controller; using Shadowsocks.Model; using SimpleJson; @@ -11,6 +14,8 @@ namespace Shadowsocks.View { private readonly ShadowsocksController _controller; private StatisticsStrategyConfiguration _configuration; + private DataTable _dataTable = new DataTable(); + private List _servers; public StatisticsStrategyConfigurationForm(ShadowsocksController controller) { @@ -24,6 +29,8 @@ namespace Shadowsocks.View private void LoadConfiguration() { + var configs = _controller.GetCurrentConfiguration().configs; + _servers = configs.Select(server => server.FriendlyName()).ToList(); _configuration = _controller.StatisticsConfiguration ?? new StatisticsStrategyConfiguration(); if (_configuration.Calculations == null) @@ -40,8 +47,23 @@ namespace Shadowsocks.View var calculation = new CalculationControl(kv.Key, kv.Value); calculationContainer.Controls.Add(calculation); } + + serverSelector.DataSource = _servers; + + _dataTable.Columns.Add("Timestamp", typeof (DateTime)); + _dataTable.Columns.Add("Package Loss", typeof (int)); + _dataTable.Columns.Add("Ping", typeof (int)); + + StatisticsChart.Series["Package Loss"].XValueMember = "Timestamp"; + StatisticsChart.Series["Package Loss"].YValueMembers = "PackageLoss"; + StatisticsChart.Series["Ping"].XValueMember = "Timestamp"; + StatisticsChart.Series["Ping"].YValueMembers = "Ping"; + StatisticsChart.DataSource = _dataTable; + loadChartData(serverSelector.SelectedText); + StatisticsChart.DataBind(); } + private void CancelButton_Click(object sender, EventArgs e) { Close(); @@ -57,5 +79,21 @@ namespace Shadowsocks.View _controller?.UpdateStatisticsConfiguration(StatisticsEnabledCheckBox.Checked); Close(); } + + private void loadChartData(string serverName) + { + _dataTable.Rows.Clear(); + List statistics; + if (!_controller.availabilityStatistics.FilteredStatistics.TryGetValue(serverName, out statistics)) return; + foreach (var data in statistics) + { + _dataTable.Rows.Add(data.Timestamp, (float) new Random().Next() % 50, new Random().Next() % 200); + } + } + + private void serverSelector_SelectedIndexChanged(object sender, EventArgs e) + { + loadChartData(_servers[serverSelector.SelectedIndex]); + } } } diff --git a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.resx b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.resx index 5f9d5c44..73aff71e 100644 --- a/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.resx +++ b/shadowsocks-csharp/View/StatisticsStrategyConfigurationForm.resx @@ -120,6 +120,9 @@ 1, 30 + + 1, 30 + 63