mirror of
https://github.com/2dust/v2rayN.git
synced 2026-09-26 08:32:08 +03:00
Fix async (#10218)
* Fix async * Fix async for statistics * Try fix pac async * Fix
This commit is contained in:
@@ -3,6 +3,7 @@ namespace ServiceLib.Handler.SysProxy;
|
||||
public static class SysProxyHandler
|
||||
{
|
||||
private static readonly string _tag = "SysProxyHandler";
|
||||
private static readonly Lazy<PacManager> _pacManager = new(() => new PacManager());
|
||||
|
||||
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
||||
{
|
||||
@@ -56,7 +57,7 @@ public static class SysProxyHandler
|
||||
|
||||
if (type != ESysProxyType.Pac && Utils.IsWindows())
|
||||
{
|
||||
PacManager.Instance.Stop();
|
||||
_pacManager.Value.Stop();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -110,7 +111,7 @@ public static class SysProxyHandler
|
||||
private static async Task SetWindowsProxyPac(int port)
|
||||
{
|
||||
var portPac = AppManager.Instance.GetLocalPort(EInboundProtocol.pac);
|
||||
await PacManager.Instance.StartAsync(port, portPac);
|
||||
await _pacManager.Value.StartAsync(port, portPac);
|
||||
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
||||
ProxySettingWindows.SetProxy(strProxy, "", 4);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class HttpClientHelper
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<string?> TryGetAsync(string url)
|
||||
public async Task<string?> TryGetAsync(string url, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
@@ -31,8 +31,12 @@ public class HttpClientHelper
|
||||
|
||||
try
|
||||
{
|
||||
var response = await httpClient.GetAsync(url);
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
var response = await httpClient.GetAsync(url, cancellationToken);
|
||||
return await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -75,15 +75,28 @@ public sealed class SQLiteHelper
|
||||
|
||||
public async Task DisposeDbConnectionAsync()
|
||||
{
|
||||
await Task.Factory.StartNew(() =>
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_db?.Close();
|
||||
_db?.Dispose();
|
||||
_db = null;
|
||||
try
|
||||
{
|
||||
_db?.Close();
|
||||
_db?.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_db = null;
|
||||
}
|
||||
|
||||
_dbAsync?.GetConnection()?.Close();
|
||||
_dbAsync?.GetConnection()?.Dispose();
|
||||
_dbAsync = null;
|
||||
try
|
||||
{
|
||||
var conn = _dbAsync?.GetConnection();
|
||||
conn?.Close();
|
||||
conn?.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dbAsync = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,36 +2,37 @@ namespace ServiceLib.Manager;
|
||||
|
||||
public class PacManager
|
||||
{
|
||||
private static readonly Lazy<PacManager> _instance = new(() => new PacManager());
|
||||
public static PacManager Instance => _instance.Value;
|
||||
|
||||
private int _httpPort;
|
||||
private const string Tag = "PacManager";
|
||||
private CancellationTokenSource? _cts;
|
||||
private int _pacPort;
|
||||
private TcpListener? _tcpListener;
|
||||
private byte[] _writeContent;
|
||||
private bool _isRunning;
|
||||
private bool _needRestart = true;
|
||||
private byte[] _writeContent = [];
|
||||
|
||||
public async Task StartAsync(int httpPort, int pacPort)
|
||||
{
|
||||
_needRestart = httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
|
||||
var content = await InitText(httpPort);
|
||||
_writeContent = content;
|
||||
|
||||
_httpPort = httpPort;
|
||||
_pacPort = pacPort;
|
||||
|
||||
await InitText();
|
||||
|
||||
if (_needRestart)
|
||||
if (_tcpListener is not null && _pacPort == pacPort)
|
||||
{
|
||||
Stop();
|
||||
RunListener();
|
||||
return;
|
||||
}
|
||||
|
||||
Stop();
|
||||
var cts = new CancellationTokenSource();
|
||||
var listener = TcpListener.Create(pacPort);
|
||||
listener.Start();
|
||||
|
||||
_cts = cts;
|
||||
_pacPort = pacPort;
|
||||
_tcpListener = listener;
|
||||
_ = ListenLoopAsync(listener, cts.Token);
|
||||
}
|
||||
|
||||
private async Task InitText()
|
||||
private async Task<byte[]> InitText(int httpPort)
|
||||
{
|
||||
var customSystemProxyPacPath = AppManager.Instance.Config.SystemProxyItem?.CustomSystemProxyPacPath;
|
||||
var fileName = (customSystemProxyPacPath.IsNotEmpty() && File.Exists(customSystemProxyPacPath))
|
||||
var customSystemProxyPacPath = AppManager.Instance.Config.SystemProxyItem.CustomSystemProxyPacPath;
|
||||
var fileName = customSystemProxyPacPath.IsNotEmpty() && File.Exists(customSystemProxyPacPath)
|
||||
? customSystemProxyPacPath
|
||||
: Path.Combine(Utils.GetConfigPath(), "pac.txt");
|
||||
|
||||
@@ -45,7 +46,7 @@ public class PacManager
|
||||
}
|
||||
|
||||
var pacText = await File.ReadAllTextAsync(fileName);
|
||||
pacText = pacText.Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
|
||||
pacText = pacText.Replace("__PROXY__", $"PROXY 127.0.0.1:{httpPort};DIRECT;");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("HTTP/1.0 200 OK");
|
||||
@@ -54,59 +55,43 @@ public class PacManager
|
||||
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
|
||||
sb.AppendLine();
|
||||
sb.Append(pacText);
|
||||
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
|
||||
return Encoding.UTF8.GetBytes(sb.ToString());
|
||||
}
|
||||
|
||||
private void RunListener()
|
||||
private async Task ListenLoopAsync(TcpListener listener, CancellationToken token)
|
||||
{
|
||||
_tcpListener = TcpListener.Create(_pacPort);
|
||||
_isRunning = true;
|
||||
_tcpListener.Start();
|
||||
Task.Factory.StartNew(async () =>
|
||||
var buffer = new byte[1024];
|
||||
try
|
||||
{
|
||||
while (_isRunning)
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_tcpListener.Pending())
|
||||
{
|
||||
await Task.Delay(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
var client = await _tcpListener.AcceptTcpClientAsync();
|
||||
await Task.Run(() => WriteContent(client));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
using var client = await listener.AcceptTcpClientAsync(token).ConfigureAwait(false);
|
||||
await using var stream = client.GetStream();
|
||||
_ = await stream.ReadAsync(buffer, token).ConfigureAwait(false);
|
||||
await stream.WriteAsync(_writeContent, token).ConfigureAwait(false);
|
||||
await stream.FlushAsync(token).ConfigureAwait(false);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
private void WriteContent(TcpClient client)
|
||||
{
|
||||
var stream = client.GetStream();
|
||||
stream.Write(_writeContent, 0, _writeContent.Length);
|
||||
stream.Flush();
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(Tag, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
listener.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_tcpListener == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_isRunning = false;
|
||||
_tcpListener.Stop();
|
||||
_tcpListener = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
_cts?.Cancel();
|
||||
_tcpListener?.Stop();
|
||||
_cts?.Dispose();
|
||||
_cts = null;
|
||||
_pacPort = 0;
|
||||
_tcpListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,23 +12,17 @@ public class TaskManager
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
_ = Task.Factory.StartNew(
|
||||
ScheduledTasks,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
Task.Run(ScheduledTasks);
|
||||
}
|
||||
|
||||
private async Task ScheduledTasks()
|
||||
{
|
||||
Logging.SaveLog("Setup Scheduled Tasks");
|
||||
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||
var numOfExecuted = 1;
|
||||
while (true)
|
||||
while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
|
||||
{
|
||||
//1 minute
|
||||
await Task.Delay(1000 * 60);
|
||||
|
||||
//Execute once 1 minute
|
||||
try
|
||||
{
|
||||
|
||||
@@ -5,8 +5,7 @@ namespace ServiceLib.Services.Statistics;
|
||||
public class StatisticsSingboxService
|
||||
{
|
||||
private readonly Config _config;
|
||||
private bool _exitFlag;
|
||||
private ClientWebSocket? webSocket;
|
||||
private CancellationTokenSource? _cts;
|
||||
private readonly Func<ServerSpeedItem, Task>? _updateFunc;
|
||||
private string Url => $"ws://{Global.Loopback}:{AppManager.Instance.StatePort2}/traffic";
|
||||
private static readonly string _tag = "StatisticsSingboxService";
|
||||
@@ -15,40 +14,17 @@ public class StatisticsSingboxService
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
_exitFlag = false;
|
||||
|
||||
_ = Task.Factory.StartNew(
|
||||
Run,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
|
||||
private async Task Init()
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
|
||||
try
|
||||
{
|
||||
if (webSocket == null)
|
||||
{
|
||||
webSocket = new ClientWebSocket();
|
||||
await webSocket.ConnectAsync(new Uri(Url), CancellationToken.None);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_exitFlag = true;
|
||||
if (webSocket != null)
|
||||
{
|
||||
webSocket.Abort();
|
||||
webSocket = null;
|
||||
}
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
_cts = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -58,53 +34,63 @@ public class StatisticsSingboxService
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
await Init();
|
||||
Close();
|
||||
_cts = new CancellationTokenSource();
|
||||
var token = _cts.Token;
|
||||
|
||||
while (!_exitFlag)
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
if (!AppManager.Instance.IsRunningCore(ECoreType.sing_box))
|
||||
{
|
||||
await Task.Delay(1000, token).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
if (webSocket != null)
|
||||
using var ws = new ClientWebSocket();
|
||||
await ws.ConnectAsync(new Uri(Url), token).ConfigureAwait(false);
|
||||
|
||||
var buffer = new byte[1024];
|
||||
while (ws.State == WebSocketState.Open
|
||||
&& !token.IsCancellationRequested)
|
||||
{
|
||||
if (webSocket.State is WebSocketState.Aborted or WebSocketState.Closed)
|
||||
var res = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), token);
|
||||
if (res.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
webSocket.Abort();
|
||||
webSocket = null;
|
||||
await Init();
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
using var ms = new MemoryStream();
|
||||
ms.Write(buffer, 0, res.Count);
|
||||
while (!res.EndOfMessage)
|
||||
{
|
||||
res = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), token).ConfigureAwait(false);
|
||||
ms.Write(buffer, 0, res.Count);
|
||||
}
|
||||
|
||||
if (webSocket.State != WebSocketState.Open)
|
||||
var result = Encoding.UTF8.GetString(ms.ToArray());
|
||||
if (!result.IsNotEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ParseOutput(result, out var up, out var down);
|
||||
|
||||
var buffer = new byte[1024];
|
||||
var res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
while (!res.CloseStatus.HasValue)
|
||||
if (_updateFunc != null)
|
||||
{
|
||||
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
||||
if (result.IsNotEmpty())
|
||||
await _updateFunc.Invoke(new ServerSpeedItem
|
||||
{
|
||||
ParseOutput(result, out var up, out var down);
|
||||
|
||||
await _updateFunc?.Invoke(new ServerSpeedItem()
|
||||
{
|
||||
ProxyUp = (long)(up / 1000),
|
||||
ProxyDown = (long)(down / 1000)
|
||||
});
|
||||
}
|
||||
res = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
ProxyUp = (long)(up / 1000),
|
||||
ProxyDown = (long)(down / 1000),
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(3000, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,33 +5,42 @@ public class StatisticsXrayService
|
||||
private const long linkBase = 1024;
|
||||
private ServerSpeedItem _serverSpeedItem = new();
|
||||
private readonly Config _config;
|
||||
private bool _exitFlag;
|
||||
private CancellationTokenSource? _cts;
|
||||
private readonly Func<ServerSpeedItem, Task>? _updateFunc;
|
||||
private string Url => $"{Global.HttpProtocol}{Global.Loopback}:{AppManager.Instance.StatePort}/debug/vars";
|
||||
private static readonly string _tag = "StatisticsXrayService";
|
||||
|
||||
public StatisticsXrayService(Config config, Func<ServerSpeedItem, Task> updateFunc)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
_exitFlag = false;
|
||||
|
||||
_ = Task.Factory.StartNew(
|
||||
Run,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default);
|
||||
Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_exitFlag = true;
|
||||
try
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
_cts = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Run()
|
||||
{
|
||||
while (!_exitFlag)
|
||||
Close();
|
||||
_cts = new CancellationTokenSource();
|
||||
var token = _cts.Token;
|
||||
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
|
||||
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
try
|
||||
{
|
||||
if (AppManager.Instance.RunningCoreType != ECoreType.Xray)
|
||||
@@ -39,16 +48,20 @@ public class StatisticsXrayService
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = await HttpClientHelper.Instance.TryGetAsync(Url);
|
||||
var result = await HttpClientHelper.Instance.TryGetAsync(Url, token);
|
||||
if (result != null)
|
||||
{
|
||||
var server = ParseOutput(result) ?? new ServerSpeedItem();
|
||||
await _updateFunc?.Invoke(server);
|
||||
await _updateFunc!.Invoke(server);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
await Task.Delay(3000, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,7 @@ public partial class ClashConnectionsViewModel : MyReactiveObject
|
||||
cancelDisposable.DisposeWith(disposables);
|
||||
var token = cancelDisposable.Token;
|
||||
|
||||
Task.Factory.StartNew(
|
||||
async () => await GetClashConnectionsTask(token),
|
||||
token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default
|
||||
);
|
||||
Task.Run(() => GetClashConnectionsTask(token));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,9 +124,9 @@ public partial class ClashConnectionsViewModel : MyReactiveObject
|
||||
try
|
||||
{
|
||||
var numOfExecuted = 1;
|
||||
while (!token.IsCancellationRequested)
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
|
||||
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
||||
{
|
||||
await Task.Delay(1000, token);
|
||||
numOfExecuted++;
|
||||
if (!(AutoRefresh && AppManager.Instance.ShowInTaskbar &&
|
||||
AppManager.Instance.IsRunningCore(ECoreType.sing_box)))
|
||||
|
||||
@@ -61,12 +61,7 @@ public partial class ClashProxiesViewModel : MyReactiveObject
|
||||
cancelDisposable.DisposeWith(disposables);
|
||||
var token = cancelDisposable.Token;
|
||||
|
||||
Task.Factory.StartNew(
|
||||
async () => await GetClashProxiesTask(token),
|
||||
token,
|
||||
TaskCreationOptions.LongRunning,
|
||||
TaskScheduler.Default
|
||||
);
|
||||
Task.Run(() => GetClashProxiesTask(token));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,9 +108,9 @@ public partial class ClashProxiesViewModel : MyReactiveObject
|
||||
try
|
||||
{
|
||||
var numOfExecuted = 1;
|
||||
while (!token.IsCancellationRequested)
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
|
||||
while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false))
|
||||
{
|
||||
await Task.Delay(1000, token);
|
||||
numOfExecuted++;
|
||||
if (!(AutoRefresh && AppManager.Instance.ShowInTaskbar &&
|
||||
AppManager.Instance.IsRunningCore(ECoreType.sing_box)))
|
||||
|
||||
Reference in New Issue
Block a user