LenovoLegionToolkit

Форк
0
417 строк · 15.2 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Threading;
5
using System.Threading.Tasks;
6
using LenovoLegionToolkit.Lib.AutoListeners;
7
using LenovoLegionToolkit.Lib.Automation.Pipeline;
8
using LenovoLegionToolkit.Lib.Automation.Pipeline.Triggers;
9
using LenovoLegionToolkit.Lib.Automation.Utils;
10
using LenovoLegionToolkit.Lib.Controllers.GodMode;
11
using LenovoLegionToolkit.Lib.Listeners;
12
using LenovoLegionToolkit.Lib.Utils;
13
using NeoSmart.AsyncLock;
14

15
namespace LenovoLegionToolkit.Lib.Automation;
16

17
public class AutomationProcessor
18
{
19
    private readonly AutomationSettings _settings;
20
    private readonly NativeWindowsMessageListener _nativeWindowsMessageListener;
21
    private readonly PowerStateListener _powerStateListener;
22
    private readonly PowerModeListener _powerModeListener;
23
    private readonly GodModeController _godModeController;
24
    private readonly GameAutoListener _gameAutoListener;
25
    private readonly ProcessAutoListener _processAutoListener;
26
    private readonly TimeAutoListener _timeAutoListener;
27
    private readonly UserInactivityAutoListener _userInactivityAutoListener;
28
    private readonly WiFiAutoListener _wifiAutoListener;
29

30
    private readonly AsyncLock _ioLock = new();
31
    private readonly AsyncLock _runLock = new();
32

33
    private List<AutomationPipeline> _pipelines = new();
34
    private CancellationTokenSource? _cts;
35

36
    public bool IsEnabled => _settings.Store.IsEnabled;
37

38
    public event EventHandler<List<AutomationPipeline>>? PipelinesChanged;
39

40
    public AutomationProcessor(AutomationSettings settings,
41
        NativeWindowsMessageListener nativeWindowsMessageListener,
42
        PowerStateListener powerStateListener,
43
        PowerModeListener powerModeListener,
44
        GodModeController godModeController,
45
        GameAutoListener gameAutoListener,
46
        ProcessAutoListener processAutoListener,
47
        TimeAutoListener timeAutoListener,
48
        UserInactivityAutoListener userInactivityAutoListener,
49
        WiFiAutoListener wifiAutoListener)
50
    {
51
        _settings = settings ?? throw new ArgumentNullException(nameof(settings));
52
        _nativeWindowsMessageListener = nativeWindowsMessageListener ?? throw new ArgumentNullException(nameof(nativeWindowsMessageListener));
53
        _powerStateListener = powerStateListener ?? throw new ArgumentNullException(nameof(powerStateListener));
54
        _powerModeListener = powerModeListener ?? throw new ArgumentNullException(nameof(powerModeListener));
55
        _godModeController = godModeController ?? throw new ArgumentNullException(nameof(godModeController));
56
        _gameAutoListener = gameAutoListener ?? throw new ArgumentNullException(nameof(gameAutoListener));
57
        _processAutoListener = processAutoListener ?? throw new ArgumentNullException(nameof(processAutoListener));
58
        _timeAutoListener = timeAutoListener ?? throw new ArgumentNullException(nameof(timeAutoListener));
59
        _userInactivityAutoListener = userInactivityAutoListener ?? throw new ArgumentNullException(nameof(userInactivityAutoListener));
60
        _wifiAutoListener = wifiAutoListener ?? throw new ArgumentNullException(nameof(wifiAutoListener));
61
    }
62

63
    #region Initialization / pipeline reloading
64

65
    public async Task InitializeAsync()
66
    {
67
        using (await _ioLock.LockAsync().ConfigureAwait(false))
68
        {
69
            _nativeWindowsMessageListener.Changed += NativeWindowsMessageListener_Changed;
70
            _powerStateListener.Changed += PowerStateListener_Changed;
71
            _powerModeListener.Changed += PowerModeListener_Changed;
72
            _godModeController.PresetChanged += GodModeController_PresetChanged;
73

74
            _pipelines = _settings.Store.Pipelines.ToList();
75

76
            RaisePipelinesChanged();
77

78
            await UpdateListenersAsync().ConfigureAwait(false);
79
        }
80
    }
81

82
    public async Task SetEnabledAsync(bool enabled)
83
    {
84
        using (await _ioLock.LockAsync().ConfigureAwait(false))
85
        {
86
            _settings.Store.IsEnabled = enabled;
87
            _settings.SynchronizeStore();
88

89
            await UpdateListenersAsync().ConfigureAwait(false);
90
        }
91
    }
92

93
    public async Task ReloadPipelinesAsync(List<AutomationPipeline> pipelines)
94
    {
95
        if (Log.Instance.IsTraceEnabled)
96
            Log.Instance.Trace($"Pipelines reload pending...");
97

98
        using (await _ioLock.LockAsync().ConfigureAwait(false))
99
        {
100
            if (Log.Instance.IsTraceEnabled)
101
                Log.Instance.Trace($"Pipelines reloading...");
102

103
            _pipelines = pipelines.Select(p => p.DeepCopy()).ToList();
104

105
            _settings.Store.Pipelines = pipelines;
106
            _settings.SynchronizeStore();
107

108
            RaisePipelinesChanged();
109

110
            await UpdateListenersAsync().ConfigureAwait(false);
111

112
            if (Log.Instance.IsTraceEnabled)
113
                Log.Instance.Trace($"Pipelines reloaded.");
114
        }
115
    }
116

117
    public async Task<List<AutomationPipeline>> GetPipelinesAsync()
118
    {
119
        using (await _ioLock.LockAsync().ConfigureAwait(false))
120
            return _pipelines.Select(p => p.DeepCopy()).ToList();
121
    }
122

123
    #endregion
124

125
    #region Run
126

127
    public void RunOnStartup()
128
    {
129
        if (!IsEnabled)
130
        {
131
            if (Log.Instance.IsTraceEnabled)
132
                Log.Instance.Trace($"Not enabled. Pipeline run on startup ignored.");
133

134
            return;
135
        }
136

137
        if (Log.Instance.IsTraceEnabled)
138
            Log.Instance.Trace($"Pipeline run on startup pending...");
139

140
        Task.Run(() => ProcessEvent(new StartupAutomationEvent()));
141
    }
142

143
    public async Task RunNowAsync(AutomationPipeline pipeline)
144
    {
145
        if (Log.Instance.IsTraceEnabled)
146
            Log.Instance.Trace($"Pipeline run now pending...");
147

148
        using (await _runLock.LockAsync().ConfigureAwait(false))
149
        {
150
            if (Log.Instance.IsTraceEnabled)
151
                Log.Instance.Trace($"Pipeline run starting...");
152

153
            try
154
            {
155
                await pipeline.DeepCopy().RunAsync().ConfigureAwait(false);
156

157
                if (Log.Instance.IsTraceEnabled)
158
                    Log.Instance.Trace($"Pipeline run finished successfully.");
159
            }
160
            catch (Exception ex)
161
            {
162
                if (Log.Instance.IsTraceEnabled)
163
                    Log.Instance.Trace($"Pipeline run failed.", ex);
164

165
                throw;
166
            }
167
        }
168
    }
169

170
    public async Task RunNowAsync(Guid pipelineId)
171
    {
172
        using (await _runLock.LockAsync().ConfigureAwait(false))
173
        {
174
            var pipeline = _pipelines.Where(p => p.Trigger is null).FirstOrDefault(p => p.Id == pipelineId);
175
            if (pipeline is null)
176
                return;
177

178
            await RunNowAsync(pipeline).ConfigureAwait(false);
179
        }
180
    }
181

182
    private async Task RunAsync(IAutomationEvent automationEvent)
183
    {
184
        if (Log.Instance.IsTraceEnabled)
185
            Log.Instance.Trace($"Run pending...");
186

187
        using (await _runLock.LockAsync().ConfigureAwait(false))
188
        {
189
            if (Log.Instance.IsTraceEnabled)
190
                Log.Instance.Trace($"Run starting...");
191

192
            _cts?.Cancel();
193

194
            if (!IsEnabled)
195
                return;
196

197
            List<AutomationPipeline> pipelines;
198
            using (await _ioLock.LockAsync().ConfigureAwait(false))
199
                pipelines = _pipelines;
200

201
            _cts = new CancellationTokenSource();
202
            var ct = _cts.Token;
203

204
            foreach (var pipeline in pipelines)
205
            {
206
                if (ct.IsCancellationRequested)
207
                {
208
                    if (Log.Instance.IsTraceEnabled)
209
                        Log.Instance.Trace($"Run interrupted.");
210
                    break;
211
                }
212

213
                try
214
                {
215
                    if (pipeline.Trigger is null || !await pipeline.Trigger.IsMatchingEvent(automationEvent).ConfigureAwait(false))
216
                    {
217
                        if (Log.Instance.IsTraceEnabled)
218
                            Log.Instance.Trace($"Pipeline triggers not satisfied. [name={pipeline.Name}, trigger={pipeline.Trigger}, steps.Count={pipeline.Steps.Count}]");
219
                        continue;
220
                    }
221

222
                    if (Log.Instance.IsTraceEnabled)
223
                        Log.Instance.Trace($"Running pipeline... [name={pipeline.Name}, trigger={pipeline.Trigger}, steps.Count={pipeline.Steps.Count}]");
224

225
                    await pipeline.RunAsync(ct).ConfigureAwait(false);
226

227
                    if (Log.Instance.IsTraceEnabled)
228
                        Log.Instance.Trace($"Pipeline completed successfully. [name={pipeline.Name}, trigger={pipeline.Trigger}]");
229
                }
230
                catch (Exception ex)
231
                {
232
                    if (Log.Instance.IsTraceEnabled)
233
                        Log.Instance.Trace($"Pipeline run failed. [name={pipeline.Name}, trigger={pipeline.Trigger}]", ex);
234
                }
235

236
                if (pipeline.IsExclusive)
237
                {
238
                    if (Log.Instance.IsTraceEnabled)
239
                        Log.Instance.Trace($"Pipeline is exclusive. Breaking. [name={pipeline.Name}, trigger={pipeline.Trigger}, steps.Count={pipeline.Steps.Count}]");
240
                    break;
241
                }
242
            }
243

244
            if (Log.Instance.IsTraceEnabled)
245
                Log.Instance.Trace($"Run finished successfully.");
246
        }
247
    }
248

249
    #endregion
250

251
    #region Listeners
252

253
    private async void NativeWindowsMessageListener_Changed(object? sender, NativeWindowsMessage message)
254
    {
255
        var e = new NativeWindowsMessageEvent { Message = message };
256
        await ProcessEvent(e).ConfigureAwait(false);
257
    }
258

259
    private async void PowerStateListener_Changed(object? sender, EventArgs _)
260
    {
261
        var e = new PowerStateAutomationEvent();
262
        await ProcessEvent(e).ConfigureAwait(false);
263
    }
264

265
    private async void PowerModeListener_Changed(object? sender, PowerModeState powerModeState)
266
    {
267
        var e = new PowerModeAutomationEvent { PowerModeState = powerModeState };
268
        await ProcessEvent(e).ConfigureAwait(false);
269
    }
270

271
    private async void GodModeController_PresetChanged(object? sender, Guid presetId)
272
    {
273
        var e = new CustomModePresetAutomationEvent { Id = presetId };
274
        await ProcessEvent(e).ConfigureAwait(false);
275
    }
276

277
    private async void GameAutoListener_Changed(object? sender, bool started)
278
    {
279
        var e = new GameAutomationEvent { Started = started };
280
        await ProcessEvent(e).ConfigureAwait(false);
281
    }
282

283
    private async void ProcessAutoListener_Changed(object? sender, ProcessEventInfo processEventInfo)
284
    {
285
        var e = new ProcessAutomationEvent { ProcessEventInfo = processEventInfo };
286
        await ProcessEvent(e).ConfigureAwait(false);
287
    }
288

289
    private async void TimeAutoListener_Changed(object? sender, (Time time, DayOfWeek day) timeDay)
290
    {
291
        var e = new TimeAutomationEvent { Time = timeDay.time, Day = timeDay.day };
292
        await ProcessEvent(e).ConfigureAwait(false);
293
    }
294

295
    private async void UserInactivityAutoListener_Changed(object? sender, (TimeSpan resolution, uint tickCount) inactivityInfo)
296
    {
297
        var e = new UserInactivityAutomationEvent
298
        {
299
            InactivityTimeSpan = inactivityInfo.resolution * inactivityInfo.tickCount,
300
            ResolutionTimeSpan = inactivityInfo.resolution
301
        };
302
        await ProcessEvent(e).ConfigureAwait(false);
303
    }
304

305
    private async void WiFiAutoListener_Changed(object? sender, (bool connected, string? ssid) wifiInfo)
306
    {
307
        var e = new WiFiAutomationEvent
308
        {
309
            IsConnected = wifiInfo.connected,
310
            Ssid = wifiInfo.ssid
311
        };
312
        await ProcessEvent(e).ConfigureAwait(false);
313
    }
314

315
    #endregion
316

317
    #region Event processing
318

319
    private async Task ProcessEvent(IAutomationEvent e)
320
    {
321
        var potentialMatch = _pipelines.SelectMany(p => p.AllTriggers)
322
            .Select(async t => await t.IsMatchingEvent(e).ConfigureAwait(false))
323
            .Select(t => t.Result)
324
            .Where(t => t)
325
            .Any();
326

327
        if (!potentialMatch)
328
            return;
329

330
        if (Log.Instance.IsTraceEnabled)
331
            Log.Instance.Trace($"Processing event {e}... [type={e.GetType().Name}]");
332

333
        await RunAsync(e).ConfigureAwait(false);
334
    }
335

336
    #endregion
337

338
    #region Helper methods
339

340
    private async Task UpdateListenersAsync()
341
    {
342
        if (Log.Instance.IsTraceEnabled)
343
            Log.Instance.Trace($"Stopping listeners...");
344

345
        await _gameAutoListener.UnsubscribeChangedAsync(GameAutoListener_Changed).ConfigureAwait(false);
346
        await _processAutoListener.UnsubscribeChangedAsync(ProcessAutoListener_Changed).ConfigureAwait(false);
347
        await _timeAutoListener.UnsubscribeChangedAsync(TimeAutoListener_Changed).ConfigureAwait(false);
348
        await _userInactivityAutoListener.UnsubscribeChangedAsync(UserInactivityAutoListener_Changed).ConfigureAwait(false);
349
        await _wifiAutoListener.UnsubscribeChangedAsync(WiFiAutoListener_Changed).ConfigureAwait(false);
350

351
        if (Log.Instance.IsTraceEnabled)
352
            Log.Instance.Trace($"Stopped listeners...");
353

354
        if (!IsEnabled)
355
        {
356
            if (Log.Instance.IsTraceEnabled)
357
                Log.Instance.Trace($"Not enabled. Will not start listeners.");
358
            return;
359
        }
360

361
        if (Log.Instance.IsTraceEnabled)
362
            Log.Instance.Trace($"Starting listeners...");
363

364
        var triggers = _pipelines.SelectMany(p => p.AllTriggers).ToArray();
365

366
        if (triggers.OfType<IGameAutomationPipelineTrigger>().Any())
367
        {
368
            if (Log.Instance.IsTraceEnabled)
369
                Log.Instance.Trace($"Starting game listener...");
370

371
            await _gameAutoListener.SubscribeChangedAsync(GameAutoListener_Changed).ConfigureAwait(false);
372
        }
373

374
        if (triggers.OfType<IProcessesAutomationPipelineTrigger>().Any())
375
        {
376
            if (Log.Instance.IsTraceEnabled)
377
                Log.Instance.Trace($"Starting process listener...");
378

379
            await _processAutoListener.SubscribeChangedAsync(ProcessAutoListener_Changed).ConfigureAwait(false);
380
        }
381

382
        if (triggers.OfType<ITimeAutomationPipelineTrigger>().Any())
383
        {
384
            if (Log.Instance.IsTraceEnabled)
385
                Log.Instance.Trace($"Starting time listener...");
386

387
            await _timeAutoListener.SubscribeChangedAsync(TimeAutoListener_Changed).ConfigureAwait(false);
388
        }
389

390
        if (triggers.OfType<IUserInactivityPipelineTrigger>().Any())
391
        {
392
            if (Log.Instance.IsTraceEnabled)
393
                Log.Instance.Trace($"Starting user inactivity listener...");
394

395
            await _userInactivityAutoListener.SubscribeChangedAsync(UserInactivityAutoListener_Changed).ConfigureAwait(false);
396
        }
397

398
        if (triggers.OfType<IWiFiConnectedPipelineTrigger>().Any() || triggers.OfType<WiFiDisconnectedAutomationPipelineTrigger>().Any())
399
        {
400
            if (Log.Instance.IsTraceEnabled)
401
                Log.Instance.Trace($"Starting WiFi listener...");
402

403
            await _wifiAutoListener.SubscribeChangedAsync(WiFiAutoListener_Changed).ConfigureAwait(false);
404
        }
405

406
        if (Log.Instance.IsTraceEnabled)
407
            Log.Instance.Trace($"Started relevant listeners.");
408
    }
409

410
    private void RaisePipelinesChanged()
411
    {
412
        PipelinesChanged?.Invoke(this, _pipelines.Select(p => p.DeepCopy()).ToList());
413
    }
414

415
    #endregion
416

417
}
418

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.