using System.Net; using System.Text; using IBKRTrader.Core.Database; using IBKRTrader.Core.Logging; using IBKRTrader.Core.Settings; namespace IBKRTrader.Core.Workers.BuiltIn; /// /// WebserverService – permanenter Service auf Basis von System.Net.HttpListener. /// Lauscht auf http://localhost:{port}/ und liefert einen Status-JSON. /// Wird später durch vollständige Web-UI erweitert. /// public class WebserverService : WorkerBase { private readonly SettingsService _settings; private HttpListener? _listener; public override string Name => "WebserverService"; public override string Module => "Core"; public override WorkerType Type => WorkerType.Service; protected override TimeSpan? Interval => null; // Service = permanent public WebserverService(LoggingService logger, DatabaseService db, SettingsService settings) : base(logger, db) { _settings = settings; Info.Active = settings.Settings.Webserver.Enabled; Info.RunEvery = "Service"; } protected override async Task ExecuteAsync(CancellationToken ct) { var port = _settings.Settings.Webserver.Port; _listener = new HttpListener(); _listener.Prefixes.Add($"http://localhost:{port}/"); try { _listener.Start(); Logger.Info(Module, $"Webserver gestartet auf http://localhost:{port}/"); Info.Info = $"http://localhost:{port}/"; while (!ct.IsCancellationRequested) { // GetContextAsync blockiert – abbrechen via ct var contextTask = _listener.GetContextAsync(); var cancelTask = Task.Delay(Timeout.Infinite, ct); var completed = await Task.WhenAny(contextTask, cancelTask); if (completed == cancelTask) break; var ctx = await contextTask; _ = HandleRequestAsync(ctx); // fire-and-forget pro Request } } finally { _listener.Stop(); Logger.Info(Module, "Webserver gestoppt."); } } private async Task HandleRequestAsync(HttpListenerContext ctx) { try { const string json = """{"status":"ok","app":"IBKRTrader","version":"1.0.0"}"""; var bytes = Encoding.UTF8.GetBytes(json); ctx.Response.ContentType = "application/json"; ctx.Response.ContentLength64 = bytes.Length; ctx.Response.StatusCode = 200; await ctx.Response.OutputStream.WriteAsync(bytes); ctx.Response.Close(); } catch { /* Client hat getrennt */ } } }