diff --git a/DysonNetwork.Gateway/RegistryProxyConfigProvider.cs b/DysonNetwork.Gateway/RegistryProxyConfigProvider.cs
index bdd5e36..7988561 100644
--- a/DysonNetwork.Gateway/RegistryProxyConfigProvider.cs
+++ b/DysonNetwork.Gateway/RegistryProxyConfigProvider.cs
@@ -93,7 +93,7 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
},
HttpRequest = new ForwarderRequestConfig
{
- ActivityTimeout = directRoute.IsWebsocket ? TimeSpan.FromHours(24) : TimeSpan.FromMinutes(2)
+ ActivityTimeout = directRoute.IsWebSocket ? TimeSpan.FromHours(24) : TimeSpan.FromMinutes(2)
}
};
clusters.Add(cluster);
@@ -104,7 +104,7 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
RouteId = $"direct-{directRoute.Service}-{directRoute.Path.Replace("/", "-")}",
ClusterId = directRoute.Service,
Match = new RouteMatch { Path = directRoute.Path },
- Timeout = directRoute.IsWebsocket ? null : TimeSpan.FromSeconds(5),
+ Timeout = directRoute.IsWebSocket ? null : TimeSpan.FromSeconds(5),
};
routes.Add(route);
_logger.LogInformation(" Added Direct Route: {Path} -> {Service}", directRoute.Path,
@@ -232,7 +232,7 @@ public class RegistryProxyConfigProvider : IProxyConfigProvider, IDisposable
{
public required string Path { get; set; }
public required string Service { get; set; }
- public bool IsWebsocket { get; set; } = false;
+ public bool IsWebSocket { get; set; } = false;
}
public virtual void Dispose()
diff --git a/DysonNetwork.Pass/Program.cs b/DysonNetwork.Pass/Program.cs
index b1f6d63..4dbafa7 100644
--- a/DysonNetwork.Pass/Program.cs
+++ b/DysonNetwork.Pass/Program.cs
@@ -47,6 +47,8 @@ using (var scope = app.Services.CreateScope())
// Configure application middleware pipeline
app.ConfigureAppMiddleware(builder.Configuration, builder.Environment.ContentRootPath);
+app.MapGatewayProxy();
+
app.MapPages(Path.Combine(builder.Environment.WebRootPath, "dist", "index.html"));
// Configure gRPC
diff --git a/DysonNetwork.Shared/DysonNetwork.Shared.csproj b/DysonNetwork.Shared/DysonNetwork.Shared.csproj
index c813c91..89f6c1c 100644
--- a/DysonNetwork.Shared/DysonNetwork.Shared.csproj
+++ b/DysonNetwork.Shared/DysonNetwork.Shared.csproj
@@ -29,6 +29,7 @@
+
diff --git a/DysonNetwork.Shared/Registry/GatewayReverseProxy.cs b/DysonNetwork.Shared/Registry/GatewayReverseProxy.cs
new file mode 100644
index 0000000..5e7a1c0
--- /dev/null
+++ b/DysonNetwork.Shared/Registry/GatewayReverseProxy.cs
@@ -0,0 +1,83 @@
+using System.Diagnostics;
+using System.Net;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Yarp.ReverseProxy.Forwarder;
+
+namespace DysonNetwork.Shared.Registry;
+
+public static class GatewayReverseProxy
+{
+ ///
+ /// Provides reverse proxy for DysonNetwork.Gateway.
+ /// Give the ability to the contained frontend to access other services via the gateway.
+ ///
+ /// The asp.net core application
+ /// The modified application
+ public static WebApplication MapGatewayProxy(this WebApplication app)
+ {
+ var httpClient = new HttpMessageInvoker(new SocketsHttpHandler
+ {
+ UseProxy = false,
+ AllowAutoRedirect = true,
+ AutomaticDecompression = DecompressionMethods.All,
+ UseCookies = true,
+ EnableMultipleHttp2Connections = true,
+ ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
+ ConnectTimeout = TimeSpan.FromSeconds(15),
+ });
+
+ var transformer = new GatewayReverseProxyTransformer();
+ var requestConfig = new ForwarderRequestConfig();
+
+ app.Map("/cgi/{**catch-all}", async (HttpContext context, IHttpForwarder forwarder) =>
+ {
+ var registry = context.RequestServices.GetRequiredService();
+ var gatewayUrl = await registry.GetServiceUrl("DysonNetwork.Gateway");
+ if (gatewayUrl is null)
+ {
+ context.Response.StatusCode = 404;
+ await context.Response.WriteAsync("Gateway not found");
+ return;
+ }
+
+ var error = await forwarder.SendAsync(
+ context,
+ gatewayUrl,
+ httpClient,
+ requestConfig,
+ transformer
+ );
+ if (error != ForwarderError.None)
+ {
+ var errorFeature = context.GetForwarderErrorFeature();
+ var exception = errorFeature?.Exception;
+ context.Response.StatusCode = 502;
+ context.Response.ContentType = "text/plain";
+ await context.Response.WriteAsync($"Gateway remote error: {exception?.Message}");
+ }
+ });
+
+ return app;
+ }
+}
+
+public class GatewayReverseProxyTransformer : HttpTransformer
+{
+ private const string Value = "/cgi";
+
+ public override ValueTask TransformRequestAsync(
+ HttpContext httpContext,
+ HttpRequestMessage proxyRequest,
+ string destinationPrefix,
+ CancellationToken cancellationToken
+ )
+ {
+ httpContext.Request.Path = httpContext.Request.Path.StartsWithSegments(Value, out var remaining)
+ ? remaining
+ : httpContext.Request.Path;
+
+ return Default.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/DysonNetwork.Shared/Registry/ServiceHelper.cs b/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs
similarity index 98%
rename from DysonNetwork.Shared/Registry/ServiceHelper.cs
rename to DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs
index 6ae2adc..4ba8d39 100644
--- a/DysonNetwork.Shared/Registry/ServiceHelper.cs
+++ b/DysonNetwork.Shared/Registry/ServiceInjectionHelper.cs
@@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace DysonNetwork.Shared.Registry;
-public static class ServiceHelper
+public static class ServiceInjectionHelper
{
public static IServiceCollection AddPusherService(this IServiceCollection services)
{
diff --git a/DysonNetwork.Shared/Registry/ServiceRegistry.cs b/DysonNetwork.Shared/Registry/ServiceRegistry.cs
index 4562a89..8c2e0e4 100644
--- a/DysonNetwork.Shared/Registry/ServiceRegistry.cs
+++ b/DysonNetwork.Shared/Registry/ServiceRegistry.cs
@@ -45,4 +45,11 @@ public class ServiceRegistry(IEtcdClient etcd, ILogger logger)
var key = $"/services/{serviceName}";
await etcd.DeleteAsync(key);
}
+
+ public async Task GetServiceUrl(string serviceName)
+ {
+ var key = $"/services/{serviceName}";
+ var response = await etcd.GetAsync(key);
+ return response.Kvs.Count == 0 ? null : response.Kvs[0].Value.ToStringUtf8();
+ }
}
\ No newline at end of file
diff --git a/DysonNetwork.Shared/Registry/Startup.cs b/DysonNetwork.Shared/Registry/Startup.cs
index a5e050c..e5cdeac 100644
--- a/DysonNetwork.Shared/Registry/Startup.cs
+++ b/DysonNetwork.Shared/Registry/Startup.cs
@@ -8,7 +8,8 @@ public static class RegistryStartup
{
public static IServiceCollection AddRegistryService(
this IServiceCollection services,
- IConfiguration configuration
+ IConfiguration configuration,
+ bool addForwarder = true
)
{
services.AddEtcdClient(options =>
@@ -19,6 +20,9 @@ public static class RegistryStartup
services.AddSingleton();
services.AddHostedService();
+ if (addForwarder)
+ services.AddHttpForwarder();
+
return services;
}
}
\ No newline at end of file
diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user
index 270aa92..b9e9d6e 100644
--- a/DysonNetwork.sln.DotSettings.user
+++ b/DysonNetwork.sln.DotSettings.user
@@ -51,10 +51,13 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -90,6 +93,8 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -98,6 +103,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -112,6 +118,7 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded