RobotNet/RobotNet.ScriptManager/Services/LoopService.cs
2025-10-15 15:15:53 +07:00

46 lines
1.6 KiB
C#

using System.Diagnostics;
namespace RobotNet.ScriptManager.Services;
public abstract class LoopService(int interval) : IHostedService
{
private readonly TimeSpan Interval = TimeSpan.FromMilliseconds(interval);
private readonly CancellationTokenSource cancellationTokenSource = new();
private readonly Stopwatch stopwatch = new();
private Timer? timer;
public async Task StartAsync(CancellationToken cancellationToken)
{
await BeforExecuteAsync(cancellationToken);
stopwatch.Start();
timer = new Timer(Callback, cancellationTokenSource, 0, Timeout.Infinite);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
cancellationTokenSource.Cancel();
timer?.Dispose();
await AfterExecuteAsync(cancellationToken);
}
protected virtual Task BeforExecuteAsync(CancellationToken cancellationToken) => Task.CompletedTask;
protected abstract void Execute(CancellationToken stoppingToken);
protected virtual Task AfterExecuteAsync(CancellationToken cancellationToken) => Task.CompletedTask;
private void Callback(object? state)
{
if (state is not CancellationTokenSource cts || cts.IsCancellationRequested) return;
Execute(cts.Token);
if (!cts.IsCancellationRequested)
{
long nextTrigger = Interval.Ticks - (stopwatch.ElapsedTicks % Interval.Ticks);
if (nextTrigger <= 0) nextTrigger = Interval.Ticks;
int nextIntervalMs = (int)(nextTrigger / TimeSpan.TicksPerMillisecond);
timer?.Change(nextIntervalMs, Timeout.Infinite);
}
}
}