ControlHttpServer.cs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. using System;
  2. using System.Net;
  3. using System.Text;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Newtonsoft.Json;
  7. namespace IvfTl.ControlHost
  8. {
  9. /// <summary>
  10. /// control 进程内的本地 HTTP 小服务,只监听 127.0.0.1:port。
  11. /// 阶段1:/ping、/status。阶段2 扩展 /serial/pause|resume、/shutdown。
  12. /// </summary>
  13. public class ControlHttpServer
  14. {
  15. private readonly int _port;
  16. private readonly Func<StatusDto> _statusProvider;
  17. private readonly Action<string> _log;
  18. private HttpListener _listener;
  19. private CancellationTokenSource _cts;
  20. public ControlHttpServer(int port, Func<StatusDto> statusProvider, Action<string> log)
  21. {
  22. _port = port;
  23. _statusProvider = statusProvider;
  24. _log = log ?? (_ => { });
  25. }
  26. public void Start()
  27. {
  28. _listener = new HttpListener();
  29. _listener.Prefixes.Add($"http://127.0.0.1:{_port}/");
  30. _listener.Start();
  31. _cts = new CancellationTokenSource();
  32. _log($"ControlHttpServer 监听 http://127.0.0.1:{_port}/");
  33. Task.Run(() => Loop(_cts.Token));
  34. }
  35. private async Task Loop(CancellationToken token)
  36. {
  37. while (!token.IsCancellationRequested)
  38. {
  39. HttpListenerContext ctx;
  40. try { ctx = await _listener.GetContextAsync(); }
  41. catch (Exception ex) { if (!token.IsCancellationRequested) _log("HttpListener 异常:" + ex.Message); break; }
  42. try { Handle(ctx); }
  43. catch (Exception ex) { _log("处理请求异常:" + ex.Message); }
  44. }
  45. }
  46. private void Handle(HttpListenerContext ctx)
  47. {
  48. string path = ctx.Request.Url.AbsolutePath.TrimEnd('/').ToLowerInvariant();
  49. string body;
  50. int code = 200;
  51. switch (path)
  52. {
  53. case "/ping":
  54. case "/status":
  55. body = JsonConvert.SerializeObject(_statusProvider());
  56. break;
  57. default:
  58. code = 404; body = "{\"ok\":false,\"error\":\"not found\"}";
  59. break;
  60. }
  61. byte[] buf = Encoding.UTF8.GetBytes(body);
  62. ctx.Response.StatusCode = code;
  63. ctx.Response.ContentType = "application/json";
  64. ctx.Response.ContentLength64 = buf.Length;
  65. ctx.Response.OutputStream.Write(buf, 0, buf.Length);
  66. ctx.Response.OutputStream.Close();
  67. }
  68. public void Stop()
  69. {
  70. try { _cts?.Cancel(); _listener?.Stop(); _listener?.Close(); }
  71. catch (Exception ex) { _log("ControlHttpServer 停止异常:" + ex.Message); }
  72. }
  73. }
  74. }