|
@@ -6,6 +6,7 @@ using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json;
|
|
|
using Newtonsoft.Json.Linq;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
+using IvfTl.ControlHost.Debug;
|
|
|
|
|
|
|
|
namespace IvfTl.ControlHost
|
|
namespace IvfTl.ControlHost
|
|
|
{
|
|
{
|
|
@@ -22,6 +23,7 @@ namespace IvfTl.ControlHost
|
|
|
private readonly Func<int, bool> _serialPauseHandler; // /serial/pause(借串口:control 让路该舱)
|
|
private readonly Func<int, bool> _serialPauseHandler; // /serial/pause(借串口:control 让路该舱)
|
|
|
private readonly Func<int, bool> _serialResumeHandler; // /serial/resume(归还:恢复采集)
|
|
private readonly Func<int, bool> _serialResumeHandler; // /serial/resume(归还:恢复采集)
|
|
|
private readonly Action<string> _log;
|
|
private readonly Action<string> _log;
|
|
|
|
|
+ private readonly DebugSessionManager _debug;
|
|
|
private HttpListener _listener;
|
|
private HttpListener _listener;
|
|
|
private CancellationTokenSource _cts;
|
|
private CancellationTokenSource _cts;
|
|
|
|
|
|
|
@@ -32,7 +34,8 @@ namespace IvfTl.ControlHost
|
|
|
Func<string, bool> shutdownHandler,
|
|
Func<string, bool> shutdownHandler,
|
|
|
Func<int, bool> serialPauseHandler,
|
|
Func<int, bool> serialPauseHandler,
|
|
|
Func<int, bool> serialResumeHandler,
|
|
Func<int, bool> serialResumeHandler,
|
|
|
- Action<string> log)
|
|
|
|
|
|
|
+ Action<string> log,
|
|
|
|
|
+ DebugSessionManager debug = null)
|
|
|
{
|
|
{
|
|
|
_port = port;
|
|
_port = port;
|
|
|
_pingProvider = pingProvider;
|
|
_pingProvider = pingProvider;
|
|
@@ -41,6 +44,7 @@ namespace IvfTl.ControlHost
|
|
|
_serialPauseHandler = serialPauseHandler;
|
|
_serialPauseHandler = serialPauseHandler;
|
|
|
_serialResumeHandler = serialResumeHandler;
|
|
_serialResumeHandler = serialResumeHandler;
|
|
|
_log = log ?? (_ => { });
|
|
_log = log ?? (_ => { });
|
|
|
|
|
+ _debug = debug;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void Start()
|
|
public void Start()
|
|
@@ -101,6 +105,40 @@ namespace IvfTl.ControlHost
|
|
|
body = "{\"ok\":" + (ok ? "true" : "false") + ",\"houseSn\":" + houseSn + (ok ? "" : ",\"error\":\"bad houseSn or handler\"") + "}";
|
|
body = "{\"ok\":" + (ok ? "true" : "false") + ",\"houseSn\":" + houseSn + (ok ? "" : ",\"error\":\"bad houseSn or handler\"") + "}";
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
+ case "/debug/acquire":
|
|
|
|
|
+ if (method != "POST") { code = 405; body = Err("method not allowed"); break; }
|
|
|
|
|
+ {
|
|
|
|
|
+ int houseSn = ReadIntField(ctx, "houseSn");
|
|
|
|
|
+ var r = _debug != null ? _debug.Acquire(houseSn) : DebugCommandResult.Fail("NO_HANDLE", "debug 未装配");
|
|
|
|
|
+ code = r.Ok ? 200 : 409; body = JsonConvert.SerializeObject(r);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "/debug/heartbeat":
|
|
|
|
|
+ if (method != "POST") { code = 405; body = Err("method not allowed"); break; }
|
|
|
|
|
+ {
|
|
|
|
|
+ var r = _debug != null ? _debug.Heartbeat(ReadField(ctx, "sessionId")) : DebugCommandResult.Fail("SESSION_EXPIRED", "debug 未装配");
|
|
|
|
|
+ code = r.Ok ? 200 : 410; body = JsonConvert.SerializeObject(r);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "/debug/release":
|
|
|
|
|
+ if (method != "POST") { code = 405; body = Err("method not allowed"); break; }
|
|
|
|
|
+ {
|
|
|
|
|
+ var r = _debug != null ? _debug.Release(ReadField(ctx, "sessionId")) : DebugCommandResult.Okay();
|
|
|
|
|
+ code = 200; body = JsonConvert.SerializeObject(r);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case "/debug/command":
|
|
|
|
|
+ if (method != "POST") { code = 405; body = Err("method not allowed"); break; }
|
|
|
|
|
+ {
|
|
|
|
|
+ var jo = ReadBody(ctx);
|
|
|
|
|
+ string sid = jo?["sessionId"]?.ToString();
|
|
|
|
|
+ string op = jo?["op"]?.ToString();
|
|
|
|
|
+ var argsObj = jo?["args"] as Newtonsoft.Json.Linq.JObject;
|
|
|
|
|
+ var r = _debug != null ? _debug.Execute(sid, op, argsObj) : DebugCommandResult.Fail("SESSION_EXPIRED", "debug 未装配");
|
|
|
|
|
+ code = r.Ok ? 200 : (r.Code == "SESSION_EXPIRED" ? 410 : (r.Code == "OUT_OF_RANGE" ? 400 : 200));
|
|
|
|
|
+ body = JsonConvert.SerializeObject(r);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
default:
|
|
default:
|
|
|
code = 404; body = Err("not found");
|
|
code = 404; body = Err("not found");
|
|
|
break;
|
|
break;
|
|
@@ -137,6 +175,20 @@ namespace IvfTl.ControlHost
|
|
|
return int.TryParse(s, out int v) ? v : -1;
|
|
return int.TryParse(s, out int v) ? v : -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// <summary>把 POST body 整体解析为 JObject(失败返回 null)。/debug/command 多字段用。</summary>
|
|
|
|
|
+ private Newtonsoft.Json.Linq.JObject ReadBody(HttpListenerContext ctx)
|
|
|
|
|
+ {
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ using (var sr = new StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding ?? Encoding.UTF8))
|
|
|
|
|
+ {
|
|
|
|
|
+ string raw = sr.ReadToEnd();
|
|
|
|
|
+ return string.IsNullOrEmpty(raw) ? null : Newtonsoft.Json.Linq.JObject.Parse(raw);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex) { _log("解析 body 异常:" + ex.Message); return null; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public void Stop()
|
|
public void Stop()
|
|
|
{
|
|
{
|
|
|
try { _cts?.Cancel(); _listener?.Stop(); _listener?.Close(); }
|
|
try { _cts?.Cancel(); _listener?.Stop(); _listener?.Close(); }
|