add Statistics(netspeed, traffic data amount)

pull/33/head
CGQAQ 2019-08-25 09:33:38 +08:00
parent f1e9737080
commit 56bb63a012
16 changed files with 583 additions and 57 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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="&gt;&gt;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="&gt;&gt;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>

View File

@ -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>

View File

@ -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);

View File

@ -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;
}

View File

@ -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="&gt;&gt;chkEnableStatistics.Name" xml:space="preserve">
<value>chkEnableStatistics</value>

View File

@ -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>

View File

@ -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

View File

@ -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();
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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">