♻️ Updated discovery resolver

This commit is contained in:
2025-12-13 19:28:24 +08:00
parent 3a7140f0a6
commit 7ecb64742f
15 changed files with 157 additions and 72 deletions

View File

@@ -0,0 +1,38 @@
using System.Diagnostics.CodeAnalysis;
using dotnet_etcd;
using Microsoft.Extensions.ServiceDiscovery;
namespace DysonNetwork.Shared.Registry;
/// <summary>
/// A factory for creating <see cref="RegistrarServiceEndpointProvider"/> instances.
/// </summary>
public class RegistrarServiceEndpointFactory(EtcdClient etcdClient) : IServiceEndpointProviderFactory
{
/// <summary>
/// Tries to create a provider for the given query.
/// </summary>
/// <remarks>
/// This factory creates a provider for any service name. It supports a convention
/// where the service name can include the service part, e.g., "my-service.http" or "my-service.grpc".
/// If the service part is not specified, it defaults to "http".
/// </remarks>
public bool TryCreateProvider(ServiceEndpointQuery query, [NotNullWhen(true)] out IServiceEndpointProvider? provider)
{
var serviceName = query.ServiceName;
var servicePart = "grpc"; // Default to "grpc"
var lastDot = serviceName.LastIndexOf('.');
if (lastDot > 0 && lastDot < serviceName.Length - 1)
{
var part = serviceName[(lastDot + 1)..];
// You might want to have a list of known parts.
// For now, we assume any suffix after a dot is a service part.
servicePart = part;
serviceName = serviceName[..lastDot];
}
provider = new RegistrarServiceEndpointProvider(serviceName, servicePart, etcdClient);
return true;
}
}

View File

@@ -0,0 +1,41 @@
using System.Net;
using dotnet_etcd;
using Microsoft.Extensions.ServiceDiscovery;
namespace DysonNetwork.Shared.Registry;
/// <summary>
/// A service endpoint provider that resolves endpoints from an etcd registry.
/// </summary>
public class RegistrarServiceEndpointProvider(string serviceName, string servicePart, EtcdClient etcdClient)
: IServiceEndpointProvider
{
public ValueTask DisposeAsync()
{
GC.SuppressFinalize(this);
return ValueTask.CompletedTask;
}
/// <summary>
/// Populates the endpoints for the service.
/// </summary>
public async ValueTask PopulateAsync(IServiceEndpointBuilder endpoints, CancellationToken cancellationToken)
{
var prefix = $"/services/{serviceName}/{servicePart}/";
// Fetch service instances from etcd.
var response = await etcdClient.GetRangeAsync(prefix, cancellationToken: cancellationToken);
var instances = response.Kvs.Select(kv => kv.Value.ToStringUtf8());
foreach (var instance in instances)
{
// Instances are in "host:port" format.
var parts = instance.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (parts.Length != 2 || !int.TryParse(parts[1], out var port)) continue;
var host = parts[0];
// Create a DnsEndPoint. The framework will use the original request's scheme (e.g., http, https).
endpoints.Endpoints.Add(ServiceEndpoint.Create(new DnsEndPoint(host, port)));
}
}
}

View File

@@ -7,11 +7,10 @@ namespace DysonNetwork.Shared.Registry;
public static class ServiceInjectionHelper
{
public static IServiceCollection AddRingService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddRingService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("ring", "grpc").GetAwaiter().GetResult();
services
.AddGrpcClient<RingService.RingServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<RingService.RingServiceClient>(o => o.Address = new Uri("https://ring"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -19,17 +18,16 @@ public static class ServiceInjectionHelper
return services;
}
public static IServiceCollection AddAuthService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddAuthService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("pass", "grpc").GetAwaiter().GetResult();
services
.AddGrpcClient<AuthService.AuthServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<AuthService.AuthServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services
.AddGrpcClient<PermissionService.PermissionServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<PermissionService.PermissionServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -37,11 +35,10 @@ public static class ServiceInjectionHelper
return services;
}
public static IServiceCollection AddAccountService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddAccountService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("pass", "grpc").GetAwaiter().GetResult();
services
.AddGrpcClient<AccountService.AccountServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<AccountService.AccountServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -49,42 +46,42 @@ public static class ServiceInjectionHelper
services
.AddGrpcClient<BotAccountReceiverService.BotAccountReceiverServiceClient>(o =>
o.Address = new Uri(instance)
o.Address = new Uri("https://pass")
)
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services.AddGrpcClient<ActionLogService.ActionLogServiceClient>(o => o.Address = new Uri(instance))
services.AddGrpcClient<ActionLogService.ActionLogServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services.AddGrpcClient<PaymentService.PaymentServiceClient>(o => o.Address = new Uri(instance))
services.AddGrpcClient<PaymentService.PaymentServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services.AddGrpcClient<WalletService.WalletServiceClient>(o => o.Address = new Uri(instance))
services.AddGrpcClient<WalletService.WalletServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services
.AddGrpcClient<RealmService.RealmServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<RealmService.RealmServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services.AddSingleton<RemoteRealmService>();
services
.AddGrpcClient<SocialCreditService.SocialCreditServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<SocialCreditService.SocialCreditServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services
.AddGrpcClient<ExperienceService.ExperienceServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<ExperienceService.ExperienceServiceClient>(o => o.Address = new Uri("https://pass"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -92,16 +89,15 @@ public static class ServiceInjectionHelper
return services;
}
public static IServiceCollection AddDriveService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddDriveService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("drive", "grpc").GetAwaiter().GetResult();
services.AddGrpcClient<FileService.FileServiceClient>(o => o.Address = new Uri(instance))
services.AddGrpcClient<FileService.FileServiceClient>(o => o.Address = new Uri("https://drive"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services.AddGrpcClient<FileReferenceService.FileReferenceServiceClient>(o =>
o.Address = new Uri("https://_grpc.drive"))
o.Address = new Uri("https://drive"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -109,17 +105,16 @@ public static class ServiceInjectionHelper
return services;
}
public static IServiceCollection AddSphereService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddSphereService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("drive", "grpc").GetAwaiter().GetResult();
services
.AddGrpcClient<PostService.PostServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<PostService.PostServiceClient>(o => o.Address = new Uri("https://sphere"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
services
.AddGrpcClient<PublisherService.PublisherServiceClient>(o => o.Address = new Uri(instance))
.AddGrpcClient<PublisherService.PublisherServiceClient>(o => o.Address = new Uri("https://sphere"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
@@ -127,15 +122,14 @@ public static class ServiceInjectionHelper
return services;
}
public static IServiceCollection AddDevelopService(this IServiceCollection services, ServiceRegistrar registrar)
public static IServiceCollection AddDevelopService(this IServiceCollection services)
{
var instance = registrar.GetServiceInstanceAsync("develop", "grpc").GetAwaiter().GetResult();
services.AddGrpcClient<CustomAppService.CustomAppServiceClient>(o =>
o.Address = new Uri(instance))
o.Address = new Uri("https://develop"))
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
);
return services;
}
}
}