mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-14 16:35:00 +03:00
f64c29972d
Move file-backed settings to ConfigTextManager and database operations to ConfigDbManager. Update desktop, Web API, and test references, and add Web API development launch settings.
173 lines
6.7 KiB
C#
173 lines
6.7 KiB
C#
using ServiceLib.Common;
|
|
using ServiceLib.Models.Entities;
|
|
using ServiceLib.Services;
|
|
using v2rayN.WebAPI.Contracts;
|
|
|
|
namespace v2rayN.WebAPI.Services;
|
|
|
|
public sealed partial class V2rayRuntime
|
|
{
|
|
private CancellationTokenSource? _scheduledOperationsCancellation;
|
|
private Task? _scheduledOperationsTask;
|
|
|
|
private void StartScheduledOperations(CancellationToken hostToken)
|
|
{
|
|
_scheduledOperationsCancellation = CancellationTokenSource.CreateLinkedTokenSource(hostToken, _operations.ShutdownToken);
|
|
var cancellationToken = _scheduledOperationsCancellation.Token;
|
|
_scheduledOperationsTask = Task.Run(() => RunScheduledOperationsAsync(cancellationToken));
|
|
}
|
|
|
|
private async Task<bool> StopScheduledOperationsAsync(CancellationToken shutdownToken)
|
|
{
|
|
var cancellation = _scheduledOperationsCancellation;
|
|
var task = _scheduledOperationsTask;
|
|
if (cancellation is null || task is null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
cancellation.Cancel();
|
|
try
|
|
{
|
|
await task.WaitAsync(shutdownToken);
|
|
}
|
|
catch (OperationCanceledException) when (task.IsCompleted && cancellation.IsCancellationRequested)
|
|
{
|
|
// Expected during graceful service shutdown.
|
|
}
|
|
finally
|
|
{
|
|
if (task.IsCompleted)
|
|
{
|
|
cancellation.Dispose();
|
|
_scheduledOperationsCancellation = null;
|
|
_scheduledOperationsTask = null;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private async Task RunScheduledOperationsAsync(CancellationToken cancellationToken)
|
|
{
|
|
var elapsedMinutes = 1;
|
|
while (true)
|
|
{
|
|
await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
|
|
await RunScheduledStepAsync("subscription", RunScheduledSubscriptionUpdatesAsync, cancellationToken);
|
|
|
|
if (elapsedMinutes % 20 == 0)
|
|
{
|
|
await RunScheduledStepAsync("save", async token =>
|
|
{
|
|
await using var operation = await _operations.EnterOperationAsync(token);
|
|
await _mutations.RunAsync(async () =>
|
|
{
|
|
await EnsureConfigSaveSucceededAsync(() => ConfigTextManager.Instance.SaveConfig());
|
|
await ProfileExManager.Instance.SaveTo();
|
|
}, operation.Token);
|
|
}, cancellationToken);
|
|
}
|
|
|
|
if (elapsedMinutes % 60 == 0)
|
|
{
|
|
await RunScheduledStepAsync("cleanup", async token =>
|
|
{
|
|
await using var operation = await _operations.EnterOperationAsync(token);
|
|
FileUtils.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1), "Test");
|
|
FileUtils.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddDays(-7));
|
|
FileUtils.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddDays(-7));
|
|
}, cancellationToken);
|
|
|
|
var elapsedHours = elapsedMinutes / 60;
|
|
if (Config.GuiItem.AutoUpdateInterval > 0 && elapsedHours % Config.GuiItem.AutoUpdateInterval == 0)
|
|
{
|
|
await RunScheduledStepAsync("geo-update", RunScheduledGeoUpdateAsync, cancellationToken);
|
|
}
|
|
}
|
|
|
|
if (elapsedMinutes % 1440 == 1)
|
|
{
|
|
await RunScheduledStepAsync("core-update-check", RunScheduledCoreUpdateCheckAsync, cancellationToken);
|
|
}
|
|
elapsedMinutes++;
|
|
}
|
|
}
|
|
|
|
private async Task RunScheduledStepAsync(string name, Func<CancellationToken, Task> step, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
await step(cancellationToken);
|
|
}
|
|
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
AddLog("task", $"{name}: {exception.Message}");
|
|
}
|
|
}
|
|
|
|
private async Task RunScheduledSubscriptionUpdatesAsync(CancellationToken cancellationToken)
|
|
{
|
|
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
IReadOnlyList<SubItem> subscriptions;
|
|
await using (var operation = await _operations.EnterOperationAsync(cancellationToken))
|
|
{
|
|
subscriptions = (await AppManager.Instance.SubItems() ?? [])
|
|
.Where(item => item.AutoUpdateInterval > 0
|
|
&& now - item.UpdateTime >= item.AutoUpdateInterval * 60L)
|
|
.ToArray();
|
|
}
|
|
|
|
foreach (var subscription in subscriptions)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
var update = StartSubscriptionUpdateTask(subscription.Id, useProxy: true, cancellationToken);
|
|
if (update is not null)
|
|
{
|
|
await update.WaitAsync(cancellationToken);
|
|
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task RunScheduledGeoUpdateAsync(CancellationToken cancellationToken)
|
|
{
|
|
await using var operation = await _operations.EnterExclusiveAsync(
|
|
cancellationToken,
|
|
allowReadOnlyObservations: true);
|
|
using var downloadService = await DownloadService.CreateDownloadServiceWithCheck(Config.CheckUpdateItem.UpdateViaProxy);
|
|
await new UpdateService(downloadService, Config, (success, message) =>
|
|
{
|
|
AddLog("update", message);
|
|
_events.Publish("geo-update-progress", new
|
|
{
|
|
success,
|
|
code = success ? "ok" : "geo_update_progress",
|
|
messageKey = success ? ApiMessageKeys.CommonCompleted : ApiMessageKeys.GeoUpdateProgress,
|
|
rawLog = message,
|
|
});
|
|
if (success)
|
|
{
|
|
_events.Publish("geo-update-completed", OperationView.Ok(ApiMessageKeys.CommonCompleted));
|
|
}
|
|
return Task.CompletedTask;
|
|
}).UpdateGeoFileAll(operation.Token);
|
|
}
|
|
|
|
private async Task RunScheduledCoreUpdateCheckAsync(CancellationToken cancellationToken)
|
|
{
|
|
await using var operation = await _operations.EnterOperationAsync(cancellationToken);
|
|
using var downloadService = await DownloadService.CreateDownloadServiceWithCheck(Config.CheckUpdateItem.UpdateViaProxy);
|
|
var updateService = new UpdateService(downloadService, Config, (_, _) => Task.CompletedTask);
|
|
var messages = await updateService.CheckHasUpdateOnlyAll(operation.Token);
|
|
foreach (var message in messages)
|
|
{
|
|
AddLog("update", message);
|
|
}
|
|
}
|
|
}
|