|
|
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
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// Lightweight HTTP API server,用于控制 CollectEngine 的状态与配置刷新。
|
|
|
/// </summary>
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
}
|