From f6f0703cb3c9634f22b5b1f89e76eec2fa65e3f6 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 18 Sep 2025 01:02:25 +0800 Subject: [PATCH] :sparkles: Proper gRPC protocol --- DysonNetwork.Control/AppHost.cs | 20 ++- DysonNetwork.Shared/Auth/Startup.cs | 11 +- .../Http/KestrelConfiguration.cs | 45 +++++++ .../Registry/ServiceInjectionHelper.cs | 120 +++++++++++------- docker-compose.yaml | 25 +++- publish/docker-compose.yaml | 10 ++ 6 files changed, 167 insertions(+), 64 deletions(-) diff --git a/DysonNetwork.Control/AppHost.cs b/DysonNetwork.Control/AppHost.cs index 7a64e5c..ee70630 100644 --- a/DysonNetwork.Control/AppHost.cs +++ b/DysonNetwork.Control/AppHost.cs @@ -9,25 +9,35 @@ var cache = builder.AddRedis("cache"); var queue = builder.AddNats("queue").WithJetStream(); var ringService = builder.AddProject("ring") - .WithReference(queue); + .WithReference(queue) + .WithHttpHealthCheck() + .WithEndpoint(5001, 5001, "https", name: "grpc"); var passService = builder.AddProject("pass") .WithReference(cache) .WithReference(queue) - .WithReference(ringService); + .WithReference(ringService) + .WithHttpHealthCheck() + .WithEndpoint(5001, 5001, "https", name: "grpc"); var driveService = builder.AddProject("drive") .WithReference(cache) .WithReference(queue) .WithReference(passService) - .WithReference(ringService); + .WithReference(ringService) + .WithHttpHealthCheck() + .WithEndpoint(5001, 5001, "https", name: "grpc"); var sphereService = builder.AddProject("sphere") .WithReference(cache) .WithReference(queue) .WithReference(passService) - .WithReference(ringService); + .WithReference(ringService) + .WithHttpHealthCheck() + .WithEndpoint(5001, 5001, "https", name: "grpc"); var developService = builder.AddProject("develop") .WithReference(cache) .WithReference(passService) - .WithReference(ringService); + .WithReference(ringService) + .WithHttpHealthCheck() + .WithEndpoint(5001, 5001, "https", name: "grpc"); // Extra double-ended references ringService.WithReference(passService); diff --git a/DysonNetwork.Shared/Auth/Startup.cs b/DysonNetwork.Shared/Auth/Startup.cs index 9197c34..e0caf8c 100644 --- a/DysonNetwork.Shared/Auth/Startup.cs +++ b/DysonNetwork.Shared/Auth/Startup.cs @@ -1,4 +1,5 @@ using DysonNetwork.Shared.Proto; +using DysonNetwork.Shared.Registry; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -10,15 +11,7 @@ public static class DysonAuthStartup this IServiceCollection services ) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); - - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); + services.AddAuthService(); services.AddAuthentication(options => { diff --git a/DysonNetwork.Shared/Http/KestrelConfiguration.cs b/DysonNetwork.Shared/Http/KestrelConfiguration.cs index e3f0f38..e8534aa 100644 --- a/DysonNetwork.Shared/Http/KestrelConfiguration.cs +++ b/DysonNetwork.Shared/Http/KestrelConfiguration.cs @@ -20,8 +20,53 @@ public static class KestrelConfiguration builder.WebHost.ConfigureKestrel(options => { options.Limits.MaxRequestBodySize = maxRequestBodySize; + + // gRPC + options.ListenAnyIP(5001, listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + + var selfSignedCert = _CreateSelfSignedCertificate(); + listenOptions.UseHttps(selfSignedCert); + }); + + var httpPorts = configuration.GetValue("HTTP_PORTS", "5000") + .Split(',', StringSplitOptions.RemoveEmptyEntries) + .Select(p => int.Parse(p.Trim())) + .ToArray(); + + // Regular HTTP + foreach (var httpPort in httpPorts) + options.ListenAnyIP(httpPort, + listenOptions => { listenOptions.Protocols = HttpProtocols.Http1AndHttp2; }); }); return builder; } + + static X509Certificate2 _CreateSelfSignedCertificate() + { + using var rsa = RSA.Create(2048); + var certRequest = new CertificateRequest( + "CN=dyson.network", // Common Name for the certificate + rsa, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + // Add extensions (e.g., for server authentication) + certRequest.CertificateExtensions.Add( + new X509EnhancedKeyUsageExtension( + new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, // Server Authentication + false)); + + // Set validity period (e.g., 1 year) + var notBefore = DateTimeOffset.UtcNow.AddDays(-1); + var notAfter = notBefore.AddYears(1); + + var certificate = certRequest.CreateSelfSigned(notBefore, notAfter); + + // Export to PKCS#12 and load using X509CertificateLoader + var pfxBytes = certificate.Export(X509ContentType.Pfx); + return X509CertificateLoader.LoadPkcs12(pfxBytes, password: null); + } } \ No newline at end of file diff --git a/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs b/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs index 739d434..d948adf 100644 --- a/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs +++ b/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs @@ -8,72 +8,94 @@ public static class ServiceInjectionHelper { public static IServiceCollection AddRingService(this IServiceCollection services) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://ring"); - }); - + services + .AddGrpcClient(o => o.Address = new Uri("https://_grpc.ring")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + return services; } - + + public static IServiceCollection AddAuthService(this IServiceCollection services) + { + services + .AddGrpcClient(o => o.Address = new Uri("https://_grpc.pass")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + + services + .AddGrpcClient(o => o.Address = new Uri("https://_grpc.pass")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + + return services; + } + public static IServiceCollection AddAccountService(this IServiceCollection services) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); + services + .AddGrpcClient(o => o.Address = new Uri("https://_grpc.pass") ) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); services.AddSingleton(); - - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); - - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); - - services.AddGrpcClient(o => - { - o.Address = new Uri("https://pass"); - }); - + + services + .AddGrpcClient(o => + o.Address = new Uri("https://_grpc.pass") + ) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.pass")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.pass")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + return services; } - + public static IServiceCollection AddDriveService(this IServiceCollection services) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://drive"); - }); - - services.AddGrpcClient(o => - { - o.Address = new Uri("https://drive"); - }); - + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.drive")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.drive")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + return services; } - + public static IServiceCollection AddPublisherService(this IServiceCollection services) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://sphere"); - }); - + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.sphere")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + return services; } public static IServiceCollection AddDevelopService(this IServiceCollection services) { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://develop"); - }); - + services.AddGrpcClient(o => o.Address = new Uri("https://_grpc.develop")) + .ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler() + { ServerCertificateCustomValidationCallback = (_, _, _, _) => true } + ); + return services; } - } \ No newline at end of file +} \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 45745be..a4aa669 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -40,9 +40,11 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${RING_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" - OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire:18889" + services__pass__grpc__0: "https://pass:5001" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "ring" volumes: @@ -50,6 +52,7 @@ services: - "./settings/ring.json:/app/appsettings.json" expose: - "${RING_PORT}" + - "5001" networks: - "aspire" pass: @@ -60,9 +63,11 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${PASS_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__ring__http__0: "http://ring:${RING_PORT}" + services__ring__grpc__0: "https://ring:5001" OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "pass" @@ -71,6 +76,7 @@ services: - "./settings/pass.json:/app/appsettings.json" expose: - "${PASS_PORT}" + - "5001" networks: - "aspire" drive: @@ -81,15 +87,19 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${DRIVE_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" + services__pass__grpc__0: "https://pass:5001" services__ring__http__0: "http://ring:${RING_PORT}" + services__ring__grpc__0: "https://ring:5001" OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "drive" expose: - "${DRIVE_PORT}" + - "5001" volumes: - "./settings/drive.json:/app/appsettings.json" networks: @@ -102,10 +112,13 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${SPHERE_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" + services__pass__grpc__0: "https://pass:5001" services__ring__http__0: "http://ring:${RING_PORT}" + services__ring__grpc__0: "https://ring:5001" OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "sphere" @@ -114,6 +127,7 @@ services: - "./settings/sphere.json:/app/appsettings.json" expose: - "${SPHERE_PORT}" + - "5001" networks: - "aspire" develop: @@ -124,14 +138,18 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${DEVELOP_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" services__pass__http__0: "http://pass:${PASS_PORT}" + services__pass__grpc__0: "https://pass:5001" services__ring__http__0: "http://ring:${RING_PORT}" + services__ring__grpc__0: "https://ring:5001" OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "develop" expose: - "${DEVELOP_PORT}" + - "5001" networks: - "aspire" gateway: @@ -143,6 +161,7 @@ services: environment: ASPNETCORE_ENVIRONMENT: "Production" services__ring__http__0: "http://ring:${RING_PORT}" + services__ring__grpc__0: "https://ring:5001" REVERSEPROXY__ROUTES__route0__MATCH__PATH: "/ws" REVERSEPROXY__ROUTES__route0__CLUSTERID: "cluster_ring" REVERSEPROXY__ROUTES__route1__MATCH__PATH: "/ring/{**catch-all}" @@ -177,9 +196,13 @@ services: REVERSEPROXY__CLUSTERS__cluster_sphere__DESTINATIONS__destination1__ADDRESS: "http://_http.sphere" REVERSEPROXY__CLUSTERS__cluster_develop__DESTINATIONS__destination1__ADDRESS: "http://_http.develop" services__pass__http__0: "http://pass:${PASS_PORT}" + services__pass__grpc__0: "https://pass:5001" services__drive__http__0: "http://drive:${DRIVE_PORT}" + services__drive__grpc__0: "https://drive:5001" services__sphere__http__0: "http://sphere:${SPHERE_PORT}" + services__sphere__grpc__0: "https://sphere:5001" services__develop__http__0: "http://develop:${DEVELOP_PORT}" + services__develop__grpc__0: "https://develop:5001" OTEL_EXPORTER_OTLP_ENDPOINT: "http://aspire-dashboard:18889" OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" OTEL_SERVICE_NAME: "gateway" diff --git a/publish/docker-compose.yaml b/publish/docker-compose.yaml index d439bed..8b4f695 100644 --- a/publish/docker-compose.yaml +++ b/publish/docker-compose.yaml @@ -40,6 +40,7 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${RING_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" OTEL_EXPORTER_OTLP_ENDPOINT: "http://docker-compose-dashboard:18889" @@ -47,6 +48,7 @@ services: OTEL_SERVICE_NAME: "ring" expose: - "${RING_PORT}" + - "5001" networks: - "aspire" pass: @@ -57,6 +59,7 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${PASS_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__ring__http__0: "http://ring:${RING_PORT}" @@ -65,6 +68,7 @@ services: OTEL_SERVICE_NAME: "pass" expose: - "${PASS_PORT}" + - "5001" networks: - "aspire" drive: @@ -75,6 +79,7 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${DRIVE_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" @@ -84,6 +89,7 @@ services: OTEL_SERVICE_NAME: "drive" expose: - "${DRIVE_PORT}" + - "5001" networks: - "aspire" sphere: @@ -94,6 +100,7 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${SPHERE_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" ConnectionStrings__queue: "nats://nats:${QUEUE_PASSWORD}@queue:4222" services__pass__http__0: "http://pass:${PASS_PORT}" @@ -103,6 +110,7 @@ services: OTEL_SERVICE_NAME: "sphere" expose: - "${SPHERE_PORT}" + - "5001" networks: - "aspire" develop: @@ -113,6 +121,7 @@ services: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" HTTP_PORTS: "${DEVELOP_PORT}" + HTTPS_PORTS: "5001" ConnectionStrings__cache: "cache:6379,password=${CACHE_PASSWORD}" services__pass__http__0: "http://pass:${PASS_PORT}" services__ring__http__0: "http://ring:${RING_PORT}" @@ -121,6 +130,7 @@ services: OTEL_SERVICE_NAME: "develop" expose: - "${DEVELOP_PORT}" + - "5001" networks: - "aspire" gateway: