using ControlPlane.Core.Config; using ControlPlane.Core.Interfaces; using ControlPlane.Core.Services; using ControlPlane.Worker; using ControlPlane.Worker.Services; using ControlPlane.Worker.Steps; using Keycloak.AuthServices.Sdk; using MassTransit; using Npgsql; var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); // Centralized infrastructure options — domain, network, internal URLs, cert paths builder.Services.Configure( builder.Configuration.GetSection(ClarityInfraOptions.Section)); // Keycloak Admin SDK client builder.Services.AddKeycloakAdminHttpClient(o => { o.AuthServerUrl = builder.Configuration["Keycloak:AuthServerUrl"] ?? "http://localhost:8080"; o.Realm = builder.Configuration["Keycloak:Realm"] ?? "master"; o.Resource = builder.Configuration["Keycloak:Resource"] ?? "admin-cli"; }); // Custom admin client - handles realm creation, roles, role assignment (not in SDK) builder.Services.AddSingleton(); // Named HttpClient for Gitea commit status API (self-signed cert) builder.Services.AddHttpClient("gitea").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }); // opcdb for build/release history tracking var opcConnStr = builder.Configuration.GetConnectionString("opcdb"); builder.Services.AddSingleton(NpgsqlDataSource.Create( !string.IsNullOrWhiteSpace(opcConnStr) ? opcConnStr : "Host=127.0.0.1;Port=5433;Database=opcdb;Username=postgres;Password=controlplane-dev")); builder.Services.AddSingleton(); // Docker container manager for per-tenant Clarity.Server instances builder.Services.AddSingleton(); // Tenant registry - persists provisioned tenant XML files to ClientAssets folder builder.Services.AddSingleton(); // Saga steps in execution order — container launches LAST once all context is populated builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddMassTransit(x => { x.SetKebabCaseEndpointNameFormatter(); x.AddConsumer(); x.AddConsumer(); x.UsingRabbitMq((ctx, cfg) => { cfg.Host(builder.Configuration.GetConnectionString("rabbitmq")); cfg.ConfigureEndpoints(ctx); }); }); try { var host = builder.Build(); host.Run(); } catch (Exception ex) { Console.Error.WriteLine($"FATAL WORKER CRASH: {ex}"); throw; }