get subscription userinfo

This commit is contained in:
2dust
2022-10-06 15:42:35 +08:00
parent cc0288ed5d
commit a5b208e729
11 changed files with 206 additions and 174 deletions

View File

@@ -51,18 +51,18 @@ namespace clashN.Base
} }
return null; return null;
} }
public async Task<string> GetAsync(HttpClient client, string url, CancellationToken token) public async Task<(string, HttpResponseHeaders)> GetAsync(HttpClient client, string url, CancellationToken token)
{ {
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
return null; return (null, null);
} }
HttpResponseMessage response = await client.GetAsync(url, token); HttpResponseMessage response = await client.GetAsync(url, token);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new Exception(string.Format("The request returned with HTTP status code {0}", response.StatusCode)); throw new Exception(string.Format("The request returned with HTTP status code {0}", response.StatusCode));
} }
return await response.Content.ReadAsStringAsync(); return (await response.Content.ReadAsStringAsync(), response.Headers);
} }

View File

@@ -637,7 +637,16 @@ namespace clashN.Handler
} }
} }
public static void ClearAllServerStatistics(ref Config config)
{
foreach (var item in config.profileItems)
{
item.uploadRemote = 0;
item.downloadRemote = 0;
}
ToJsonFile(config);
}
#endregion #endregion
} }

View File

@@ -71,7 +71,7 @@ namespace clashN.Handler
/// DownloadString /// DownloadString
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
public async Task<string> DownloadStringAsync(string url, bool blProxy, string userAgent) public async Task<(string, HttpResponseHeaders)> DownloadStringAsync(string url, bool blProxy, string userAgent)
{ {
try try
{ {
@@ -109,7 +109,7 @@ namespace clashN.Handler
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException)); Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
} }
} }
return null; return (null, null);
} }
public async Task<string> UrlRedirectAsync(string url, bool blProxy) public async Task<string> UrlRedirectAsync(string url, bool blProxy)

View File

@@ -7,34 +7,34 @@ namespace clashN.Handler
class StatisticsHandler class StatisticsHandler
{ {
private Config config_; private Config config_;
private ServerStatistics serverStatistics_; //private ServerStatistics serverStatistics_;
private bool exitFlag_; private bool exitFlag_;
private ClientWebSocket webSocket = null; private ClientWebSocket webSocket = null;
string url = string.Empty; string url = string.Empty;
Action<ulong, ulong, List<ProfileStatItem>> updateFunc_; Action<ulong, ulong> updateFunc_;
private bool Enable private bool Enable
{ {
get; set; get; set;
} }
private List<ProfileStatItem> Statistic //private List<ProfileStatItem> Statistic
{ //{
get // get
{ // {
return serverStatistics_.profileStat; // return serverStatistics_.profileStat;
} // }
} //}
public StatisticsHandler(Config config, Action<ulong, ulong, List<ProfileStatItem>> update) public StatisticsHandler(Config config, Action<ulong, ulong> update)
{ {
config_ = config; config_ = config;
Enable = config.enableStatistics; Enable = config.enableStatistics;
updateFunc_ = update; updateFunc_ = update;
exitFlag_ = false; exitFlag_ = false;
LoadFromFile(); //LoadFromFile();
Task.Run(() => Run()); Task.Run(() => Run());
} }
@@ -106,18 +106,14 @@ namespace clashN.Handler
var result = Encoding.UTF8.GetString(buffer, 0, res.Count); var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
if (!Utils.IsNullOrEmpty(result)) if (!Utils.IsNullOrEmpty(result))
{ {
string itemId = config_.indexId; var serverStatItem = config_.GetProfileItem(config_.indexId);
ProfileStatItem serverStatItem = GetServerStatItem(itemId);
ParseOutput(result, out ulong up, out ulong down); ParseOutput(result, out ulong up, out ulong down);
if (up + down > 0) if (up + down > 0)
{ {
serverStatItem.todayUp += up; serverStatItem.uploadRemote += up;
serverStatItem.todayDown += down; serverStatItem.downloadRemote += down;
serverStatItem.totalUp += up;
serverStatItem.totalDown += down;
} }
updateFunc_(up, down, new List<ProfileStatItem> { serverStatItem }); updateFunc_(up, down);
} }
res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
} }
@@ -133,103 +129,103 @@ namespace clashN.Handler
} }
} }
public void LoadFromFile() //public void LoadFromFile()
{ //{
try // try
{ // {
string result = Utils.LoadResource(Utils.GetConfigPath(Global.StatisticLogOverall)); // string result = Utils.LoadResource(Utils.GetConfigPath(Global.StatisticLogOverall));
if (!Utils.IsNullOrEmpty(result)) // if (!Utils.IsNullOrEmpty(result))
{ // {
serverStatistics_ = Utils.FromJson<ServerStatistics>(result); // serverStatistics_ = Utils.FromJson<ServerStatistics>(result);
} // }
if (serverStatistics_ == null) // if (serverStatistics_ == null)
{ // {
serverStatistics_ = new ServerStatistics(); // serverStatistics_ = new ServerStatistics();
} // }
if (serverStatistics_.profileStat == null) // if (serverStatistics_.profileStat == null)
{ // {
serverStatistics_.profileStat = new List<ProfileStatItem>(); // serverStatistics_.profileStat = new List<ProfileStatItem>();
} // }
long ticks = DateTime.Now.Date.Ticks; // long ticks = DateTime.Now.Date.Ticks;
foreach (ProfileStatItem item in serverStatistics_.profileStat) // foreach (ProfileStatItem item in serverStatistics_.profileStat)
{ // {
if (item.dateNow != ticks) // if (item.dateNow != ticks)
{ // {
item.todayUp = 0; // item.todayUp = 0;
item.todayDown = 0; // item.todayDown = 0;
item.dateNow = ticks; // item.dateNow = ticks;
} // }
} // }
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
Utils.SaveLog(ex.Message, ex); // Utils.SaveLog(ex.Message, ex);
} // }
} //}
public void SaveToFile() //public void SaveToFile()
{ //{
try // try
{ // {
Utils.ToJsonFile(serverStatistics_, Utils.GetConfigPath(Global.StatisticLogOverall)); // Utils.ToJsonFile(serverStatistics_, Utils.GetConfigPath(Global.StatisticLogOverall));
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
Utils.SaveLog(ex.Message, ex); // Utils.SaveLog(ex.Message, ex);
} // }
} //}
public void ClearAllServerStatistics() //public void ClearAllServerStatistics()
{ //{
if (serverStatistics_ != null) // if (serverStatistics_ != null)
{ // {
foreach (var item in serverStatistics_.profileStat) // foreach (var item in serverStatistics_.profileStat)
{ // {
item.todayUp = 0; // item.todayUp = 0;
item.todayDown = 0; // item.todayDown = 0;
item.totalUp = 0; // item.totalUp = 0;
item.totalDown = 0; // item.totalDown = 0;
// update ui display to zero // // update ui display to zero
updateFunc_(0, 0, new List<ProfileStatItem> { item }); // updateFunc_(0, 0);
} // }
// update statistic json file // // update statistic json file
SaveToFile(); // //SaveToFile();
} // }
} //}
public List<ProfileStatItem> GetStatistic() //public List<ProfileStatItem> GetStatistic()
{ //{
return Statistic; // return Statistic;
} //}
private ProfileStatItem GetServerStatItem(string itemId) //private ProfileStatItem GetServerStatItem(string itemId)
{ //{
long ticks = DateTime.Now.Date.Ticks; // long ticks = DateTime.Now.Date.Ticks;
int cur = Statistic.FindIndex(item => item.indexId == itemId); // int cur = Statistic.FindIndex(item => item.indexId == itemId);
if (cur < 0) // if (cur < 0)
{ // {
Statistic.Add(new ProfileStatItem // Statistic.Add(new ProfileStatItem
{ // {
indexId = itemId, // indexId = itemId,
totalUp = 0, // totalUp = 0,
totalDown = 0, // totalDown = 0,
todayUp = 0, // todayUp = 0,
todayDown = 0, // todayDown = 0,
dateNow = ticks // dateNow = ticks
}); // });
cur = Statistic.Count - 1; // cur = Statistic.Count - 1;
} // }
if (Statistic[cur].dateNow != ticks) // if (Statistic[cur].dateNow != ticks)
{ // {
Statistic[cur].todayUp = 0; // Statistic[cur].todayUp = 0;
Statistic[cur].todayDown = 0; // Statistic[cur].todayDown = 0;
Statistic[cur].dateNow = ticks; // Statistic[cur].dateNow = ticks;
} // }
return Statistic[cur]; // return Statistic[cur];
} //}
private void ParseOutput(string source, out ulong up, out ulong down) private void ParseOutput(string source, out ulong up, out ulong down)
{ {

View File

@@ -3,6 +3,7 @@ using clashN.Mode;
using clashN.Resx; using clashN.Resx;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Net.Http.Headers;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
@@ -211,27 +212,56 @@ namespace clashN.Handler
_updateFunc(false, $"{hashCode}{args.GetException().Message}"); _updateFunc(false, $"{hashCode}{args.GetException().Message}");
}; };
var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent); var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent);
if (blProxy && Utils.IsNullOrEmpty(result)) if (blProxy && Utils.IsNullOrEmpty(result.Item1))
{ {
result = await downloadHandle.DownloadStringAsync(url, false, userAgent); result = await downloadHandle.DownloadStringAsync(url, false, userAgent);
} }
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result.Item1))
{ {
_updateFunc(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}"); _updateFunc(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}");
} }
else else
{ {
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}"); _updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result.Length < 99) if (result.Item1.Length < 99)
{ {
_updateFunc(false, $"{hashCode}{result}"); _updateFunc(false, $"{hashCode}{result}");
} }
int ret = ConfigHandler.AddBatchProfiles(ref config, result, indexId, groupId); int ret = ConfigHandler.AddBatchProfiles(ref config, result.Item1, indexId, groupId);
if (ret == 0) if (ret == 0)
{ {
item.updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); item.updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
//get remote info
try
{
if (result.Item2 != null && result.Item2 is HttpResponseHeaders)
{
var userinfo = ((HttpResponseHeaders)result.Item2)
.Where(t => t.Key == "subscription-userinfo")
.Select(t => t.Value)
.FirstOrDefault()?
.FirstOrDefault();
Dictionary<string, string>? dicInfo = userinfo?.Split(';')
.Select(value => value.Split('='))
.ToDictionary(pair => pair[0].Trim(), pair => pair[1].Trim());
if (dicInfo != null)
{
item.uploadRemote = ParseRemoteInfo(dicInfo, "upload");
item.downloadRemote = ParseRemoteInfo(dicInfo, "download");
item.totalRemote = ParseRemoteInfo(dicInfo, "total");
item.expireRemote = dicInfo.ContainsKey("expire") ? Convert.ToInt64(dicInfo?["expire"]) : 0;
}
}
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
_updateFunc(false, $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}"); _updateFunc(false, $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}");
} }
else else
@@ -251,7 +281,10 @@ namespace clashN.Handler
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); _updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}); });
} }
private ulong ParseRemoteInfo(Dictionary<string, string> dicInfo, string key)
{
return dicInfo.ContainsKey(key) ? Convert.ToUInt64(dicInfo?[key]) : 0;
}
public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update) public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
{ {

View File

@@ -150,7 +150,7 @@ namespace clashN.Mode
{ {
get { return !address.IsNullOrEmpty(); } get { return !address.IsNullOrEmpty(); }
} }
public string HasUpdateTime public string StrUpdateTime
{ {
get get
{ {
@@ -159,9 +159,30 @@ namespace clashN.Mode
return String.Empty; return String.Empty;
} }
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return dateTime.AddSeconds(updateTime).ToLocalTime().ToString("MM/dd HH:mm"); return dateTime.AddSeconds(updateTime).ToLocalTime().ToString("MM-dd HH:mm");
} }
} }
public string TrafficUsed
{
get { return Utils.HumanFy(uploadRemote + downloadRemote); }
}
public string TrafficTotal
{
get { return totalRemote <= 0 ? "∞" : Utils.HumanFy(totalRemote); }
}
public string StrExpireTime
{
get
{
if (expireRemote <= 0)
{
return String.Empty;
}
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return dateTime.AddSeconds(expireRemote).ToLocalTime().ToString("yyyy-MM-dd");
}
}
#endregion #endregion
@@ -216,7 +237,10 @@ namespace clashN.Mode
public bool enableConvert { get; set; } public bool enableConvert { get; set; }
public long updateTime { get; set; } public long updateTime { get; set; }
public ulong uploadRemote { get; set; }
public ulong downloadRemote { get; set; }
public ulong totalRemote { get; set; }
public long expireRemote { get; set; }
} }
[Serializable] [Serializable]

View File

@@ -3,22 +3,5 @@
public class ProfileItemModel : ProfileItem public class ProfileItemModel : ProfileItem
{ {
public bool isActive { get; set; } public bool isActive { get; set; }
public string totalUp
{
get; set;
}
public string totalDown
{
get; set;
}
public string todayUp
{
get; set;
}
public string todayDown
{
get; set;
}
} }
} }

View File

@@ -200,7 +200,7 @@ namespace clashN.ViewModels
StorageUI(); StorageUI();
ConfigHandler.SaveConfig(ref _config); ConfigHandler.SaveConfig(ref _config);
statistics?.SaveToFile(); //statistics?.SaveToFile();
statistics?.Close(); statistics?.Close();
} }
catch { } catch { }
@@ -271,7 +271,7 @@ namespace clashN.ViewModels
await LoadCore(); await LoadCore();
} }
} }
private void UpdateStatisticsHandler(ulong up, ulong down, List<ProfileStatItem> statistics) private void UpdateStatisticsHandler(ulong up, ulong down)
{ {
try try
{ {
@@ -291,15 +291,6 @@ namespace clashN.ViewModels
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
} }
} }
public void ClearAllServerStatistics()
{
statistics?.ClearAllServerStatistics();
}
public List<ProfileStatItem>? GetAllServerStatistic()
{
return statistics?.GetStatistic();
}
#endregion #endregion
#region Core #region Core
@@ -319,7 +310,7 @@ namespace clashN.ViewModels
Global.reloadCore = false; Global.reloadCore = false;
ConfigHandler.SaveConfig(ref _config, false); ConfigHandler.SaveConfig(ref _config, false);
statistics?.SaveToFile(); //statistics?.SaveToFile();
ChangePACButtonStatus(_config.sysProxyType); ChangePACButtonStatus(_config.sysProxyType);
SetRuleMode(_config.ruleMode); SetRuleMode(_config.ruleMode);
@@ -332,7 +323,7 @@ namespace clashN.ViewModels
public void CloseCore() public void CloseCore()
{ {
ConfigHandler.SaveConfig(ref _config, false); ConfigHandler.SaveConfig(ref _config, false);
statistics?.SaveToFile(); //statistics?.SaveToFile();
ChangePACButtonStatus(ESysProxyType.ForcedClear); ChangePACButtonStatus(ESysProxyType.ForcedClear);
@@ -450,7 +441,7 @@ namespace clashN.ViewModels
if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0)
{ {
if(_config.uiItem.mainWidth > SystemInformation.WorkingArea.Width) if (_config.uiItem.mainWidth > SystemInformation.WorkingArea.Width)
{ {
_config.uiItem.mainWidth = SystemInformation.WorkingArea.Width * 2 / 3; _config.uiItem.mainWidth = SystemInformation.WorkingArea.Width * 2 / 3;
} }

View File

@@ -128,7 +128,8 @@ namespace clashN.ViewModels
ClearStatisticCmd = ReactiveCommand.Create(() => ClearStatisticCmd = ReactiveCommand.Create(() =>
{ {
Locator.Current.GetService<MainWindowViewModel>()?.ClearAllServerStatistics(); ConfigHandler.ClearAllServerStatistics(ref _config);
RefreshProfiles();
}); });
ProfileReloadCmd = ReactiveCommand.Create(() => ProfileReloadCmd = ReactiveCommand.Create(() =>
{ {
@@ -320,22 +321,10 @@ namespace clashN.ViewModels
ConfigHandler.SetDefaultProfile(_config, _config.profileItems); ConfigHandler.SetDefaultProfile(_config, _config.profileItems);
var lstModel = new List<ProfileItemModel>(); var lstModel = new List<ProfileItemModel>();
var statistic = Locator.Current.GetService<MainWindowViewModel>()?.GetAllServerStatistic();
foreach (var item in _config.profileItems) foreach (var item in _config.profileItems)
{ {
var model = Utils.FromJson<ProfileItemModel>(Utils.ToJson(item)); var model = Utils.FromJson<ProfileItemModel>(Utils.ToJson(item));
model.isActive = _config.IsActiveNode(item); model.isActive = _config.IsActiveNode(item);
if (statistic != null)
{
var statOne = statistic.Where(t => t.indexId == item.indexId).FirstOrDefault();
if (statOne != null)
{
model.todayUp = Utils.HumanFy(statOne.todayUp);
model.todayDown = Utils.HumanFy(statOne.todayDown);
model.totalUp = Utils.HumanFy(statOne.totalUp);
model.totalDown = Utils.HumanFy(statOne.totalDown);
}
}
lstModel.Add(model); lstModel.Add(model);
} }

View File

@@ -142,7 +142,7 @@
IsHitTestVisible="False" IsHitTestVisible="False"
Style="{StaticResource ListItemCheckBox}" /> Style="{StaticResource ListItemCheckBox}" />
<TextBlock Style="{StaticResource ListItemSubTitle}" Text="{Binding HasUpdateTime}" /> <TextBlock Style="{StaticResource ListItemSubTitle}" Text="{Binding StrUpdateTime}" />
</StackPanel> </StackPanel>
@@ -152,20 +152,25 @@
Grid.Row="4" Grid.Row="4"
Margin="8,0,8,8" Margin="8,0,8,8"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Horizontal"> Orientation="Horizontal">
<materialDesign:PackIcon Padding="4,0,4,0" Kind="ArrowUpThin" /> <materialDesign:PackIcon Kind="ChartDonut" />
<TextBlock <TextBlock
Padding="4,0,4,0" Padding="4,0,4,0"
Style="{StaticResource ListItemSubTitle}" Style="{StaticResource ListItemSubTitle}"
Text="{Binding totalUp}" /> Text="{Binding TrafficUsed}" />
<materialDesign:PackIcon
Margin="8,0,0,0"
Padding="4,0,4,0"
Kind="ArrowDownThin" />
<TextBlock <TextBlock
Padding="4,0,4,0" Padding="4,0,4,0"
Style="{StaticResource ListItemSubTitle}" Style="{StaticResource ListItemSubTitle}"
Text="{Binding totalDown}" /> Text="/" />
<TextBlock
Padding="4,0,4,0"
Style="{StaticResource ListItemSubTitle}"
Text="{Binding TrafficTotal}" />
<TextBlock
Padding="4,0,4,0"
Style="{StaticResource ListItemSubTitle}"
Text="{Binding StrExpireTime}" />
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -36,6 +36,7 @@
<ComboBox <ComboBox
x:Name="cmbSwatches" x:Name="cmbSwatches"
Width="100" Width="100"
Margin="8"
DisplayMemberPath="Name" DisplayMemberPath="Name"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<Separator /> <Separator />
@@ -46,6 +47,7 @@
<ComboBox <ComboBox
x:Name="cmbCurrentLanguage" x:Name="cmbCurrentLanguage"
Width="100" Width="100"
Margin="8"
materialDesign:HintAssist.Hint="Language" materialDesign:HintAssist.Hint="Language"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />