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(); LoadServers();
SelectLastServer(); SelectLastServer();
ServerHelper.DelayTestHelper.UpdateInterval(); DelayTestHelper.UpdateTick(true);
ModeHelper.InitWatcher(); ModeHelper.InitWatcher();
ModeHelper.Load(); ModeHelper.Load();
@@ -592,7 +592,7 @@ namespace Netch.Forms
} }
if (oldSettings.DetectionTick != Global.Settings.DetectionTick) if (oldSettings.DetectionTick != Global.Settings.DetectionTick)
ServerHelper.DelayTestHelper.UpdateInterval(); DelayTestHelper.UpdateTick(true);
if (oldSettings.ProfileCount != Global.Settings.ProfileCount) if (oldSettings.ProfileCount != Global.Settings.ProfileCount)
LoadProfiles(); LoadProfiles();
@@ -663,7 +663,7 @@ namespace Netch.Forms
} }
else else
{ {
await ServerHelper.DelayTestHelper.TestAllDelayAsync(); await DelayTestHelper.PerformTestAsync(true);
Enable(); Enable();
} }
} }
@@ -995,7 +995,7 @@ namespace Netch.Forms
_state = value; _state = value;
ServerHelper.DelayTestHelper.Enabled = IsWaiting(_state); DelayTestHelper.Enabled = IsWaiting(_state);
StatusText(); StatusText();
switch (value) switch (value)
@@ -1057,14 +1057,11 @@ namespace Netch.Forms
State = State.Stopped; State = State.Stopped;
} }
private bool IsWaiting() private bool IsWaiting() => IsWaiting(_state);
{
return State == State.Waiting || State == State.Stopped;
}
private static bool IsWaiting(State state) private static bool IsWaiting(State state)
{ {
return state == State.Waiting || state == State.Stopped; return state is State.Waiting or State.Stopped;
} }
/// <summary> /// <summary>
@@ -1253,7 +1250,7 @@ namespace Netch.Forms
return; return;
} }
State = State.Terminating; // State = State.Terminating;
NotifyIcon.Visible = false; NotifyIcon.Visible = false;
Hide(); 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>(ProfileCountTextBox, i => i > -1, i => Global.Settings.ProfileCount = i, Global.Settings.ProfileCount);
BindTextBox<int>(DetectionTickTextBox, BindTextBox<int>(DetectionTickTextBox,
i => ServerHelper.DelayTestHelper.Range.InRange(i), i => DelayTestHelper.Range.InRange(i),
i => Global.Settings.DetectionTick = i, i => Global.Settings.DetectionTick = i,
Global.Settings.DetectionTick); Global.Settings.DetectionTick);

View File

@@ -43,11 +43,7 @@ namespace Netch.Models
/// <summary> /// <summary>
/// 代理类型 /// 代理类型
/// </summary> /// </summary>
public virtual string Type { get; } = string.Empty; public abstract string Type { get; }
[JsonExtensionData]
// ReSharper disable once CollectionNeverUpdated.Global
public Dictionary<string, object> ExtensionData { get; set; } = new();
public object Clone() public object Clone()
{ {
@@ -62,7 +58,7 @@ namespace Netch.Models
{ {
var remark = string.IsNullOrWhiteSpace(Remark) ? $"{Hostname}:{Port}" : Remark; 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}"; 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) public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{ {
var jsonElement = JsonSerializer.Deserialize<JsonElement>(ref reader)!; var jsonElement = JsonSerializer.Deserialize<JsonElement>(ref reader);
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
try return (Server)JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
{
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())!;
}
} }
public override void Write(Utf8JsonWriter writer, Server value, JsonSerializerOptions options) public override void Write(Utf8JsonWriter writer, Server value, JsonSerializerOptions options)

View File

@@ -1,14 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Netch.Interfaces; using Netch.Interfaces;
using Netch.Models;
using Timer = System.Timers.Timer;
namespace Netch.Utils namespace Netch.Utils
{ {
@@ -23,102 +17,11 @@ namespace Netch.Utils
ServerUtilDictionary = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).ToDictionary(util => util.TypeName); ServerUtilDictionary = serversUtilsTypes.Select(t => (IServerUtil)Activator.CreateInstance(t)!).ToDictionary(util => util.TypeName);
} }
#region Delay public static Dictionary<string, IServerUtil> ServerUtilDictionary { get; }
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 IServerUtil GetUtilByTypeName(string typeName) 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) public static IServerUtil? GetUtilByUriScheme(string scheme)
@@ -130,7 +33,5 @@ namespace Netch.Utils
{ {
return GetUtilByTypeName(typeName).ServerType; return GetUtilByTypeName(typeName).ServerType;
} }
#endregion
} }
} }