diff --git a/.gitignore b/.gitignore index 8153c72..35ac2be 100644 --- a/.gitignore +++ b/.gitignore @@ -230,6 +230,8 @@ Thumbs.db .idea/ # custom +# Ignore environment-specific appsettings, but allow .example files /**/**/appsettings.*.json +!/**/**/appsettings.*.json.example **/**/deployment.yml diff --git a/src/Nocr.TelegramListener.Host/Infrastructure/HostBuilderFactory.cs b/src/Nocr.TelegramListener.Host/Infrastructure/HostBuilderFactory.cs index 89b00e5..9773409 100644 --- a/src/Nocr.TelegramListener.Host/Infrastructure/HostBuilderFactory.cs +++ b/src/Nocr.TelegramListener.Host/Infrastructure/HostBuilderFactory.cs @@ -8,12 +8,24 @@ public class HostBuilderFactory where TStartup : class { var builder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(host => { host.UseStartup(); }) - .ConfigureAppConfiguration((_, configurationBuilder) => + .ConfigureAppConfiguration((context, configurationBuilder) => { if (!string.IsNullOrWhiteSpace(baseDirectory)) configurationBuilder.SetBasePath(baseDirectory); - configurationBuilder.AddJsonFile("appsettings.protected.json", optional: true, reloadOnChange: true); + // Configuration priority (low to high): + // 1. appsettings.json (already loaded by CreateDefaultBuilder) + // 2. appsettings.{Environment}.json (already loaded) + // 3. User Secrets (already loaded in Development) + // 4. Environment Variables (already loaded) ← highest priority + + // Debug mode: log configuration on startup + if (Environment.GetEnvironmentVariable("NOCR_DEBUG_MODE") == "true") + { + Console.WriteLine("[NOCR_DEBUG] Configuration debug mode enabled"); + Console.WriteLine($"[NOCR_DEBUG] Environment: {context.HostingEnvironment.EnvironmentName}"); + Console.WriteLine($"[NOCR_DEBUG] Base Path: {baseDirectory ?? configurationBuilder.Build().GetValue("ContentRoot") ?? "default"}"); + } }) .UseSerilog((ctx, logBuilder) => { diff --git a/src/Nocr.TelegramListener.Host/Infrastructure/Startup.cs b/src/Nocr.TelegramListener.Host/Infrastructure/Startup.cs index 10f1c57..247ff0b 100644 --- a/src/Nocr.TelegramListener.Host/Infrastructure/Startup.cs +++ b/src/Nocr.TelegramListener.Host/Infrastructure/Startup.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Options; using Nocr.TelegramListener.AppServices; +using Nocr.TelegramListener.AppServices.UpdateListeners; using Nocr.TelegramListener.Async.Api.Contracts.Events; using Nocr.TelegramListener.Core.Dates; using Nocr.TelegramListener.Core.Options; @@ -22,6 +23,12 @@ public class Startup public void ConfigureServices(IServiceCollection services) { + // Debug mode: log loaded configuration + if (Environment.GetEnvironmentVariable("NOCR_DEBUG_MODE") == "true") + { + LogConfigurationDebug(); + } + services.AddSingleton(); services.AddAppServices(Configuration); @@ -41,6 +48,41 @@ public class Startup .Routing(r => r.TypeBased())); } + private void LogConfigurationDebug() + { + Console.WriteLine("=== [NOCR_DEBUG] Configuration Values ==="); + + var rebusOptions = Configuration.GetSection(nameof(RebusRabbitMqOptions)); + Console.WriteLine($"[NOCR_DEBUG] RebusRabbitMqOptions:"); + Console.WriteLine($"[NOCR_DEBUG] ConnectionString: {MaskConnectionString(rebusOptions["ConnectionString"])}"); + Console.WriteLine($"[NOCR_DEBUG] InputQueueName: {rebusOptions["InputQueueName"]}"); + Console.WriteLine($"[NOCR_DEBUG] DirectExchangeName: {rebusOptions["DirectExchangeName"]}"); + Console.WriteLine($"[NOCR_DEBUG] TopicsExchangeName: {rebusOptions["TopicsExchangeName"]}"); + + var wtOptions = Configuration.GetSection(nameof(WTelegramClientOptions)); + Console.WriteLine($"[NOCR_DEBUG] WTelegramClientOptions:"); + Console.WriteLine($"[NOCR_DEBUG] ApiId: {wtOptions["ApiId"]}"); + Console.WriteLine($"[NOCR_DEBUG] ApiHash: {MaskSecret(wtOptions["ApiHash"])}"); + Console.WriteLine($"[NOCR_DEBUG] PhoneNumber: {MaskSecret(wtOptions["PhoneNumber"])}"); + + Console.WriteLine("=== [NOCR_DEBUG] End Configuration ==="); + } + + private static string MaskConnectionString(string? value) + { + if (string.IsNullOrEmpty(value)) return "(empty)"; + // Mask password in connection string: amqp://user:pass@host -> amqp://user:***@host + var masked = System.Text.RegularExpressions.Regex.Replace(value, @"(?<=://)([^:]+):([^@]+)(?=@)", m => $"{m.Groups[1].Value}:***"); + return masked; + } + + private static string MaskSecret(string? value) + { + if (string.IsNullOrEmpty(value)) return "(empty)"; + if (value.Length <= 4) return "***"; + return $"{value.Substring(0, 2)}...{value.Substring(value.Length - 2)}"; + } + public void Configure(IApplicationBuilder app) { var bus = app.ApplicationServices.GetRequiredService(); diff --git a/src/Nocr.TelegramListener.Host/appsettings.Development.json.example b/src/Nocr.TelegramListener.Host/appsettings.Development.json.example new file mode 100644 index 0000000..7b0ec54 --- /dev/null +++ b/src/Nocr.TelegramListener.Host/appsettings.Development.json.example @@ -0,0 +1,17 @@ +{ + // This file provides an example configuration for local VS Code debugging. + // Copy this file to appsettings.Development.json and fill in your actual values. + // Alternatively, use environment variables or User Secrets for sensitive data. + + "RebusRabbitMqOptions": { + // RabbitMQ connection string for local development + // Format: amqp://username:password@hostname:port/ + "ConnectionString": "amqp://admin:admin@localhost:5672/" + }, + "WTelegramClientOptions": { + // Telegram API credentials - obtain from https://my.telegram.org/apps + "ApiId": "YOUR_API_ID", + "ApiHash": "YOUR_API_HASH", + "PhoneNumber": "YOUR_PHONE_NUMBER" + } +} diff --git a/src/Nocr.TelegramListener.Host/appsettings.DockerCompose.json.example b/src/Nocr.TelegramListener.Host/appsettings.DockerCompose.json.example new file mode 100644 index 0000000..52527b6 --- /dev/null +++ b/src/Nocr.TelegramListener.Host/appsettings.DockerCompose.json.example @@ -0,0 +1,11 @@ +{ + // This file provides an example configuration for Docker Compose deployment. + // Copy this file to appsettings.DockerCompose.json (or use environment variables). + + "RebusRabbitMqOptions": { + // RabbitMQ connection string - use service name from docker-compose.yml + "ConnectionString": "amqp://admin:admin@nocr-rabbitmq:5672/" + } + // Note: WTelegramClientOptions should be provided via environment variables + // See docker-compose.yml or use .env file +}