Преглед изворни кода

feat(control): 内嵌 HttpListener 本地小服务(/ping /status)

阶段1-Task4:127.0.0.1 only,JSON 响应,Start/Stop 生命周期。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
huangjie пре 4 дана
родитељ
комит
e841269ac3
1 измењених фајлова са 80 додато и 0 уклоњено
  1. 80 0
      ivf_tl_operate_2.0/control/ivf_tl_ControlHost/ControlHttpServer.cs

+ 80 - 0
ivf_tl_operate_2.0/control/ivf_tl_ControlHost/ControlHttpServer.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace IvfTl.ControlHost
+{
+    /// <summary>
+    /// control 进程内的本地 HTTP 小服务,只监听 127.0.0.1:port。
+    /// 阶段1:/ping、/status。阶段2 扩展 /serial/pause|resume、/shutdown。
+    /// </summary>
+    public class ControlHttpServer
+    {
+        private readonly int _port;
+        private readonly Func<StatusDto> _statusProvider;
+        private readonly Action<string> _log;
+        private HttpListener _listener;
+        private CancellationTokenSource _cts;
+
+        public ControlHttpServer(int port, Func<StatusDto> statusProvider, Action<string> log)
+        {
+            _port = port;
+            _statusProvider = statusProvider;
+            _log = log ?? (_ => { });
+        }
+
+        public void Start()
+        {
+            _listener = new HttpListener();
+            _listener.Prefixes.Add($"http://127.0.0.1:{_port}/");
+            _listener.Start();
+            _cts = new CancellationTokenSource();
+            _log($"ControlHttpServer 监听 http://127.0.0.1:{_port}/");
+            Task.Run(() => Loop(_cts.Token));
+        }
+
+        private async Task Loop(CancellationToken token)
+        {
+            while (!token.IsCancellationRequested)
+            {
+                HttpListenerContext ctx;
+                try { ctx = await _listener.GetContextAsync(); }
+                catch (Exception ex) { if (!token.IsCancellationRequested) _log("HttpListener 异常:" + ex.Message); break; }
+                try { Handle(ctx); }
+                catch (Exception ex) { _log("处理请求异常:" + ex.Message); }
+            }
+        }
+
+        private void Handle(HttpListenerContext ctx)
+        {
+            string path = ctx.Request.Url.AbsolutePath.TrimEnd('/').ToLowerInvariant();
+            string body;
+            int code = 200;
+            switch (path)
+            {
+                case "/ping":
+                case "/status":
+                    body = JsonConvert.SerializeObject(_statusProvider());
+                    break;
+                default:
+                    code = 404; body = "{\"ok\":false,\"error\":\"not found\"}";
+                    break;
+            }
+            byte[] buf = Encoding.UTF8.GetBytes(body);
+            ctx.Response.StatusCode = code;
+            ctx.Response.ContentType = "application/json";
+            ctx.Response.ContentLength64 = buf.Length;
+            ctx.Response.OutputStream.Write(buf, 0, buf.Length);
+            ctx.Response.OutputStream.Close();
+        }
+
+        public void Stop()
+        {
+            try { _cts?.Cancel(); _listener?.Stop(); _listener?.Close(); }
+            catch (Exception ex) { _log("ControlHttpServer 停止异常:" + ex.Message); }
+        }
+    }
+}