mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-21 09:45:48 +08:00
修复 DpiHelper 在未初始化窗口句柄时获取 DPI 缩放值的问题,现在能正确处理多显示器场景。重构 QuartzSchedulerService 的触发器同步逻辑,确保定时任务正确更新。在添加/编辑触发器时增加 Cron 表达式格式校验,避免无效表达式导致调度失败。同时修复 ScriptService 中任务启动时的线程调度问题。
97 lines
3.3 KiB
C#
97 lines
3.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BetterGenshinImpact.Model.Gear.Triggers;
|
|
using BetterGenshinImpact.Model.Gear.Triggers.QuartzJob;
|
|
using BetterGenshinImpact.ViewModel.Pages.Component;
|
|
using BetterGenshinImpact.Service.GearTask;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Quartz;
|
|
using Quartz.Impl.Matchers;
|
|
|
|
namespace BetterGenshinImpact.Service;
|
|
|
|
/// <summary>
|
|
/// Quartz.NET 调度器服务
|
|
/// </summary>
|
|
public class QuartzSchedulerService(ILogger<QuartzSchedulerService> logger,
|
|
ISchedulerFactory schedulerFactory,
|
|
GearTriggerStorageService triggerStorageService) : IHostedService
|
|
{
|
|
private readonly ILogger<QuartzSchedulerService> _logger = logger;
|
|
private const string GearGroupName = "gear";
|
|
|
|
public async Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
var (timedTriggers, _) = await triggerStorageService.LoadTriggersAsync();
|
|
await SyncTimedTriggersAsync(timedTriggers, cancellationToken);
|
|
}
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public async Task SyncTimedTriggersAsync(IEnumerable<GearTriggerViewModel> timedTriggers, CancellationToken cancellationToken = default)
|
|
{
|
|
var scheduler = await schedulerFactory.GetScheduler(cancellationToken);
|
|
var existingJobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(GearGroupName), cancellationToken);
|
|
|
|
if (existingJobKeys.Count > 0)
|
|
{
|
|
await scheduler.DeleteJobs(existingJobKeys.ToList(), cancellationToken);
|
|
}
|
|
|
|
var jobsDictionary = BuildJobsDictionary(timedTriggers);
|
|
if (jobsDictionary.Count > 0)
|
|
{
|
|
await scheduler.ScheduleJobs(jobsDictionary, replace: true, cancellationToken);
|
|
}
|
|
}
|
|
|
|
private static Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> BuildJobsDictionary(IEnumerable<GearTriggerViewModel> timedTriggers)
|
|
{
|
|
var allData = timedTriggers
|
|
.Where(t => t.IsEnabled && !string.IsNullOrWhiteSpace(t.CronExpression))
|
|
.Select(t => t.ToTrigger())
|
|
.OfType<QuartzCronGearTrigger>()
|
|
.ToList();
|
|
|
|
var jobsDictionary = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
|
|
|
|
foreach (var data in allData)
|
|
{
|
|
if (string.IsNullOrEmpty(data.CronExpression) || !data.IsEnabled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var jobDataMap = new JobDataMap
|
|
{
|
|
{ "TriggerName", data.Name },
|
|
{ "TriggerId", System.Guid.NewGuid().ToString() },
|
|
{ "ShouldInterruptOthers", false },
|
|
{ "TaskDefinitionName", data.TaskDefinitionName }
|
|
};
|
|
|
|
var job = JobBuilder.Create<QuartzGearTaskJob>()
|
|
.WithIdentity($"job:{data.Name}", GearGroupName)
|
|
.UsingJobData(jobDataMap)
|
|
.Build();
|
|
|
|
var trigger = TriggerBuilder.Create()
|
|
.WithIdentity($"trigger:{data.Name}", GearGroupName)
|
|
.WithCronSchedule(data.CronExpression)
|
|
.ForJob(job)
|
|
.Build();
|
|
|
|
jobsDictionary.Add(job, new HashSet<ITrigger> { trigger });
|
|
}
|
|
|
|
return jobsDictionary;
|
|
}
|
|
|
|
}
|