| 1 | using Microsoft.UI.Dispatching; |
| 2 | using RblxTool.Interop; |
| 3 | using RblxTool.Models; |
| 4 | |
| 5 | namespace RblxTool.Services; |
| 6 | |
| 7 | public sealed class JobRunner |
| 8 | { |
| 9 | private readonly RblxEngine _engine; |
| 10 | private readonly DispatcherQueue _dispatcher; |
| 11 | private CancellationTokenSource? _pump; |
| 12 | |
| 13 | public JobRunner(RblxEngine engine, DispatcherQueue dispatcher) |
| 14 | { |
| 15 | _engine = engine; |
| 16 | _dispatcher = dispatcher; |
| 17 | } |
| 18 | |
| 19 | public ulong JobId { get; private set; } |
| 20 | |
| 21 | public bool Running => _pump is not null && !_pump.IsCancellationRequested; |
| 22 | |
| 23 | public event Action<JobEvent>? EventReceived; |
| 24 | |
| 25 | public event Action<string>? Completed; |
| 26 | |
| 27 | public void Start(ulong jobId, int pollIntervalMs = 120) |
| 28 | { |
| 29 | if (jobId == 0) |
| 30 | { |
| 31 | Completed?.Invoke("engine refused the job"); |
| 32 | return; |
| 33 | } |
| 34 | Stop(); |
| 35 | JobId = jobId; |
| 36 | var source = new CancellationTokenSource(); |
| 37 | _pump = source; |
| 38 | _ = Task.Run(() => Pump(jobId, pollIntervalMs, source.Token), source.Token); |
| 39 | } |
| 40 | |
| 41 | private async Task Pump(ulong jobId, int pollIntervalMs, CancellationToken token) |
| 42 | { |
| 43 | var idle = 0; |
| 44 | while (!token.IsCancellationRequested) |
| 45 | { |
| 46 | var poll = _engine.Poll(jobId); |
| 47 | if (poll.Events.Count > 0) |
| 48 | { |
| 49 | idle = 0; |
| 50 | var batch = poll.Events; |
| 51 | _dispatcher.TryEnqueue(DispatcherQueuePriority.Low, () => |
| 52 | { |
| 53 | foreach (var item in batch) |
| 54 | { |
| 55 | EventReceived?.Invoke(item); |
| 56 | } |
| 57 | }); |
| 58 | } |
| 59 | else |
| 60 | { |
| 61 | idle++; |
| 62 | } |
| 63 | |
| 64 | if (poll.Done && poll.Events.Count == 0) |
| 65 | { |
| 66 | var result = _engine.Result(jobId); |
| 67 | _dispatcher.TryEnqueue(() => Completed?.Invoke(result)); |
| 68 | break; |
| 69 | } |
| 70 | |
| 71 | var delay = idle > 20 ? pollIntervalMs * 4 : pollIntervalMs; |
| 72 | try |
| 73 | { |
| 74 | await Task.Delay(delay, token).ConfigureAwait(false); |
| 75 | } |
| 76 | catch (TaskCanceledException) |
| 77 | { |
| 78 | break; |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | public void Cancel() |
| 84 | { |
| 85 | if (JobId != 0) |
| 86 | { |
| 87 | _engine.Cancel(JobId); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | public void Stop() |
| 92 | { |
| 93 | _pump?.Cancel(); |
| 94 | _pump?.Dispose(); |
| 95 | _pump = null; |
| 96 | } |
| 97 | } |