using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using GrasscutterTools.Properties; using GrasscutterTools.Utils; using Newtonsoft.Json; namespace GrasscutterTools.Pages { internal partial class PageTasks : BasePage { public override string Text => Resources.PageTasksTitle; public PageTasks() { InitializeComponent(); ListTasks.FullRowSelect = true; if (DesignMode) return; InitTasks(); } /// /// 循环任务 /// private class LoopTask { /// /// 任务标签 /// public string Tag { get; set; } /// /// 任务内容 /// public string Content { get; set; } /// /// 延迟时间(秒) /// public int DelayS { get; set; } /// /// 触发次数 -1为无限循环 /// public int TriggerCount { get; set; } } /// /// 任务列表路径 /// private readonly string TasksJsonPath = Common.GetAppDataFile("Tasks.json"); /// /// 任务集合 /// private List Tasks; /// /// 运行中的任务集合 /// private readonly ConcurrentDictionary RunningTasks = new ConcurrentDictionary(); /// /// 初始化任务集合 /// private void InitTasks() { if (File.Exists(TasksJsonPath)) { try { Tasks = JsonConvert.DeserializeObject>(File.ReadAllText(TasksJsonPath)); ListTasks.Items.AddRange(Tasks.Select(TaskToViewItem).ToArray()); } catch (Exception ex) { Tasks = new List(); Logger.W(Name, "Parsing Tasks json failed", ex); } } else { Tasks = new List(); } } /// /// 关闭时触发 /// public override void OnClosed() { // 取消所有正在运行的任务 foreach (var cs in RunningTasks.Values) cs.Cancel(); // 清空列表 RunningTasks.Clear(); // 保存任务列表 File.WriteAllText(TasksJsonPath, JsonConvert.SerializeObject(Tasks)); } /// /// 任务转为列表项 /// /// 任务 /// 列表项 private static ListViewItem TaskToViewItem(LoopTask task) => new ListViewItem(new string[] { task.Tag, task.Content, TimeSpan.FromSeconds(task.DelayS).ToString(), task.TriggerCount.ToString(), }); /// /// 列表选中项改变时触发 /// private void ListTasks_SelectedIndexChanged(object sender, EventArgs e) { if (ListTasks.SelectedIndices.Count == 0) return; int i = ListTasks.SelectedIndices[0]; var task = Tasks[i]; TxtTag.Text = task.Tag; DTPDelay.Value = DateTime.Today.Add(TimeSpan.FromSeconds(task.DelayS)); NUDTriggerCount.Value = task.TriggerCount; // 设置命令 SetCommand(task.Content); } /// /// 点击确定按钮时触发 /// private void BtnAccept_Click(object sender, EventArgs e) { var tag = TxtTag.Text.Trim(); var commands = GetCommand(); var delay = DTPDelay.Value.TimeOfDay; var count = (int)NUDTriggerCount.Value; if (string.IsNullOrEmpty(tag) || string.IsNullOrEmpty(commands) || delay.Ticks == 0) { MessageBox.Show(Resources.EmptyInputTip, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 查找是否已经存在 var i = Tasks.FindIndex(t => t.Tag == tag); if (i == -1) { // 新建任务 var t = new LoopTask { Tag = tag, Content = commands, DelayS = (int)delay.TotalSeconds, TriggerCount = count, }; ListTasks.Items.Add(TaskToViewItem(t)); Tasks.Add(t); } else { // 已存在的任务,确认是否正在运行中 if (ListTasks.Items[i].Checked || RunningTasks.ContainsKey(tag)) { MessageBox.Show(Resources.TaskRunningCannotOperated, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 否则修改任务内容 var task = Tasks[i]; task.Content = commands; task.DelayS = (int)delay.TotalSeconds; task.TriggerCount = count; ListTasks.Items[i] = TaskToViewItem(task); } } /// /// 点击删除按钮时触发 /// private void BtnRemove_Click(object sender, EventArgs e) { var tag = TxtTag.Text.Trim(); // 查找是否已经存在 var i = Tasks.FindIndex(t => t.Tag == tag); if (i == -1) return; if (ListTasks.Items[i].Checked || RunningTasks.ContainsKey(tag)) { MessageBox.Show(Resources.TaskRunningCannotOperated, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // 删除实例 ListTasks.Items.RemoveAt(i); Tasks.RemoveAt(i); } /// /// 任务前复选框改变时触发 /// private void ListTasks_ItemChecked(object sender, ItemCheckedEventArgs e) { try { var item = e.Item; if (item.Index < 0 || item.Index >= Tasks.Count) return; var task = Tasks[item.Index]; // 先将旧的任务取消 if (RunningTasks.TryRemove(task.Tag, out var source)) source.Cancel(); if (item.Checked) { var cancelSource = new CancellationTokenSource(); RunningTasks.TryAdd(task.Tag, cancelSource); var token = cancelSource.Token; Task.Run(async () => { try { Logger.I(Name, $"Task \"{task.Tag}\" started"); // 循环执行命令 for (int c = 0; !token.IsCancellationRequested && (c < task.TriggerCount || task.TriggerCount <= 0); c++) { // 延迟 await Task.Delay(task.DelayS * 1000, token); // 使用UI线程执行 var ret = Invoke(new Func>(RunRawCommands), task.Content); if (ret is Task b && b.Result == false) break; // 执行 //if (!await RunRawCommands(task.Content)) // break; } } finally { // 任务结束后取消勾选状态 BeginInvoke(new Action(() => item.Checked = false)); Logger.I(Name, $"Task \"{task.Tag}\" stoped"); } }, token); } } catch (Exception ex) { Logger.E(Name, "Start or Stop Task failed.", ex); MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// 任务标签输入栏改变时触发 /// private void TxtTag_TextChanged(object sender, EventArgs e) { LblClearFilter.Visible = TxtTag.Text.Length > 0; } /// /// 点击清空任务标签输入栏标签时触发 /// private void LblClearFilter_Click(object sender, EventArgs e) { TxtTag.Clear(); } } }