194 lines
7.7 KiB
C#
194 lines
7.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using LessokajiWeaverUtilities.Utilities;
|
|
using Newtonsoft.Json;
|
|
using SimpleCore;
|
|
using SimpleCore.Library;
|
|
using SimpleLite.RCS;
|
|
using StandardScene.Signal.Logic;
|
|
using StandardScene.Signal.Model;
|
|
using StandardScene.Signal.Ui;
|
|
using StandardScene.Utils;
|
|
|
|
namespace StandardScene.Signal
|
|
{
|
|
/// <summary>
|
|
/// 磁条交管进程:只针对 MagCar。同区名排队后,按「本线 + 冲突对向线」站点并集查占用,容量允许则发启动。
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 配置 <c>Config/Signal/mag-control-areas.json</c>。
|
|
/// 同「管控区名称」绑成一个路口排队;放行时合并本线与冲突对向线的管控站点列表统计当前占用。
|
|
/// 不使用 pending 在途占额。不处理 Mag2Car。
|
|
/// </remarks>
|
|
[MissionType(Name = "磁条交管进程", editor = typeof(MagTrafficMission))]
|
|
[I18N.DocumentTranslation(Name = "Magnetic Traffic Mission", locale = "en")]
|
|
public class MagTrafficMission : Mission
|
|
{
|
|
/// <summary>扫车周期(毫秒)。停在触发点的 MagCar 每拍排队判定一次。</summary>
|
|
[FieldMember] public int TickMs = 1000;
|
|
|
|
/// <summary>管控区表路径。相对路径只解析工作目录 <c>Config/Signal</c>。</summary>
|
|
[FieldMember] public string AreasPath = @"Config\Signal\mag-control-areas.json";
|
|
|
|
/// <summary>放行日志根目录。实际按车名落在其下 mag-traffic/car{name}/release_yyyyMMdd.log。</summary>
|
|
[FieldMember] public string LogDirectory = "log";
|
|
|
|
/// <summary>是否把交管放行写入本地文件留档。</summary>
|
|
[FieldMember] public bool EnableFileLog = true;
|
|
|
|
[JsonIgnore] private bool _started;
|
|
[JsonIgnore] private readonly MagControlRuntime _runtime = new MagControlRuntime();
|
|
[JsonIgnore] private CancellationTokenSource _cts;
|
|
[JsonIgnore] private Thread _thread;
|
|
|
|
public class MagTrafficMissionStatus : MissionStatus
|
|
{
|
|
public int RuleCount { get; set; }
|
|
public int WaitingAtTrigger { get; set; }
|
|
public int PendingInFlight { get; set; }
|
|
public int ScanTickCount { get; set; }
|
|
public string AreasFile { get; set; }
|
|
}
|
|
|
|
public override MissionStatus status { get; set; } = new MagTrafficMissionStatus();
|
|
|
|
public static Mission Create() => new MagTrafficMission();
|
|
|
|
[MethodMember(Name = "启动进程", Description = "加载管控区表,按区名排队后对 MagCar 发放行")]
|
|
public override void Execute()
|
|
{
|
|
try
|
|
{
|
|
MagTrafficFileLogger.Configure(LogDirectory, EnableFileLog);
|
|
ReloadConfig();
|
|
_started = true;
|
|
StartWatch();
|
|
MagTrafficFileLogger.WriteSystem($"进程启动 规则={((MagTrafficMissionStatus)status).RuleCount} 配置={((MagTrafficMissionStatus)status).AreasFile}");
|
|
Diagnosis.Post(
|
|
$"磁条交管进程已启动,规则={((MagTrafficMissionStatus)status).RuleCount}(仅 MagCar),放行日志={MagTrafficFileLogger.GetLogDirectory()}",
|
|
"MagTraffic", true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
status.status = "启动失败";
|
|
Diagnosis.Post($"磁条交管进程启动失败:{ExceptionFormatter.FormatEx(ex)}", "MagTraffic", true);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
[MethodMember(Name = "重新加载配置", Description = "重新读取 mag-control-areas.json")]
|
|
public void ReloadConfig()
|
|
{
|
|
var file = SignalConfigStore.Resolve(AreasPath);
|
|
var rows = SignalConfigStore.Load<MagControlAreaModel>(file);
|
|
_runtime.Replace(rows);
|
|
|
|
var st = (MagTrafficMissionStatus)status;
|
|
st.AreasFile = file;
|
|
st.RuleCount = _runtime.RuleCount;
|
|
st.PendingInFlight = _runtime.PendingCount;
|
|
status.status = _started ? "运行中" : "配置已加载";
|
|
MagTrafficFileLogger.Configure(LogDirectory, EnableFileLog);
|
|
MagTrafficFileLogger.WriteSystem($"重新加载配置 规则={st.RuleCount} 文件={file}");
|
|
Diagnosis.Post($"磁条交管配置已加载:启用规则 {st.RuleCount} @ {file}", "MagTraffic", true);
|
|
}
|
|
|
|
[MethodMember(Name = "停止进程")]
|
|
public new void Stop()
|
|
{
|
|
_started = false;
|
|
StopWatch();
|
|
status.status = "已停止";
|
|
MagTrafficFileLogger.WriteSystem("进程停止");
|
|
Diagnosis.Post("磁条交管进程已停止", "MagTraffic", true);
|
|
}
|
|
|
|
[MethodMember(Name = "打开放行日志目录", Description = "打开 mag-traffic 目录(按 car{name} 分子目录),便于按车查阅放行记录")]
|
|
public void OpenReleaseLogFolder()
|
|
{
|
|
try
|
|
{
|
|
MagTrafficFileLogger.Configure(LogDirectory, EnableFileLog);
|
|
var dir = MagTrafficFileLogger.GetLogDirectory();
|
|
Directory.CreateDirectory(dir);
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
|
{
|
|
FileName = dir,
|
|
UseShellExecute = true
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
CycleUiHelper.Alert("错误", $"打开放行日志目录失败:{ex.Message}");
|
|
}
|
|
}
|
|
|
|
[MethodMember(Name = "打开管控区列表", Description = "编辑区名 / 兼容组 / 优先级 / 等待时长 / 触发点 / 区内站点 / 容量")]
|
|
public void OpenAreas()
|
|
{
|
|
try
|
|
{
|
|
var path = SignalConfigStore.Resolve(AreasPath);
|
|
ModelListPanel<MagControlAreaModel>.Open(
|
|
"磁条管控区配置",
|
|
path,
|
|
x => x == null ? "" : x.TriggerSit.ToString());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
CycleUiHelper.Alert("错误", $"打开管控区列表失败:{ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void StartWatch()
|
|
{
|
|
StopWatch();
|
|
_cts = new CancellationTokenSource();
|
|
_thread = new Thread(WatchLoop)
|
|
{
|
|
IsBackground = true,
|
|
Name = "MagTrafficWatch"
|
|
};
|
|
_thread.Start();
|
|
}
|
|
|
|
private void StopWatch()
|
|
{
|
|
try { _cts?.Cancel(); }
|
|
catch { }
|
|
try { _thread?.Join(2000); }
|
|
catch { }
|
|
_thread = null;
|
|
}
|
|
|
|
private void WatchLoop()
|
|
{
|
|
var token = _cts.Token;
|
|
var tick = 0;
|
|
var interval = Math.Max(200, TickMs);
|
|
while (!token.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
var (waiting, _) = _runtime.ScanAndRelease();
|
|
var st = (MagTrafficMissionStatus)status;
|
|
st.WaitingAtTrigger = waiting;
|
|
st.PendingInFlight = _runtime.PendingCount;
|
|
st.RuleCount = _runtime.RuleCount;
|
|
st.ScanTickCount = ++tick;
|
|
if (_started)
|
|
status.status = $"运行中 规则{st.RuleCount} 等待{waiting}";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Diagnosis.Log($"磁条交管扫车异常:{ex.Message}", "MagTraffic", true);
|
|
}
|
|
|
|
try { Thread.Sleep(interval); }
|
|
catch (ThreadInterruptedException) { break; }
|
|
}
|
|
}
|
|
}
|
|
}
|