FunGame-Core/Api/Utility/TaskScheduler.cs
milimoe 18854781a6
完善 WebSocket 支持;防止 SQL 注入;修改 Json 自定义转换器基类 (#104)
* 更换任务计划实现方式;修改自定义 Json 转换器基类

* RunTimeController 添加 HTTPClient(WebSocket)支持;SQL 查询修改为参数化,防止注入
2025-01-11 01:09:49 +08:00

217 lines
7.3 KiB
C#

using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
namespace Milimoe.FunGame.Core.Api.Utility
{
public class TaskScheduler
{
/// <summary>
/// 任务计划管理器实例,可以直接使用
/// </summary>
public static TaskScheduler Shared { get; } = new();
private readonly List<ScheduledTask> _tasks = [];
private readonly List<RecurringTask> _recurringTasks = [];
private readonly Lock _lock = new();
/// <summary>
/// 创建一个轻量级的任务计划管理器
/// </summary>
public TaskScheduler()
{
Task.Factory.StartNew(async () =>
{
while (true)
{
CheckAndRunTasks();
await Task.Delay(1000);
}
}, TaskCreationOptions.LongRunning);
}
/// <summary>
/// 添加一个任务计划
/// </summary>
/// <param name="name"></param>
/// <param name="timeOfDay"></param>
/// <param name="action"></param>
public void AddTask(string name, TimeSpan timeOfDay, Action action)
{
lock (_lock)
{
ScheduledTask task = new(name, timeOfDay, action);
if (DateTime.Now > DateTime.Today.Add(timeOfDay))
{
task.LastRun = DateTime.Today.Add(timeOfDay);
}
_tasks.Add(task);
}
}
/// <summary>
/// 添加一个循环任务
/// </summary>
/// <param name="name"></param>
/// <param name="interval"></param>
/// <param name="action"></param>
/// <param name="startNow"></param>
public void AddRecurringTask(string name, TimeSpan interval, Action action, bool startNow = false)
{
lock (_lock)
{
DateTime now = DateTime.Now;
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0);
DateTime nextRun = startNow ? now : now.Add(interval);
RecurringTask recurringTask = new(name, interval, action)
{
NextRun = nextRun
};
_recurringTasks.Add(recurringTask);
}
}
/// <summary>
/// 移除任务计划
/// </summary>
/// <param name="name"></param>
public void RemoveTask(string name)
{
lock (_lock)
{
int removeTasks = _tasks.RemoveAll(t => t.Name == name);
int removeRecurringTasks = _recurringTasks.RemoveAll(t => t.Name == name);
}
}
/// <summary>
/// 获取任务计划上一次执行时间
/// </summary>
/// <param name="name"></param>
/// <param name="recurring"></param>
/// <returns></returns>
public DateTime GetLastTime(string name, bool recurring = false)
{
if (!recurring)
{
if (_tasks.FirstOrDefault(t => t.Name == name) is ScheduledTask task && task.LastRun.HasValue)
{
return task.LastRun.Value;
}
else if (_recurringTasks.FirstOrDefault(t => t.Name == name) is RecurringTask recurringTask && recurringTask.LastRun.HasValue)
{
return recurringTask.LastRun.Value;
}
}
else if (_recurringTasks.FirstOrDefault(t => t.Name == name) is RecurringTask recurringTask && recurringTask.LastRun.HasValue)
{
return recurringTask.LastRun.Value;
}
return DateTime.MinValue;
}
/// <summary>
/// 获取任务计划下一次执行时间
/// </summary>
/// <param name="name"></param>
/// <param name="recurring"></param>
/// <returns></returns>
public DateTime GetNextTime(string name, bool recurring = false)
{
if (!recurring)
{
if (_tasks.FirstOrDefault(t => t.Name == name) is ScheduledTask task)
{
DateTime today = DateTime.Today.Add(task.TimeOfDay);
return task.IsTodayRun ? today.AddDays(1) : today;
}
else if (_recurringTasks.FirstOrDefault(t => t.Name == name) is RecurringTask recurringTask)
{
return recurringTask.NextRun;
}
}
else if (_recurringTasks.FirstOrDefault(t => t.Name == name) is RecurringTask recurringTask)
{
return recurringTask.NextRun;
}
return DateTime.MaxValue;
}
public string GetRunTimeInfo(string name)
{
DateTime last = GetLastTime(name);
DateTime next = GetNextTime(name);
string msg = "";
if (last != DateTime.MinValue)
{
msg += $"上次运行时间:{last.ToString(General.GeneralDateTimeFormat)}\r\n";
}
if (next != DateTime.MaxValue)
{
msg += $"下次运行时间:{next.ToString(General.GeneralDateTimeFormat)}\r\n";
}
if (msg != "")
{
msg = $"任务计划:{name}\r\n{msg}";
}
else
{
msg = $"任务计划 {name} 不存在!";
}
return msg.Trim();
}
/// <summary>
/// 执行任务
/// </summary>
private void CheckAndRunTasks()
{
lock (_lock)
{
DateTime now = DateTime.Now;
foreach (ScheduledTask task in _tasks)
{
if (!task.IsTodayRun)
{
if (now.TimeOfDay >= task.TimeOfDay && now.TimeOfDay < task.TimeOfDay.Add(TimeSpan.FromSeconds(10)))
{
task.LastRun = now;
Task.Run(() =>
{
try
{
task.Action();
}
catch (Exception ex)
{
task.Error = ex;
}
});
}
}
}
foreach (RecurringTask recurringTask in _recurringTasks)
{
if (now >= recurringTask.NextRun)
{
recurringTask.LastRun = now;
recurringTask.NextRun = recurringTask.NextRun.Add(recurringTask.Interval);
Task.Run(() =>
{
try
{
recurringTask.Action();
}
catch (Exception ex)
{
recurringTask.Error = ex;
}
});
}
}
}
}
}
}