using IBKRTrader.Core.Logging;
using IBKRTrader.Core.Modularity;
using IBKRTrader.Core.Settings;
using IBKRTrader.Core.Trading;
using IBKRTrader.Core.Workers;
using IBKRTrader.Hosting;
using IBKRTrader.UI;
using IBKRTrader.UI.Views;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace IBKRTrader;
///
/// Einstiegspunkt der WinForms-Shell (Windows).
///
/// Der Host selbst kommt aus und ist plattformneutral – hier
/// wird er nur um Fensterverwaltung und Launcher ergänzt. Derselbe Host trägt den kopflosen
/// Linux-Dienst IBKRTrader.Daemon; so kann keine der beiden Varianten eine Registrierung
/// vergessen.
///
internal static class Program
{
public static IHost? AppHost { get; private set; }
[STAThread]
static void Main(string[] args)
{
// Headless-Smoke-Test der UI (konstruiert jede View + Launcher, ohne Message-Loop).
if (args.Length > 0 && string.Equals(args[0], "--smoke-ui", StringComparison.OrdinalIgnoreCase))
{
Environment.ExitCode = RunSmokeUi();
return;
}
ApplicationConfiguration.Initialize();
var modules = AppHostBuilder.CreateModules();
AppHost = AppHostBuilder.Build(modules, RegisterShellServices);
AppHostBuilder.RunStartupChecks(AppHost.Services);
// Host starten → alle Worker/Services (IHostedService) laufen an.
AppHost.Start();
// Views registrieren (Core + Module), dann Launcher starten.
var uiHost = AppHost.Services.GetRequiredService();
RegisterCoreViews(uiHost, AppHost.Services);
foreach (var module in modules)
module.RegisterUi(uiHost, AppHost.Services);
ModuleViews.Register(uiHost, AppHost.Services);
ViewIcons.AssignDefaults(uiHost);
Application.Run(AppHost.Services.GetRequiredService());
AppHost.StopAsync().GetAwaiter().GetResult();
}
/// Nur die Dienste, die es ohne Oberfläche nicht gibt.
private static void RegisterShellServices(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton();
services.AddSingleton(sp => sp.GetRequiredService());
services.AddSingleton();
}
/// Registriert die Core-Views (Dashboard, Workers, Logs, Settings) bei der Shell.
private static void RegisterCoreViews(IModuleUiHost uiHost, IServiceProvider sp)
{
uiHost.RegisterView(new ModuleView
{
Id = "core.dashboard", Title = "Dashboard", Group = "Core", Order = 5,
CreateView = () => new DashboardView(
sp.GetRequiredService(),
sp.GetRequiredService(),
sp.GetServices(),
sp.GetRequiredService(),
sp.GetServices())
});
uiHost.RegisterView(new ModuleView
{
Id = "core.workers", Title = "Workers / Services", Group = "Core", Order = 10,
CreateView = () => new WorkersView(sp.GetRequiredService())
});
uiHost.RegisterView(new ModuleView
{
Id = "core.logs", Title = "Logs", Group = "Core", Order = 20,
CreateView = () => new LogsView(sp.GetRequiredService())
});
uiHost.RegisterView(new ModuleView
{
Id = "core.settings", Title = "Settings", Group = "Core", Order = 30,
CreateView = () => new SettingsView(sp.GetRequiredService())
});
}
///
/// Headless-Smoke-Test: baut den Host, registriert Views + Modul-UI und konstruiert jede
/// registrierte View sowie den Launcher – ohne Message-Loop. Gibt die Fehleranzahl zurück.
/// Der Host wird bewusst NICHT gestartet: sonst liefen Worker und Broker-Verbindungen an,
/// was für eine reine Konstruktionsprüfung unerwünscht ist.
///
private static int RunSmokeUi()
{
ApplicationConfiguration.Initialize();
var modules = AppHostBuilder.CreateModules();
using var host = AppHostBuilder.Build(modules, RegisterShellServices);
AppHostBuilder.RunStartupChecks(host.Services);
var uiHost = host.Services.GetRequiredService();
RegisterCoreViews(uiHost, host.Services);
foreach (var module in modules)
module.RegisterUi(uiHost, host.Services);
ModuleViews.Register(uiHost, host.Services);
ViewIcons.AssignDefaults(uiHost);
var failures = 0;
Console.WriteLine("=== Smoke-UI: View-Konstruktion ===");
foreach (var view in uiHost.Views)
{
try { using var form = (Form)view.CreateView(); Console.WriteLine($"[OK] {view.Id} ({view.Title})"); }
catch (Exception ex) { failures++; Console.WriteLine($"[FEHLER] {view.Id}: {ex.GetType().Name}: {ex.Message}"); }
}
try { using var launcher = host.Services.GetRequiredService(); Console.WriteLine("[OK] LauncherForm konstruiert"); }
catch (Exception ex) { failures++; Console.WriteLine($"[FEHLER] LauncherForm: {ex.GetType().Name}: {ex.Message}"); }
Console.WriteLine(failures == 0 ? "=== Smoke-UI OK ===" : $"=== Smoke-UI: {failures} Fehler ===");
return failures;
}
}