using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace IvfTl.ControlHost
{
///
/// control 进程内的本地 HTTP 小服务,只监听 127.0.0.1:port。
/// 阶段1:/ping、/status。阶段2 扩展 /serial/pause|resume、/shutdown。
///
public class ControlHttpServer
{
private readonly int _port;
private readonly Func _statusProvider;
private readonly Action _log;
private HttpListener _listener;
private CancellationTokenSource _cts;
public ControlHttpServer(int port, Func statusProvider, Action 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); }
}
}
}