mirror of https://github.com/2dust/v2rayN
add Statistics(netspeed, traffic data amount)
parent
f1e9737080
commit
56bb63a012
|
@ -31,7 +31,7 @@
|
|||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.lvServers = new System.Windows.Forms.ListView();
|
||||
this.lvServers = new v2rayN.Forms.MainForm.ListViewFlickerFree();
|
||||
this.cmsLv = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.menuAddVmessServer = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuAddShadowsocksServer = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -766,7 +766,7 @@
|
|||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.TextBox txtMsgBox;
|
||||
private System.Windows.Forms.ListView lvServers;
|
||||
private v2rayN.Forms.MainForm.ListViewFlickerFree lvServers;
|
||||
private System.Windows.Forms.NotifyIcon notifyMain;
|
||||
private System.Windows.Forms.ContextMenuStrip cmsMain;
|
||||
private System.Windows.Forms.ToolStripMenuItem menuExit;
|
||||
|
|
|
@ -20,6 +20,17 @@ namespace v2rayN.Forms
|
|||
|
||||
private StatisticsHandler statistics;
|
||||
|
||||
class ListViewFlickerFree: ListView
|
||||
{
|
||||
public ListViewFlickerFree()
|
||||
{
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer
|
||||
| ControlStyles.AllPaintingInWmPaint
|
||||
, true);
|
||||
UpdateStyles();
|
||||
}
|
||||
}
|
||||
|
||||
#region Window 事件
|
||||
|
||||
public MainForm()
|
||||
|
@ -42,15 +53,73 @@ namespace v2rayN.Forms
|
|||
v2rayHandler = new V2rayHandler();
|
||||
v2rayHandler.ProcessEvent += v2rayHandler_ProcessEvent;
|
||||
statistics = new StatisticsHandler(config,
|
||||
(ulong totalUp, ulong totalDown, ulong up, ulong down) =>
|
||||
(ulong totalUp, ulong totalDown, ulong up, ulong down, List<Mode.ServerStatistics> statistics) =>
|
||||
{
|
||||
toolSslBlank4.Text = down.ToString();
|
||||
double up_amount = 0.0, down_amount;
|
||||
string up_unit = "", down_unit;
|
||||
Utils.ToHumanReadable(up, out up_amount, out up_unit);
|
||||
Utils.ToHumanReadable(down, out down_amount, out down_unit);
|
||||
up_unit += "/s";
|
||||
down_unit += "/s";
|
||||
|
||||
up_amount /= config.statisticsFreshRate / 1000f;
|
||||
down_amount /= config.statisticsFreshRate / 1000f;
|
||||
|
||||
toolSslBlank4.Text = string.Format(
|
||||
"{4}: {0:f2} {1} | {5}: {2:f2} {3}",
|
||||
up_amount,
|
||||
up_unit,
|
||||
down_amount,
|
||||
down_unit,
|
||||
UIRes.I18N("uploadSpeed"),
|
||||
UIRes.I18N("downloadSpeed")
|
||||
);
|
||||
|
||||
|
||||
List<string[]> datas = new List<string[]>();
|
||||
for (int i= 0; i < config.vmess.Count; i++)
|
||||
{
|
||||
string totalUp_ = string.Empty,
|
||||
totalDown_ = string.Empty,
|
||||
todayUp_ = string.Empty,
|
||||
todayDown_ = string.Empty;
|
||||
var index = statistics.FindIndex(item_ => (config.vmess[i].address == item_.address && config.vmess[i].port == item_.port));
|
||||
if (index != -1)
|
||||
{
|
||||
Func<ulong, string> human_fy = (amount) =>
|
||||
{
|
||||
double result;
|
||||
string unit;
|
||||
Utils.ToHumanReadable(amount, out result, out unit);
|
||||
return $"{string.Format("{0:f2}", result)}{unit}";
|
||||
};
|
||||
totalUp_ = human_fy(statistics[index].totalUp);
|
||||
totalDown_ = human_fy(statistics[index].totalDown);
|
||||
todayUp_ = human_fy(statistics[index].todayUp);
|
||||
todayDown_ = human_fy(statistics[index].todayDown);
|
||||
}
|
||||
|
||||
datas.Add(new string[] { totalUp_, totalDown_, todayUp_, todayDown_ });
|
||||
}
|
||||
|
||||
lvServers.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
lvServers.SuspendLayout();
|
||||
for (int i =0; i< datas.Count; i++)
|
||||
{
|
||||
lvServers.Items[i].SubItems[7].Text = datas[i][0];
|
||||
lvServers.Items[i].SubItems[8].Text = datas[i][1];
|
||||
lvServers.Items[i].SubItems[9].Text = datas[i][2];
|
||||
lvServers.Items[i].SubItems[10].Text = datas[i][3];
|
||||
}
|
||||
lvServers.ResumeLayout();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void MainForm_VisibleChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (statistics == null) return;
|
||||
if (statistics == null || !statistics.Enable) return;
|
||||
if((sender as Form).Visible)
|
||||
{
|
||||
statistics.UpdateUI = true;
|
||||
|
@ -78,9 +147,15 @@ namespace v2rayN.Forms
|
|||
{
|
||||
e.Cancel = true;
|
||||
|
||||
statistics.saveToFile();
|
||||
|
||||
HideForm();
|
||||
return;
|
||||
}
|
||||
if(e.CloseReason == CloseReason.ApplicationExitCall)
|
||||
{
|
||||
statistics.saveToFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainForm_Resize(object sender, EventArgs e)
|
||||
|
@ -109,7 +184,8 @@ namespace v2rayN.Forms
|
|||
Utils.SaveLog("Windows shutdown UnsetProxy");
|
||||
//CloseV2ray();
|
||||
ConfigHandler.ToJsonFile(config);
|
||||
statistics.saveToFile();
|
||||
if(statistics!=null && statistics.Enable)
|
||||
statistics.saveToFile();
|
||||
ProxySetting.UnsetProxy();
|
||||
m.Result = (IntPtr)1;
|
||||
break;
|
||||
|
@ -152,6 +228,16 @@ namespace v2rayN.Forms
|
|||
lvServers.Columns.Add(UIRes.I18N("LvPort"), 50, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvEncryptionMethod"), 90, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTransportProtocol"), 70, HorizontalAlignment.Left);
|
||||
|
||||
if(statistics != null && statistics.Enable)
|
||||
{
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTotalUploadDataAmount"), 70, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTotalDownloadDataAmount"), 70, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTodayUploadDataAmount"), 70, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTodayDownloadDataAmount"), 70, HorizontalAlignment.Left);
|
||||
this.Width = 1250;
|
||||
}
|
||||
|
||||
lvServers.Columns.Add(UIRes.I18N("LvSubscription"), 50, HorizontalAlignment.Left);
|
||||
lvServers.Columns.Add(UIRes.I18N("LvTestResults"), 100, HorizontalAlignment.Left);
|
||||
|
||||
|
@ -167,14 +253,38 @@ namespace v2rayN.Forms
|
|||
for (int k = 0; k < config.vmess.Count; k++)
|
||||
{
|
||||
string def = string.Empty;
|
||||
string totalUp = string.Empty,
|
||||
totalDown = string.Empty,
|
||||
todayUp = string.Empty,
|
||||
todayDown = string.Empty;
|
||||
if (config.index.Equals(k))
|
||||
{
|
||||
def = "√";
|
||||
}
|
||||
|
||||
VmessItem item = config.vmess[k];
|
||||
ListViewItem lvItem = new ListViewItem(new string[]
|
||||
|
||||
ListViewItem lvItem = null;
|
||||
if (statistics != null && statistics.Enable)
|
||||
{
|
||||
var index = statistics.Statistic.FindIndex(item_ => item_.address == item.address);
|
||||
if (index != -1)
|
||||
{
|
||||
Func<ulong, string> human_fy = (amount) =>
|
||||
{
|
||||
double result;
|
||||
string unit;
|
||||
Utils.ToHumanReadable(amount, out result, out unit);
|
||||
return $"{string.Format("{0:f2}", result)}{unit}";
|
||||
};
|
||||
totalUp = human_fy(statistics.Statistic[index].totalUp);
|
||||
totalDown = human_fy(statistics.Statistic[index].totalDown);
|
||||
todayUp = human_fy(statistics.Statistic[index].todayUp);
|
||||
todayDown = human_fy(statistics.Statistic[index].todayDown);
|
||||
}
|
||||
|
||||
lvItem = new ListViewItem(new string[]
|
||||
{
|
||||
def,
|
||||
((EConfigType)item.configType).ToString(),
|
||||
item.remarks,
|
||||
|
@ -184,10 +294,37 @@ namespace v2rayN.Forms
|
|||
//item.alterId.ToString(),
|
||||
item.security,
|
||||
item.network,
|
||||
totalUp,
|
||||
totalDown,
|
||||
todayUp,
|
||||
todayDown,
|
||||
item.getSubRemarks(config),
|
||||
item.testResult
|
||||
});
|
||||
lvServers.Items.Add(lvItem);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
lvItem = new ListViewItem(new string[]
|
||||
{
|
||||
def,
|
||||
((EConfigType)item.configType).ToString(),
|
||||
item.remarks,
|
||||
item.address,
|
||||
item.port.ToString(),
|
||||
//item.id,
|
||||
//item.alterId.ToString(),
|
||||
item.security,
|
||||
item.network,
|
||||
//totalUp,
|
||||
//totalDown,
|
||||
//todayUp,
|
||||
//todayDown,
|
||||
item.getSubRemarks(config),
|
||||
item.testResult
|
||||
});
|
||||
}
|
||||
|
||||
if(lvItem!=null) lvServers.Items.Add(lvItem);
|
||||
}
|
||||
|
||||
//if (lvServers.Items.Count > 0)
|
||||
|
|
|
@ -305,7 +305,7 @@
|
|||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="lvServers.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>726, 331</value>
|
||||
<value>638, 331</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="lvServers.TabIndex" type="System.Int32, mscorlib">
|
||||
|
@ -315,7 +315,7 @@
|
|||
<value>lvServers</value>
|
||||
</data>
|
||||
<data name=">>lvServers.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>v2rayN.Forms.MainForm+ListViewFlickerFree, v2rayN, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</value>
|
||||
</data>
|
||||
<data name=">>lvServers.Parent" xml:space="preserve">
|
||||
<value>splitContainer1.Panel1</value>
|
||||
|
@ -375,10 +375,10 @@
|
|||
<value>100</value>
|
||||
</data>
|
||||
<data name="splitContainer1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>986, 331</value>
|
||||
<value>898, 331</value>
|
||||
</data>
|
||||
<data name="splitContainer1.SplitterDistance" type="System.Int32, mscorlib">
|
||||
<value>726</value>
|
||||
<value>638</value>
|
||||
</data>
|
||||
<data name="splitContainer1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
|
@ -501,7 +501,7 @@
|
|||
<value>0, 66</value>
|
||||
</data>
|
||||
<data name="groupBox1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>992, 351</value>
|
||||
<value>904, 351</value>
|
||||
</data>
|
||||
<data name="groupBox1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
|
@ -537,7 +537,7 @@
|
|||
<value>Vertical</value>
|
||||
</data>
|
||||
<data name="txtMsgBox.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>986, 134</value>
|
||||
<value>898, 134</value>
|
||||
</data>
|
||||
<data name="txtMsgBox.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
|
@ -567,7 +567,7 @@
|
|||
<value>0, 17</value>
|
||||
</data>
|
||||
<data name="toolSslBlank1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>257, 17</value>
|
||||
<value>227, 17</value>
|
||||
</data>
|
||||
<data name="toolSslHttpPortLab.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>38, 17</value>
|
||||
|
@ -579,7 +579,7 @@
|
|||
<value>0, 17</value>
|
||||
</data>
|
||||
<data name="toolSslBlank2.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>257, 17</value>
|
||||
<value>227, 17</value>
|
||||
</data>
|
||||
<data name="toolSslPacPortLab.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>31, 17</value>
|
||||
|
@ -591,7 +591,7 @@
|
|||
<value>0, 17</value>
|
||||
</data>
|
||||
<data name="toolSslBlank3.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>257, 17</value>
|
||||
<value>227, 17</value>
|
||||
</data>
|
||||
<data name="toolSslServerSpeed.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>45, 17</value>
|
||||
|
@ -609,7 +609,7 @@
|
|||
<value>3, 151</value>
|
||||
</data>
|
||||
<data name="ssMain.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>986, 22</value>
|
||||
<value>898, 22</value>
|
||||
</data>
|
||||
<data name="ssMain.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
|
@ -636,7 +636,7 @@
|
|||
<value>0, 417</value>
|
||||
</data>
|
||||
<data name="groupBox2.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>992, 176</value>
|
||||
<value>904, 176</value>
|
||||
</data>
|
||||
<data name="groupBox2.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
|
@ -663,7 +663,7 @@
|
|||
<value>0, 56</value>
|
||||
</data>
|
||||
<data name="panel1.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>992, 10</value>
|
||||
<value>904, 10</value>
|
||||
</data>
|
||||
<data name="panel1.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
|
@ -867,7 +867,7 @@
|
|||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="tsMain.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>992, 56</value>
|
||||
<value>904, 56</value>
|
||||
</data>
|
||||
<data name="tsMain.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>6</value>
|
||||
|
@ -894,7 +894,7 @@
|
|||
<value>6, 12</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>992, 593</value>
|
||||
<value>904, 593</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
|
|
|
@ -450,4 +450,7 @@
|
|||
<data name="tsbClose.Text" xml:space="preserve">
|
||||
<value> 关闭 </value>
|
||||
</data>
|
||||
<data name="toolSslServerSpeed.Text" xml:space="preserve">
|
||||
<value>代理速度</value>
|
||||
</data>
|
||||
</root>
|
|
@ -83,7 +83,9 @@
|
|||
this.txtKcpmtu = new System.Windows.Forms.TextBox();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.tabPage7 = new System.Windows.Forms.TabPage();
|
||||
this.cbFreshrate = new System.Windows.Forms.ComboBox();
|
||||
this.tbCacheDays = new System.Windows.Forms.TextBox();
|
||||
this.lbFreshrate = new System.Windows.Forms.Label();
|
||||
this.lbCacheDays = new System.Windows.Forms.Label();
|
||||
this.chkEnableStatistics = new System.Windows.Forms.CheckBox();
|
||||
this.chkAllowLANConn = new System.Windows.Forms.CheckBox();
|
||||
|
@ -93,8 +95,6 @@
|
|||
this.panel2 = new System.Windows.Forms.Panel();
|
||||
this.btnOK = new System.Windows.Forms.Button();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.cbFreshrate = new System.Windows.Forms.ComboBox();
|
||||
this.lbFreshrate = new System.Windows.Forms.Label();
|
||||
this.configBindingSource = new System.Windows.Forms.BindingSource(this.components);
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
|
@ -494,11 +494,22 @@
|
|||
this.tabPage7.Name = "tabPage7";
|
||||
this.tabPage7.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cbFreshrate
|
||||
//
|
||||
this.cbFreshrate.FormattingEnabled = true;
|
||||
resources.ApplyResources(this.cbFreshrate, "cbFreshrate");
|
||||
this.cbFreshrate.Name = "cbFreshrate";
|
||||
//
|
||||
// tbCacheDays
|
||||
//
|
||||
resources.ApplyResources(this.tbCacheDays, "tbCacheDays");
|
||||
this.tbCacheDays.Name = "tbCacheDays";
|
||||
//
|
||||
// lbFreshrate
|
||||
//
|
||||
resources.ApplyResources(this.lbFreshrate, "lbFreshrate");
|
||||
this.lbFreshrate.Name = "lbFreshrate";
|
||||
//
|
||||
// lbCacheDays
|
||||
//
|
||||
resources.ApplyResources(this.lbCacheDays, "lbCacheDays");
|
||||
|
@ -551,17 +562,6 @@
|
|||
resources.ApplyResources(this.panel1, "panel1");
|
||||
this.panel1.Name = "panel1";
|
||||
//
|
||||
// cbFreshrate
|
||||
//
|
||||
this.cbFreshrate.FormattingEnabled = true;
|
||||
resources.ApplyResources(this.cbFreshrate, "cbFreshrate");
|
||||
this.cbFreshrate.Name = "cbFreshrate";
|
||||
//
|
||||
// lbFreshrate
|
||||
//
|
||||
resources.ApplyResources(this.lbFreshrate, "lbFreshrate");
|
||||
this.lbFreshrate.Name = "lbFreshrate";
|
||||
//
|
||||
// configBindingSource
|
||||
//
|
||||
this.configBindingSource.DataSource = typeof(v2rayN.Mode.Config);
|
||||
|
|
|
@ -114,16 +114,31 @@ namespace v2rayN.Forms
|
|||
tbCacheDays.Text = config.CacheDays.ToString();
|
||||
|
||||
|
||||
|
||||
cbFreshrate.DataSource = new ComboItem[]
|
||||
var cbSource = new ComboItem[]
|
||||
{
|
||||
new ComboItem{ID = (int)Global.StatisticsFreshRate.quick, Text = UIRes.I18N("QuickFresh")},
|
||||
new ComboItem{ID = (int)Global.StatisticsFreshRate.medium, Text = UIRes.I18N("MediumFresh")},
|
||||
new ComboItem{ID = (int)Global.StatisticsFreshRate.slow, Text = UIRes.I18N("SlowFresh")},
|
||||
};
|
||||
cbFreshrate.DataSource = cbSource;
|
||||
|
||||
cbFreshrate.DisplayMember = "Text";
|
||||
cbFreshrate.ValueMember = "ID";
|
||||
|
||||
switch(config.statisticsFreshRate)
|
||||
{
|
||||
case (int)Global.StatisticsFreshRate.quick:
|
||||
cbFreshrate.SelectedItem = cbSource[0];
|
||||
break;
|
||||
case (int)Global.StatisticsFreshRate.medium:
|
||||
cbFreshrate.SelectedItem = cbSource[1];
|
||||
break;
|
||||
case (int)Global.StatisticsFreshRate.slow:
|
||||
cbFreshrate.SelectedItem = cbSource[2];
|
||||
break;
|
||||
}
|
||||
|
||||
cbFreshrate.Enabled = enableStatistics;
|
||||
}
|
||||
|
||||
private void btnOK_Click(object sender, EventArgs e)
|
||||
|
@ -319,6 +334,8 @@ namespace v2rayN.Forms
|
|||
days = 7;
|
||||
config.CacheDays = days;
|
||||
|
||||
config.statisticsFreshRate = (int)cbFreshrate.SelectedValue;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1486,7 +1486,7 @@
|
|||
<value>161, 82</value>
|
||||
</data>
|
||||
<data name="cbFreshrate.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>121, 20</value>
|
||||
<value>58, 20</value>
|
||||
</data>
|
||||
<data name="cbFreshrate.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>32</value>
|
||||
|
@ -1591,13 +1591,13 @@
|
|||
<value>15, 60</value>
|
||||
</data>
|
||||
<data name="chkEnableStatistics.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>390, 16</value>
|
||||
<value>558, 16</value>
|
||||
</data>
|
||||
<data name="chkEnableStatistics.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>29</value>
|
||||
</data>
|
||||
<data name="chkEnableStatistics.Text" xml:space="preserve">
|
||||
<value>Enable Statistics(Realtime net speed and traffic data amount)</value>
|
||||
<value>Enable Statistics(Realtime net speed and traffic data amount. Need restart v2rayN client)</value>
|
||||
</data>
|
||||
<data name=">>chkEnableStatistics.Name" xml:space="preserve">
|
||||
<value>chkEnableStatistics</value>
|
||||
|
|
|
@ -288,11 +288,8 @@
|
|||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>参数设置</value>
|
||||
</data>
|
||||
<data name="chkEnableHotkey.Text" xml:space="preserve">
|
||||
<value>启用快捷键(Ctrl+P ping 选中服务器/ Ctrl+T 测速选中服务器)</value>
|
||||
</data>
|
||||
<data name="chkEnableStatistics.Text" xml:space="preserve">
|
||||
<value>启用统计(实时网速显示和使用流量显示)</value>
|
||||
<value>启用统计(实时网速显示和使用流量显示,需要重启v2rayN客户端)</value>
|
||||
</data>
|
||||
<data name="lbCacheDays.Text" xml:space="preserve">
|
||||
<value>缓存天数(0-30, 0关闭缓存单独每天的数据使用情况)</value>
|
||||
|
|
|
@ -149,10 +149,12 @@ namespace v2rayN
|
|||
public const uint InboundAPIPort = 10085;
|
||||
public enum StatisticsFreshRate
|
||||
{
|
||||
quick = 1000,
|
||||
medium = 2000,
|
||||
slow = 3000
|
||||
quick = 500,
|
||||
medium = 1000,
|
||||
slow = 2000
|
||||
}
|
||||
public const string StatisticLogDirectory = "Statistics";
|
||||
public const string StatisticLogOverall = "overall.txt";
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace v2rayN.Handler
|
|||
|
||||
private Thread workThread_;
|
||||
|
||||
Action<ulong, ulong, ulong, ulong> updateFunc_;
|
||||
Action<ulong, ulong, ulong, ulong, List<Mode.ServerStatistics>> updateFunc_;
|
||||
|
||||
private bool enabled_;
|
||||
public bool Enable
|
||||
|
@ -35,20 +35,35 @@ namespace v2rayN.Handler
|
|||
|
||||
private StringBuilder outputBuilder_;
|
||||
|
||||
public UInt64 TotalUp { get; private set; }
|
||||
public ulong TotalUp { get; private set; }
|
||||
|
||||
public UInt64 TotalDown { get; private set; }
|
||||
public ulong TotalDown { get; private set; }
|
||||
|
||||
public UInt64 Up { get; private set; }
|
||||
public List<Mode.ServerStatistics> Statistic{ get; set; }
|
||||
|
||||
public UInt64 Down { get; private set; }
|
||||
public ulong Up { get; private set; }
|
||||
|
||||
public StatisticsHandler(Config config, Action<ulong, ulong, ulong, ulong> update)
|
||||
public ulong Down { get; private set; }
|
||||
|
||||
private string logPath_;
|
||||
|
||||
public StatisticsHandler(Config config, Action<ulong, ulong, ulong, ulong, List<Mode.ServerStatistics>> update)
|
||||
{
|
||||
config_ = config;
|
||||
enabled_ = config.enableStatistics;
|
||||
UpdateUI = false;
|
||||
updateFunc_ = update;
|
||||
logPath_ = Utils.GetPath($"{Global.StatisticLogDirectory}\\");
|
||||
Statistic = new List<Mode.ServerStatistics>();
|
||||
|
||||
DeleteExpiredLog();
|
||||
foreach (var server in config.vmess)
|
||||
{
|
||||
var statistic = new ServerStatistics(server.remarks, server.address, server.port, 0, 0, 0, 0);
|
||||
Statistic.Add(statistic);
|
||||
}
|
||||
|
||||
loadFromFile();
|
||||
|
||||
outputBuilder_ = new StringBuilder();
|
||||
|
||||
|
@ -83,6 +98,9 @@ namespace v2rayN.Handler
|
|||
{
|
||||
if (enabled_)
|
||||
{
|
||||
var addr = config_.address();
|
||||
var port = config_.port();
|
||||
var cur = Statistic.FindIndex(item => item.address == addr && item.port == port);
|
||||
connector_.Start();
|
||||
string output = connector_.StandardOutput.ReadToEnd();
|
||||
UInt64 up = 0;
|
||||
|
@ -97,14 +115,21 @@ namespace v2rayN.Handler
|
|||
TotalUp += up;
|
||||
TotalDown += down;
|
||||
|
||||
if(cur != -1)
|
||||
{
|
||||
Statistic[cur].todayUp += up;
|
||||
Statistic[cur].todayDown += down;
|
||||
Statistic[cur].totalUp += up;
|
||||
Statistic[cur].totalDown += down;
|
||||
}
|
||||
|
||||
if (UpdateUI)
|
||||
updateFunc_(TotalUp, TotalDown, Up, Down);
|
||||
updateFunc_(TotalUp, TotalDown, Up, Down, Statistic);
|
||||
Thread.Sleep(config_.statisticsFreshRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{ }
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void parseOutput(string source, out UInt64 up, out UInt64 down)
|
||||
|
@ -148,12 +173,186 @@ namespace v2rayN.Handler
|
|||
|
||||
public void saveToFile()
|
||||
{
|
||||
if(!Directory.Exists(logPath_))
|
||||
{
|
||||
Directory.CreateDirectory(logPath_);
|
||||
}
|
||||
|
||||
// 总流量统计文件
|
||||
var overallPath = Path.Combine(logPath_, Global.StatisticLogOverall);
|
||||
if (!File.Exists(overallPath))
|
||||
{
|
||||
File.Create(overallPath);
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var overallWriter = new StreamWriter(overallPath))
|
||||
{
|
||||
double up_amount, down_amount;
|
||||
string up_unit, down_unit;
|
||||
|
||||
Utils.ToHumanReadable(TotalUp, out up_amount, out up_unit);
|
||||
Utils.ToHumanReadable(TotalDown, out down_amount, out down_unit);
|
||||
|
||||
overallWriter.WriteLine($"LastUpdate {DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}");
|
||||
overallWriter.WriteLine($"UP {string.Format("{0:f2}", up_amount)}{up_unit} {TotalUp}");
|
||||
overallWriter.WriteLine($"DOWN {string.Format("{0:f2}", down_amount)}{down_unit} {TotalDown}");
|
||||
foreach(var s in Statistic)
|
||||
{
|
||||
overallWriter.WriteLine($"* {s.name} {s.address} {s.port} {s.totalUp} {s.totalDown}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// 当天流量记录文件
|
||||
var dailyPath = Path.Combine(logPath_, $"{DateTime.Now.ToLongDateString()}.txt");
|
||||
if (!File.Exists(dailyPath))
|
||||
{
|
||||
File.Create(dailyPath);
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var dailyWriter = new StreamWriter(dailyPath))
|
||||
{
|
||||
dailyWriter.WriteLine($"LastUpdate {DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}");
|
||||
foreach (var s in Statistic)
|
||||
{
|
||||
dailyWriter.WriteLine($"* {s.name} {s.address} {s.port} {s.todayUp} {s.todayDown}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void loadFromFile()
|
||||
{
|
||||
if (!Directory.Exists(logPath_)) return;
|
||||
|
||||
// 总流量统计文件
|
||||
///
|
||||
/// 文件结构
|
||||
/// LastUpdate [date] [time]
|
||||
/// UP [readable string] [amount]
|
||||
/// DOWN [readable string] [amount]
|
||||
/// 每行每个数据空格分隔
|
||||
///
|
||||
var overallPath = Path.Combine(logPath_, Global.StatisticLogOverall);
|
||||
if (File.Exists(overallPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var overallReader = new StreamReader(overallPath))
|
||||
{
|
||||
while (!overallReader.EndOfStream)
|
||||
{
|
||||
var line = overallReader.ReadLine();
|
||||
if (line.StartsWith("LastUpdate"))
|
||||
{
|
||||
|
||||
}
|
||||
else if (line.StartsWith("UP"))
|
||||
{
|
||||
var datas = line.Split(' ');
|
||||
if (datas.Length < 3) return;
|
||||
TotalUp = ulong.Parse(datas[2]);
|
||||
}
|
||||
else if (line.StartsWith("DOWN"))
|
||||
{
|
||||
var datas = line.Split(' ');
|
||||
if (datas.Length < 3) return;
|
||||
TotalDown = ulong.Parse(datas[2]);
|
||||
}
|
||||
else if (line.StartsWith("*"))
|
||||
{
|
||||
var datas = line.Split(' ');
|
||||
if (datas.Length < 6) return;
|
||||
var name = datas[1];
|
||||
var address = datas[2];
|
||||
var port = int.Parse(datas[3]);
|
||||
var totalUp = ulong.Parse(datas[4]);
|
||||
var totalDown = ulong.Parse(datas[5]);
|
||||
|
||||
var index = Statistic.FindIndex(item => item.address == address && item.port == port);
|
||||
if (index != -1)
|
||||
{
|
||||
Statistic[index].totalUp = totalUp;
|
||||
Statistic[index].totalDown = totalDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = new Mode.ServerStatistics(name, address, port, totalUp, totalDown, 0, 0);
|
||||
Statistic.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// 当天流量记录文件
|
||||
var dailyPath = Path.Combine(logPath_, $"{DateTime.Now.ToLongDateString()}.txt");
|
||||
if (File.Exists(dailyPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var dailyReader = new StreamReader(dailyPath))
|
||||
{
|
||||
while (!dailyReader.EndOfStream)
|
||||
{
|
||||
var line = dailyReader.ReadLine();
|
||||
if (line.StartsWith("LastUpdate"))
|
||||
{
|
||||
|
||||
}
|
||||
else if (line.StartsWith("*"))
|
||||
{
|
||||
var datas = line.Split(' ');
|
||||
if (datas.Length < 6) return;
|
||||
var name = datas[1];
|
||||
var address = datas[2];
|
||||
var port = int.Parse(datas[3]);
|
||||
var todayUp = ulong.Parse(datas[4]);
|
||||
var todayDown = ulong.Parse(datas[5]);
|
||||
|
||||
var index = Statistic.FindIndex(item => item.address == address && item.port == port);
|
||||
if (index != -1)
|
||||
{
|
||||
Statistic[index].todayUp = todayUp;
|
||||
Statistic[index].todayDown = todayDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
var s = new Mode.ServerStatistics(name, address, port, 0, 0, todayUp, todayDown);
|
||||
Statistic.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void DeleteExpiredLog()
|
||||
{
|
||||
if (!Directory.Exists(logPath_)) return;
|
||||
var dirInfo = new DirectoryInfo(logPath_);
|
||||
var files = dirInfo.GetFiles();
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.Name == "overall.txt") continue;
|
||||
var name = file.Name.Split('.')[0];
|
||||
var ft = DateTime.Parse(name);
|
||||
var ct = DateTime.Now;
|
||||
var dur = ct - ft;
|
||||
if(dur.Days > config_.CacheDays)
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace v2rayN.Mode
|
||||
{
|
||||
class ServerStatistics
|
||||
{
|
||||
public string name;
|
||||
public string address;
|
||||
public int port;
|
||||
public ulong totalUp;
|
||||
public ulong totalDown;
|
||||
public ulong todayUp;
|
||||
public ulong todayDown;
|
||||
|
||||
public ServerStatistics() { }
|
||||
public ServerStatistics(string name, string addr, int port, ulong totalUp, ulong totalDown, ulong todayUp, ulong todayDown)
|
||||
{
|
||||
this.name = name;
|
||||
this.address = addr;
|
||||
this.port = port;
|
||||
this.totalUp = totalUp;
|
||||
this.totalDown = totalDown;
|
||||
this.todayUp = todayUp;
|
||||
this.todayDown = todayDown;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -105,6 +105,15 @@ namespace v2rayN.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to DOWN.
|
||||
/// </summary>
|
||||
internal static string downloadSpeed {
|
||||
get {
|
||||
return ResourceManager.GetString("downloadSpeed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Whether to download? {0}.
|
||||
/// </summary>
|
||||
|
@ -321,6 +330,42 @@ namespace v2rayN.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Today download traffic.
|
||||
/// </summary>
|
||||
internal static string LvTodayDownloadDataAmount {
|
||||
get {
|
||||
return ResourceManager.GetString("LvTodayDownloadDataAmount", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Today upload traffic.
|
||||
/// </summary>
|
||||
internal static string LvTodayUploadDataAmount {
|
||||
get {
|
||||
return ResourceManager.GetString("LvTodayUploadDataAmount", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Total download traffic.
|
||||
/// </summary>
|
||||
internal static string LvTotalDownloadDataAmount {
|
||||
get {
|
||||
return ResourceManager.GetString("LvTotalDownloadDataAmount", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Total upload traffic.
|
||||
/// </summary>
|
||||
internal static string LvTotalUploadDataAmount {
|
||||
get {
|
||||
return ResourceManager.GetString("LvTotalUploadDataAmount", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Transport.
|
||||
/// </summary>
|
||||
|
@ -690,5 +735,14 @@ namespace v2rayN.Resx {
|
|||
return ResourceManager.GetString("SuccessfullyImportedServerViaScan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to UP.
|
||||
/// </summary>
|
||||
internal static string uploadSpeed {
|
||||
get {
|
||||
return ResourceManager.GetString("uploadSpeed", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,4 +328,22 @@
|
|||
<data name="SlowFresh" xml:space="preserve">
|
||||
<value>SlowFresh</value>
|
||||
</data>
|
||||
<data name="downloadSpeed" xml:space="preserve">
|
||||
<value>DOWN</value>
|
||||
</data>
|
||||
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
|
||||
<value>Today download traffic</value>
|
||||
</data>
|
||||
<data name="LvTodayUploadDataAmount" xml:space="preserve">
|
||||
<value>Today upload traffic</value>
|
||||
</data>
|
||||
<data name="LvTotalDownloadDataAmount" xml:space="preserve">
|
||||
<value>Total download traffic</value>
|
||||
</data>
|
||||
<data name="LvTotalUploadDataAmount" xml:space="preserve">
|
||||
<value>Total upload traffic</value>
|
||||
</data>
|
||||
<data name="uploadSpeed" xml:space="preserve">
|
||||
<value>UP</value>
|
||||
</data>
|
||||
</root>
|
|
@ -328,4 +328,22 @@
|
|||
<data name="SlowFresh" xml:space="preserve">
|
||||
<value>慢</value>
|
||||
</data>
|
||||
<data name="downloadSpeed" xml:space="preserve">
|
||||
<value>下载</value>
|
||||
</data>
|
||||
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
|
||||
<value>今日下载</value>
|
||||
</data>
|
||||
<data name="LvTodayUploadDataAmount" xml:space="preserve">
|
||||
<value>今日上传</value>
|
||||
</data>
|
||||
<data name="LvTotalDownloadDataAmount" xml:space="preserve">
|
||||
<value>总下载</value>
|
||||
</data>
|
||||
<data name="LvTotalUploadDataAmount" xml:space="preserve">
|
||||
<value>总上传</value>
|
||||
</data>
|
||||
<data name="uploadSpeed" xml:space="preserve">
|
||||
<value>上传</value>
|
||||
</data>
|
||||
</root>
|
|
@ -262,6 +262,55 @@ namespace v2rayN
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// byte 转成 有两位小数点的 方便阅读的数据
|
||||
/// 比如 2.50 MB
|
||||
/// </summary>
|
||||
/// <param name="amount">bytes</param>
|
||||
/// <param name="result">转换之后的数据</param>
|
||||
/// <param name="unit">单位</param>
|
||||
public static void ToHumanReadable(ulong amount, out double result, out string unit)
|
||||
{
|
||||
var factor = 1024u;
|
||||
var KBs = amount / factor;
|
||||
if(amount / factor > 0)
|
||||
{
|
||||
// multi KB
|
||||
var MBs = KBs / factor;
|
||||
if(MBs > 0)
|
||||
{
|
||||
// multi MB
|
||||
var GBs = MBs / factor;
|
||||
if(GBs > 0)
|
||||
{
|
||||
// multi GB
|
||||
var TBs = GBs / factor;
|
||||
if(TBs > 0)
|
||||
{
|
||||
// 你是魔鬼吗? 用这么多流量
|
||||
result = TBs + GBs % factor / (factor + 0.0);
|
||||
unit = "TB";
|
||||
return;
|
||||
}
|
||||
result = GBs + MBs % factor / (factor + 0.0);
|
||||
unit = "GB";
|
||||
return;
|
||||
}
|
||||
result = MBs + KBs % factor / (factor + 0.0);
|
||||
unit = "MB";
|
||||
return;
|
||||
}
|
||||
result = KBs + amount % factor / (factor + 0.0);
|
||||
unit = "KB";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = amount;
|
||||
unit = "Byte";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@
|
|||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Mode\EMove.cs" />
|
||||
<Compile Include="Mode\ServerStatistics.cs" />
|
||||
<Compile Include="Mode\SysproxyConfig.cs" />
|
||||
<Compile Include="Mode\EConfigType.cs" />
|
||||
<Compile Include="Resx\ResUI.zh-Hans.Designer.cs">
|
||||
|
|
Loading…
Reference in New Issue