using System; using System.Net; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using log4net; using CncCollector.Core; using System.IO; namespace CncCollector.Api { /// /// Lightweight HTTP API server,用于控制 CollectEngine 的状态与配置刷新。 /// public class CollectorApiServer { private readonly CollectorEngine _engine; private readonly string _apiKey; private readonly int _port; private readonly HttpListener _listener = new HttpListener(); private readonly ILog _log = LogManager.GetLogger(typeof(CollectorApiServer)); private Task _listenTask; private bool _running; public CollectorApiServer(CollectorEngine engine, string apiKey, int port = 0) { _engine = engine; _apiKey = apiKey; _port = port > 0 ? port : 8080; } public void Start() { var prefix = $"http://+:{_port}/api/collector/"; _listener.Prefixes.Add(prefix); _listener.Start(); _running = true; _log.Info("CollectorApiServer started on " + prefix); _listenTask = Task.Run(() => ListenLoop()); } public void Stop() { _running = false; _listener.Stop(); } private async Task ListenLoop() { while (_running) { try { var ctx = await _listener.GetContextAsync(); _ = Task.Run(() => ProcessRequest(ctx)); } catch (HttpListenerException) { // 监听关闭 break; } catch (Exception ex) { _log.Error("CollectorApiServer 处理请求异常", ex); } } } private void ProcessRequest(HttpListenerContext ctx) { var req = ctx.Request; var res = ctx.Response; // 简单的 API-Key 认证 if (!ValidateApiKey(req)) { res.StatusCode = 401; WriteJson(res, new { code = 1, message = "Unauthorized" }); return; } string path = req.Url.AbsolutePath.ToLower(); switch (req.HttpMethod) { case "GET": if (path.EndsWith("/status")) WriteJson(res, new { code = 0, message = "success", data = new { status = _engine.Status } }); else WriteJson(res, new { code = 0, message = "unknown endpoint" }); break; case "POST": if (path.EndsWith("/start")) { _engine.Start(); WriteJson(res, new { code = 0, message = "started" }); } else if (path.EndsWith("/stop")) { _engine.Stop(); WriteJson(res, new { code = 0, message = "stopped" }); } else if (path.EndsWith("/refresh")) { _engine.Refresh(); WriteJson(res, new { code = 0, message = "refreshed" }); } else { WriteJson(res, new { code = 0, message = "unknown endpoint" }); } break; default: res.StatusCode = 405; WriteJson(res, new { code = 1, message = "method not allowed" }); break; } } private bool ValidateApiKey(HttpListenerRequest req) { var header = req.Headers["X-Api-Key"]; return !string.IsNullOrEmpty(_apiKey) && string.Equals(_apiKey, header); } private void WriteJson(HttpListenerResponse res, object data) { var json = JsonConvert.SerializeObject(data); var buffer = Encoding.UTF8.GetBytes(json); res.ContentType = "application/json"; res.ContentLength64 = buffer.Length; res.OutputStream.Write(buffer, 0, buffer.Length); } } }