using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Grpc.Net.Client; using MagicOnion.Client; using System; using System.Linq; using System.Threading.Tasks; namespace DysonNetwork.Shared.Etcd { public static class EtcdServiceExtensions { public static IServiceCollection AddEtcdService(this IServiceCollection services, IConfiguration configuration) { var connectionString = configuration["ConnectionStrings:Etcd"]; if (connectionString is null) throw new ArgumentNullException(nameof(connectionString)); services.AddSingleton(new EtcdService(connectionString!)); return services; } public static IServiceCollection AddRemoteService(this IServiceCollection services) where TService : class, MagicOnion.IService { services.AddSingleton(serviceProvider => { var etcdService = serviceProvider.GetRequiredService(); var serviceName = typeof(TService).Name.TrimStart('I'); // Convention: IMyService -> MyService // Synchronously wait for service discovery (or handle asynchronously if preferred) var endpoints = etcdService.DiscoverServicesAsync(serviceName).GetAwaiter().GetResult(); if (endpoints.Count == 0) throw new InvalidOperationException($"No endpoints found for MagicOnion service: {serviceName}"); // For simplicity, use the first discovered endpoint var endpoint = endpoints.First(); var channel = GrpcChannel.ForAddress(endpoint); return MagicOnionClient.Create(channel); }); return services; } } }