You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
haoliang-net/Api/CollectorApiServer.cs

134 lines
4.4 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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);
}
}
}