private static K2Config LoadConfig(string[] args) { string APP_SETTINGS_OVERRIDE_FILENAME = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json"; // build configuration ; https://stackoverflow.com/a/58594026 var builder = new ConfigurationBuilder() // configuration 순서 중요 .SetBasePath(GetBasePath()) // 파일을 읽기 전에 설정 .AddEnvironmentVariables() // 환경변수에 "K2:ServerId" 와 같은 형식의 값으로 사용 가능하도록 .AddJsonFile(APP_SETTINGS_FILENAME); // 환경변수 값을 json 으로 override 가능하도록 if (System.IO.File.Exists(APP_SETTINGS_OVERRIDE_FILENAME)) { builder.AddJsonFile(APP_SETTINGS_OVERRIDE_FILENAME); // 환경에 따른 json override } builder.AddCommandLine(args); // 모든 설정은 다시 commandline argument 로 override 가능. ex) K2:ListeningPort=1111 var configuration = builder.Build(); var config = configuration.GetSection(K2Config.SECTION_NAME).Get <K2Config>(); if (config == null) { config = new K2Config(); // create default (development environment) } if (config.HasServerManager) { // ServerManager 로 동작하는 경우 ServerManagerAddress 는 항상 자기 자신이어야 한다. 잘못설정한 경우 crash 가 맞나? config.ServerManagerAddress = $"{config.ServiceScheme}://localhost:{config.ListeningPort}"; } return(config); }
// Additional configuration is required to successfully run gRPC on macOS. // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 public static IHostBuilder CreateHostBuilder(string[] args, K2Config config) { return(Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder .UseKestrel(options => { options.ListenAnyIP(config.ListeningPort); }) .ConfigureServices(sc => { var backendHeader = new Grpc.Core.Metadata(); backendHeader.Add(nameof(config.BackendGroupId), config.BackendGroupId); // key 는 소문자로 변환되어 들어간다 // K2Config 종속적인 resource 들 ; asp.net core 3.0 이후 직접 StartUp 에 parameter 를 전달할 수 없음 (https://andrewlock.net/avoiding-startup-service-injection-in-asp-net-core-3/) sc.AddSingleton(config); sc.AddSingleton(backendHeader); }) .UseStartup <Startup>() ; })); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, K2Config localConfig, RemoteConfig remoteConfig, ILogger <Startup> logger) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // service blocker app.Use(async(context, next) => { // https://docs.microsoft.com/ko-kr/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1#middleware-class if (localConfig.HasServerManager == false && remoteConfig.Registered == false) { // 아직 grpc 서비스를 사용가능한 상태가 아님 logger.LogWarning($"not registered yet for {context.Request.Path}"); return; } await next(); }); // 여기(app.Use~ middleware) 순서 중요 ; https://docs.microsoft.com/ko-kr/aspnet/core/grpc/authn-and-authz?view=aspnetcore-3.1 app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { // TODO: reflection 으로 endpoints.MapGrpcService 을 자동화 // backend services(managers) if (localConfig.HasServerManager) { endpoints.MapGrpcService <Backend.ServerManagerBackend>(); } if (localConfig.HasSessionManager) { endpoints.MapGrpcService <Backend.SessionManagerBackend>(); } // hosts(backend client to backend service) // backend server 의 명령(push)을 받을 backend host 들 ; disable 될 수 없다.(항상 manager 의 request 에 응답해야 한다) endpoints.MapGrpcService <Backend.ServerHostBackend>(); endpoints.MapGrpcService <Backend.SessionHostBackend>(); // frontend services if (localConfig.HasInitService) { endpoints.MapGrpcService <Frontend.InitService>(); } if (localConfig.HasPushService) { endpoints.MapGrpcService <Frontend.PushService>(); } if (localConfig.HasPushSampleService) { endpoints.MapGrpcService <Frontend.PushSampleService>(); } if (localConfig.HasSimpleSampleService) { endpoints.MapGrpcService <Frontend.SimpleSampleService>(); } endpoints.MapGet("/", async context => { await context.Response.WriteAsync("invalid access"); }); }); }