diff --git a/v2rayN/v2rayN/Forms/MainForm.Designer.cs b/v2rayN/v2rayN/Forms/MainForm.Designer.cs index a48ab929..4f4fe2e9 100644 --- a/v2rayN/v2rayN/Forms/MainForm.Designer.cs +++ b/v2rayN/v2rayN/Forms/MainForm.Designer.cs @@ -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; diff --git a/v2rayN/v2rayN/Forms/MainForm.cs b/v2rayN/v2rayN/Forms/MainForm.cs index a4a7d2e5..356178e3 100644 --- a/v2rayN/v2rayN/Forms/MainForm.cs +++ b/v2rayN/v2rayN/Forms/MainForm.cs @@ -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 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 datas = new List(); + 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 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 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) diff --git a/v2rayN/v2rayN/Forms/MainForm.resx b/v2rayN/v2rayN/Forms/MainForm.resx index 1c8fbd92..89a06c02 100644 --- a/v2rayN/v2rayN/Forms/MainForm.resx +++ b/v2rayN/v2rayN/Forms/MainForm.resx @@ -305,7 +305,7 @@ 0, 0 - 726, 331 + 638, 331 @@ -315,7 +315,7 @@ lvServers - System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + v2rayN.Forms.MainForm+ListViewFlickerFree, v2rayN, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null splitContainer1.Panel1 @@ -375,10 +375,10 @@ 100 - 986, 331 + 898, 331 - 726 + 638 2 @@ -501,7 +501,7 @@ 0, 66 - 992, 351 + 904, 351 2 @@ -537,7 +537,7 @@ Vertical - 986, 134 + 898, 134 2 @@ -567,7 +567,7 @@ 0, 17 - 257, 17 + 227, 17 38, 17 @@ -579,7 +579,7 @@ 0, 17 - 257, 17 + 227, 17 31, 17 @@ -591,7 +591,7 @@ 0, 17 - 257, 17 + 227, 17 45, 17 @@ -609,7 +609,7 @@ 3, 151 - 986, 22 + 898, 22 7 @@ -636,7 +636,7 @@ 0, 417 - 992, 176 + 904, 176 4 @@ -663,7 +663,7 @@ 0, 56 - 992, 10 + 904, 10 5 @@ -867,7 +867,7 @@ 0, 0 - 992, 56 + 904, 56 6 @@ -894,7 +894,7 @@ 6, 12 - 992, 593 + 904, 593 4, 4, 4, 4 diff --git a/v2rayN/v2rayN/Forms/MainForm.zh-Hans.resx b/v2rayN/v2rayN/Forms/MainForm.zh-Hans.resx index e25e9c82..ea88b1d6 100644 --- a/v2rayN/v2rayN/Forms/MainForm.zh-Hans.resx +++ b/v2rayN/v2rayN/Forms/MainForm.zh-Hans.resx @@ -450,4 +450,7 @@ 关闭 + + 代理速度 + \ No newline at end of file diff --git a/v2rayN/v2rayN/Forms/OptionSettingForm.Designer.cs b/v2rayN/v2rayN/Forms/OptionSettingForm.Designer.cs index f642333e..4caf3e40 100644 --- a/v2rayN/v2rayN/Forms/OptionSettingForm.Designer.cs +++ b/v2rayN/v2rayN/Forms/OptionSettingForm.Designer.cs @@ -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); diff --git a/v2rayN/v2rayN/Forms/OptionSettingForm.cs b/v2rayN/v2rayN/Forms/OptionSettingForm.cs index f64f9271..b692f928 100644 --- a/v2rayN/v2rayN/Forms/OptionSettingForm.cs +++ b/v2rayN/v2rayN/Forms/OptionSettingForm.cs @@ -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; } diff --git a/v2rayN/v2rayN/Forms/OptionSettingForm.resx b/v2rayN/v2rayN/Forms/OptionSettingForm.resx index 16622a9b..7e395cbd 100644 --- a/v2rayN/v2rayN/Forms/OptionSettingForm.resx +++ b/v2rayN/v2rayN/Forms/OptionSettingForm.resx @@ -1486,7 +1486,7 @@ 161, 82 - 121, 20 + 58, 20 32 @@ -1591,13 +1591,13 @@ 15, 60 - 390, 16 + 558, 16 29 - Enable Statistics(Realtime net speed and traffic data amount) + Enable Statistics(Realtime net speed and traffic data amount. Need restart v2rayN client) chkEnableStatistics diff --git a/v2rayN/v2rayN/Forms/OptionSettingForm.zh-Hans.resx b/v2rayN/v2rayN/Forms/OptionSettingForm.zh-Hans.resx index 1f11bc0f..cef4cd5a 100644 --- a/v2rayN/v2rayN/Forms/OptionSettingForm.zh-Hans.resx +++ b/v2rayN/v2rayN/Forms/OptionSettingForm.zh-Hans.resx @@ -288,11 +288,8 @@ 参数设置 - - 启用快捷键(Ctrl+P ping 选中服务器/ Ctrl+T 测速选中服务器) - - 启用统计(实时网速显示和使用流量显示) + 启用统计(实时网速显示和使用流量显示,需要重启v2rayN客户端) 缓存天数(0-30, 0关闭缓存单独每天的数据使用情况) diff --git a/v2rayN/v2rayN/Global.cs b/v2rayN/v2rayN/Global.cs index b854be90..f3a77f79 100644 --- a/v2rayN/v2rayN/Global.cs +++ b/v2rayN/v2rayN/Global.cs @@ -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 diff --git a/v2rayN/v2rayN/Handler/StatisticsHandler.cs b/v2rayN/v2rayN/Handler/StatisticsHandler.cs index 2ab1d687..9813c8ef 100644 --- a/v2rayN/v2rayN/Handler/StatisticsHandler.cs +++ b/v2rayN/v2rayN/Handler/StatisticsHandler.cs @@ -22,7 +22,7 @@ namespace v2rayN.Handler private Thread workThread_; - Action updateFunc_; + Action> 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 Statistic{ get; set; } - public UInt64 Down { get; private set; } + public ulong Up { get; private set; } - public StatisticsHandler(Config config, Action update) + public ulong Down { get; private set; } + + private string logPath_; + + public StatisticsHandler(Config config, Action> update) { config_ = config; enabled_ = config.enableStatistics; UpdateUI = false; updateFunc_ = update; + logPath_ = Utils.GetPath($"{Global.StatisticLogDirectory}\\"); + Statistic = new List(); + + 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(); + } + } } } } diff --git a/v2rayN/v2rayN/Mode/ServerStatistics.cs b/v2rayN/v2rayN/Mode/ServerStatistics.cs new file mode 100644 index 00000000..ac8ee61b --- /dev/null +++ b/v2rayN/v2rayN/Mode/ServerStatistics.cs @@ -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; + } + } +} diff --git a/v2rayN/v2rayN/Resx/ResUI.Designer.cs b/v2rayN/v2rayN/Resx/ResUI.Designer.cs index 8b66bfc2..66383ce9 100644 --- a/v2rayN/v2rayN/Resx/ResUI.Designer.cs +++ b/v2rayN/v2rayN/Resx/ResUI.Designer.cs @@ -105,6 +105,15 @@ namespace v2rayN.Resx { } } + /// + /// Looks up a localized string similar to DOWN. + /// + internal static string downloadSpeed { + get { + return ResourceManager.GetString("downloadSpeed", resourceCulture); + } + } + /// /// Looks up a localized string similar to Whether to download? {0}. /// @@ -321,6 +330,42 @@ namespace v2rayN.Resx { } } + /// + /// Looks up a localized string similar to Today download traffic. + /// + internal static string LvTodayDownloadDataAmount { + get { + return ResourceManager.GetString("LvTodayDownloadDataAmount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Today upload traffic. + /// + internal static string LvTodayUploadDataAmount { + get { + return ResourceManager.GetString("LvTodayUploadDataAmount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total download traffic. + /// + internal static string LvTotalDownloadDataAmount { + get { + return ResourceManager.GetString("LvTotalDownloadDataAmount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total upload traffic. + /// + internal static string LvTotalUploadDataAmount { + get { + return ResourceManager.GetString("LvTotalUploadDataAmount", resourceCulture); + } + } + /// /// Looks up a localized string similar to Transport. /// @@ -690,5 +735,14 @@ namespace v2rayN.Resx { return ResourceManager.GetString("SuccessfullyImportedServerViaScan", resourceCulture); } } + + /// + /// Looks up a localized string similar to UP. + /// + internal static string uploadSpeed { + get { + return ResourceManager.GetString("uploadSpeed", resourceCulture); + } + } } } diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index c49770ca..7f18977b 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -328,4 +328,22 @@ SlowFresh + + DOWN + + + Today download traffic + + + Today upload traffic + + + Total download traffic + + + Total upload traffic + + + UP + \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index 27a7cd9e..9119c5d5 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -328,4 +328,22 @@ + + 下载 + + + 今日下载 + + + 今日上传 + + + 总下载 + + + 总上传 + + + 上传 + \ No newline at end of file diff --git a/v2rayN/v2rayN/Tool/Utils.cs b/v2rayN/v2rayN/Tool/Utils.cs index fb8e7a20..01037932 100644 --- a/v2rayN/v2rayN/Tool/Utils.cs +++ b/v2rayN/v2rayN/Tool/Utils.cs @@ -262,6 +262,55 @@ namespace v2rayN } } + /// + /// byte 转成 有两位小数点的 方便阅读的数据 + /// 比如 2.50 MB + /// + /// bytes + /// 转换之后的数据 + /// 单位 + 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 diff --git a/v2rayN/v2rayN/v2rayN.csproj b/v2rayN/v2rayN/v2rayN.csproj index 1af85bc3..141ced38 100644 --- a/v2rayN/v2rayN/v2rayN.csproj +++ b/v2rayN/v2rayN/v2rayN.csproj @@ -157,6 +157,7 @@ Component +