using Deal.Grpc.Hosting.Interceptors; using Deal.Grpc.Hosting.Models; using Deal.Grpc.Hosting.Options; using Deal.Grpc.Hosting.Services; using Deal.Telegram.Core; using Deal.Telegram.Dialogs; using Deal.Telegram.Discovery; using Deal.Telegram.Hosting; using Deal.Telegram.Sessions; using Deal.Telegram.Telegram; namespace Deal.Telegram; /// /// Собирает WebApplication gRPC-хоста telegram-service. /// public static class TelegramServiceHost { /// /// Создаёт (не запускает) хост /// /// TCP-порт Kestrel. /// Аргументы командной строки (Program.cs); в тестах не нужны. /// Опциональный хук DI для тестов (подмена зависимостей фейками, напр. ITelegramClientFactory). /// Опциональный хук конфигурации билдера для production-точки входа (Program.cs): Serilog. Тесты хост поднимают БЕЗ этого хука — логирование файлов/консоли тестам не нужно. /// Собранный хост; запуск — StartAsync/RunAsync у вызывающего. public static WebApplication Create( int grpcPort, string[]? args = null, Action? configureServices = null, Action? configureBuilder = null) { WebApplicationBuilder builder = WebApplication.CreateBuilder(args ?? []); // Общая серверная обвязка (Deal.Grpc.Hosting, C31): mTLS env DEAL_MTLS_* — загрузка // сертификатов сразу с fail-fast (compose-prod монтирует deploy/certs, scripts/mtls-certs.sh); // Один экземпляр mtlsCertificates используют и Kestrel ниже, и исходящий канал в ядро // (CoreIngressClient). MtlsCertificates? mtlsCertificates = GrpcServer.LoadMtlsCertificates(builder); GrpcServer.ConfigureKestrelHttp2Endpoint(builder, grpcPort, mtlsCertificates); builder.Services.AddDealGrpcServer(); builder.Services.AddReadyHealthCheck("хост telegram-service готов"); // файлов data/sessions/.session (AES-GCM, ключ из env), пул 1 аккаунт/тенант и // фоновый цикл auto_resume/heartbeat (30 с). DEAL_TELEGRAM_SESSION_KEY обязателен — // иначе хост не стартует (сессии не могут храниться в открытом виде). TgOptions sessionOptions = TgOptions.FromConfiguration(builder.Configuration, builder.Environment); builder.Services.AddSingleton(sessionOptions); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); CoreIngressOptions ingressOptions = CoreIngressOptions.FromConfiguration(builder.Configuration); builder.Services.AddSingleton(ingressOptions); builder.Services.AddSingleton(provider => new CoreIngressClient( ingressOptions, provider.GetRequiredService>(), mtlsCertificates)); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); configureServices?.Invoke(builder.Services); configureBuilder?.Invoke(builder); WebApplication app = builder.Build(); app.MapGrpcService(); app.MapGrpcHealthChecksService(); return app; } }