From 773bad484546b2fcc6cced96cc34b00e95d2592d Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Mon, 19 Jul 2021 04:46:00 +0800 Subject: [PATCH] Update ServerHelper.cs Extract and Refactor DelayTestHelper --- Netch/Forms/MainForm.cs | 17 ++- Netch/Forms/SettingForm.cs | 2 +- Netch/Models/Server.cs | 8 +- Netch/Utils/DelayTestHelper.cs | 107 ++++++++++++++++++ .../ServerConverterWithTypeDiscriminator.cs | 16 +-- Netch/Utils/ServerHelper.cs | 103 +---------------- 6 files changed, 122 insertions(+), 131 deletions(-) create mode 100644 Netch/Utils/DelayTestHelper.cs diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index 583a7364..b5319dec 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -78,7 +78,7 @@ namespace Netch.Forms LoadServers(); SelectLastServer(); - ServerHelper.DelayTestHelper.UpdateInterval(); + DelayTestHelper.UpdateTick(true); ModeHelper.InitWatcher(); ModeHelper.Load(); @@ -592,7 +592,7 @@ namespace Netch.Forms } if (oldSettings.DetectionTick != Global.Settings.DetectionTick) - ServerHelper.DelayTestHelper.UpdateInterval(); + DelayTestHelper.UpdateTick(true); if (oldSettings.ProfileCount != Global.Settings.ProfileCount) LoadProfiles(); @@ -663,7 +663,7 @@ namespace Netch.Forms } else { - await ServerHelper.DelayTestHelper.TestAllDelayAsync(); + await DelayTestHelper.PerformTestAsync(true); Enable(); } } @@ -995,7 +995,7 @@ namespace Netch.Forms _state = value; - ServerHelper.DelayTestHelper.Enabled = IsWaiting(_state); + DelayTestHelper.Enabled = IsWaiting(_state); StatusText(); switch (value) @@ -1057,14 +1057,11 @@ namespace Netch.Forms State = State.Stopped; } - private bool IsWaiting() - { - return State == State.Waiting || State == State.Stopped; - } + private bool IsWaiting() => IsWaiting(_state); private static bool IsWaiting(State state) { - return state == State.Waiting || state == State.Stopped; + return state is State.Waiting or State.Stopped; } /// @@ -1253,7 +1250,7 @@ namespace Netch.Forms return; } - State = State.Terminating; + // State = State.Terminating; NotifyIcon.Visible = false; Hide(); diff --git a/Netch/Forms/SettingForm.cs b/Netch/Forms/SettingForm.cs index d18d4156..a8186838 100644 --- a/Netch/Forms/SettingForm.cs +++ b/Netch/Forms/SettingForm.cs @@ -48,7 +48,7 @@ namespace Netch.Forms BindTextBox(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount); BindTextBox(DetectionTickTextBox, - i => ServerHelper.DelayTestHelper.Range.InRange(i), + i => DelayTestHelper.Range.InRange(i), i => Global.Settings.DetectionTick = i, Global.Settings.DetectionTick); diff --git a/Netch/Models/Server.cs b/Netch/Models/Server.cs index ce070fbe..2d83536a 100644 --- a/Netch/Models/Server.cs +++ b/Netch/Models/Server.cs @@ -43,11 +43,7 @@ namespace Netch.Models /// /// 代理类型 /// - public virtual string Type { get; } = string.Empty; - - [JsonExtensionData] - // ReSharper disable once CollectionNeverUpdated.Global - public Dictionary ExtensionData { get; set; } = new(); + public abstract string Type { get; } public object Clone() { @@ -62,7 +58,7 @@ namespace Netch.Models { var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark; - var shortName = Type.IsNullOrEmpty() ? "WTF" : ServerHelper.GetUtilByTypeName(Type).ShortName; + var shortName = ServerHelper.GetUtilByTypeName(Type).ShortName; return $"[{shortName}][{Group}] {remark}"; } diff --git a/Netch/Utils/DelayTestHelper.cs b/Netch/Utils/DelayTestHelper.cs new file mode 100644 index 00000000..383393f7 --- /dev/null +++ b/Netch/Utils/DelayTestHelper.cs @@ -0,0 +1,107 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Threading; +using Netch.Models; +using Timer = System.Timers.Timer; + +namespace Netch.Utils +{ + public static class DelayTestHelper + { + private static readonly Timer Timer; + + private static readonly SemaphoreSlim Lock = new(1, 1); + + private static readonly SemaphoreSlim PoolLock = new(16, 16); + + public static readonly NumberRange Range = new(0, int.MaxValue / 1000); + + private static bool _enabled = true; + + static DelayTestHelper() + { + Timer = new Timer + { + Interval = 10000, + AutoReset = true + }; + + Timer.Elapsed += (_, _) => PerformTestAsync().Forget(); + } + + public static bool Enabled + { + get => _enabled; + set + { + _enabled = value; + UpdateTick(); + } + } + + /// if does not get lock, block until last release + public static async Task PerformTestAsync(bool waitFinish = false) + { + if (Lock.CurrentCount == 0) + { + if (waitFinish) + { + await Lock.WaitAsync(); + Lock.Release(); + } + + return; + } + + await Lock.WaitAsync(); + try + { + var tasks = Global.Settings.Server.Select(async s => + { + await PoolLock.WaitAsync(); + try + { + await s.PingAsync(); + } + finally + { + PoolLock.Release(); + } + }); + + await Task.WhenAll(tasks); + } + catch (Exception) + { + // ignored + } + finally + { + Lock.Release(); + } + } + + public static void UpdateTick(bool performTestAtOnce = false) + { + UpdateTick(Global.Settings.DetectionTick, performTestAtOnce); + } + + /// interval(seconds), 0 disable, MaxValue int.MaxValue/1000 + /// + private static void UpdateTick(int interval, bool performTestAtOnce = false) + { + Timer.Stop(); + + var enable = Enabled && interval > 0 && Range.InRange(interval); + if (enable) + { + Timer.Interval = interval * 1000; + Timer.Start(); + if (performTestAtOnce) + PerformTestAsync().Forget(); + } + } + } +} \ No newline at end of file diff --git a/Netch/Utils/ServerConverterWithTypeDiscriminator.cs b/Netch/Utils/ServerConverterWithTypeDiscriminator.cs index 8c9f755f..08e0bf76 100644 --- a/Netch/Utils/ServerConverterWithTypeDiscriminator.cs +++ b/Netch/Utils/ServerConverterWithTypeDiscriminator.cs @@ -11,19 +11,9 @@ namespace Netch.Utils public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var jsonElement = JsonSerializer.Deserialize(ref reader)!; - - try - { - var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!); - // TODO replace with .NET 6 Deserialize from DOM - return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!; - } - catch - { - // Unsupported Server Type - return JsonSerializer.Deserialize(jsonElement.GetRawText(), new JsonSerializerOptions())!; - } + var jsonElement = JsonSerializer.Deserialize(ref reader); + var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!); + return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!; } public override void Write(Utf8JsonWriter writer, Server value, JsonSerializerOptions options) diff --git a/Netch/Utils/ServerHelper.cs b/Netch/Utils/ServerHelper.cs index 7b94d7be..35ce4c4d 100644 --- a/Netch/Utils/ServerHelper.cs +++ b/Netch/Utils/ServerHelper.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.VisualStudio.Threading; using Netch.Interfaces; -using Netch.Models; -using Timer = System.Timers.Timer; namespace Netch.Utils { @@ -23,102 +17,11 @@ namespace Netch.Utils ServerUtilDictionary = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).ToDictionary(util => util.TypeName); } - #region Delay - - public static class DelayTestHelper - { - private static readonly Timer Timer; - private static readonly object TestAllLock = new(); - - private static readonly SemaphoreSlim SemaphoreSlim = new(1, 16); - - public static readonly NumberRange Range = new(0, int.MaxValue / 1000); - - static DelayTestHelper() - { - Timer = new Timer - { - Interval = 10000, - AutoReset = true - }; - - Timer.Elapsed += (_, _) => TestAllDelayAsync().Forget(); - } - - public static bool Enabled - { - get => Timer.Enabled; - set - { - if (!ValueIsEnabled(Global.Settings.DetectionTick)) - return; - - Timer.Enabled = value; - } - } - - public static int Interval => (int)(Timer.Interval / 1000); - - private static bool ValueIsEnabled(int value) - { - return value != 0 && Range.InRange(value); - } - - public static async Task TestAllDelayAsync() - { - if (!Monitor.TryEnter(TestAllLock)) - return; - - try - { - var tasks = Global.Settings.Server.Select(async s => - { - await SemaphoreSlim.WaitAsync(); - try - { - await s.PingAsync(); - } - finally - { - SemaphoreSlim.Release(); - } - }); - - await Task.WhenAll(tasks); - } - catch (Exception) - { - // ignored - } - finally - { - Monitor.Exit(TestAllLock); - } - } - - public static void UpdateInterval() - { - Timer.Stop(); - - if (!ValueIsEnabled(Global.Settings.DetectionTick)) - return; - - Timer.Interval = Global.Settings.DetectionTick * 1000; - Timer.Start(); - - TestAllDelayAsync().Forget(); - } - } - - #endregion - - #region Handler - - public static Dictionary ServerUtilDictionary { get; set; } + public static Dictionary ServerUtilDictionary { get; } public static IServerUtil GetUtilByTypeName(string typeName) { - return ServerUtilDictionary[typeName]; + return ServerUtilDictionary.GetValueOrDefault(typeName) ?? throw new NotSupportedException("Specified server type is not supported."); } public static IServerUtil? GetUtilByUriScheme(string scheme) @@ -130,7 +33,5 @@ namespace Netch.Utils { return GetUtilByTypeName(typeName).ServerType; } - - #endregion } } \ No newline at end of file