Update ServerHelper.cs

Extract and Refactor DelayTestHelper
This commit is contained in:
ChsBuffer
2021-07-19 04:46:00 +08:00
parent 3e943ec6b8
commit 773bad4845
6 changed files with 122 additions and 131 deletions

View File

@@ -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;
}
/// <summary>
@@ -1253,7 +1250,7 @@ namespace Netch.Forms
return;
}
State = State.Terminating;
// State = State.Terminating;
NotifyIcon.Visible = false;
Hide();

View File

@@ -48,7 +48,7 @@ namespace Netch.Forms
BindTextBox<int>(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount);
BindTextBox<int>(DetectionTickTextBox,
i => ServerHelper.DelayTestHelper.Range.InRange(i),
i => DelayTestHelper.Range.InRange(i),
i => Global.Settings.DetectionTick = i,
Global.Settings.DetectionTick);

View File

@@ -43,11 +43,7 @@ namespace Netch.Models
/// <summary>
/// 代理类型
/// </summary>
public virtual string Type { get; } = string.Empty;
[JsonExtensionData]
// ReSharper disable once CollectionNeverUpdated.Global
public Dictionary<string, object> 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}";
}

View File

@@ -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();
}
}
/// <param name="waitFinish">if does not get lock, block until last release</param>
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);
}
/// <param name="interval">interval(seconds), 0 disable, MaxValue <c>int.MaxValue/1000</c></param>
/// <param name="performTestAtOnce"></param>
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();
}
}
}
}

View File

@@ -11,19 +11,9 @@ namespace Netch.Utils
public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonElement = JsonSerializer.Deserialize<JsonElement>(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<Server>(jsonElement.GetRawText(), new JsonSerializerOptions())!;
}
var jsonElement = JsonSerializer.Deserialize<JsonElement>(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)

View File

@@ -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<string, IServerUtil> ServerUtilDictionary { get; set; }
public static Dictionary<string, IServerUtil> 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
}
}