From 4a5708985e7ace49d0090bd311424e323b0f3158 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Thu, 2 Jul 2026 19:17:25 +0200 Subject: [PATCH 1/5] Implement scopes for GatewayClient handlers --- .../Gateway/GatewayClientHostedService.cs | 8 +- .../NetCord.Hosting/Gateway/GatewayEvent.cs | 12 +- ...tewayHandlerServiceCollectionExtensions.cs | 54 +++- .../Gateway/GatewayHandlers.cs | 25 +- .../HostingGatewayEventsGenerator.cs | 286 ++++++++++++++---- Tests/NetCord.Test.Hosting/Program.cs | 4 +- 6 files changed, 295 insertions(+), 94 deletions(-) diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayClientHostedService.cs b/Hosting/NetCord.Hosting/Gateway/GatewayClientHostedService.cs index e0388bf08..9c72e8352 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayClientHostedService.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayClientHostedService.cs @@ -12,12 +12,12 @@ public Task StartAsync(CancellationToken cancellationToken) { var client = services.GetRequiredService(); - foreach (var handler in services.GetServices()) + foreach (var handlerMetadata in services.GetServices()) { - if (handler is IDelegateGatewayHandlerBase delegateHandler) - RegisterDelegateHandler(client, delegateHandler); + if (handlerMetadata is ClassGatewayHandlerMetadata classHandlerMetadata) + RegisterClassHandler(services, client, classHandlerMetadata); else - RegisterClassHandler(client, handler); + RegisterDelegateHandler(services, client, (DelegateGatewayHandlerMetadata)handlerMetadata); } var options = services.GetRequiredService>().Value; diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayEvent.cs b/Hosting/NetCord.Hosting/Gateway/GatewayEvent.cs index 93cc2cf1e..f0b600b57 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayEvent.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayEvent.cs @@ -2,20 +2,20 @@ namespace NetCord.Hosting.Gateway; public partial class GatewayEvent { - internal GatewayEvent(string name) + internal GatewayEvent(GatewayEventId id) { - Name = name; + Id = id; } - internal string Name { get; } + internal GatewayEventId Id { get; } } public class GatewayEvent { - internal GatewayEvent(string name) + internal GatewayEvent(GatewayEventId id) { - Name = name; + Id = id; } - internal string Name { get; } + internal GatewayEventId Id { get; } } diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs index 095e22415..7864bc5f9 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs @@ -2,9 +2,28 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace NetCord.Hosting.Gateway; +internal abstract class GatewayHandlerMetadata(bool isSingleton) +{ + public bool IsSingleton => isSingleton; +} + +internal sealed class ClassGatewayHandlerMetadata(Type handlerType, bool isSingleton) : GatewayHandlerMetadata(isSingleton) +{ + public Type HandlerType => handlerType; + +} + +internal sealed class DelegateGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : GatewayHandlerMetadata(isSingleton) +{ + public Delegate Handler => handler; + + public GatewayEventId EventId => eventId; +} + public static class GatewayHandlerServiceCollectionExtensions { /// @@ -13,9 +32,10 @@ public static class GatewayHandlerServiceCollectionExtensions /// The type of the to add. /// The to add the to. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services) where T : class, IGatewayHandler + public static IServiceCollection AddGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IGatewayHandler { - services.AddSingleton(); + services.TryAdd(ServiceDescriptor.Describe(typeof(T), typeof(T), lifetime)); + services.AddSingleton(new ClassGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); return services; } @@ -26,9 +46,10 @@ public static class GatewayHandlerServiceCollectionExtensions /// The to add the to. /// The factory that creates the . /// A reference to this instance after the operation has completed. - public static IServiceCollection AddGatewayHandler(this IServiceCollection services, Func implementationFactory) where T : class, IGatewayHandler + public static IServiceCollection AddGatewayHandler(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IGatewayHandler { - services.AddSingleton(implementationFactory); + services.TryAdd(ServiceDescriptor.Describe(typeof(T), implementationFactory, lifetime)); + services.AddSingleton(new ClassGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); return services; } @@ -38,9 +59,10 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection se /// The to add the to. /// The type of the to add. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType) + public static IServiceCollection AddGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(typeof(IGatewayHandler), handlerType); + services.TryAdd(ServiceDescriptor.Describe(handlerType, handlerType, lifetime)); + services.AddSingleton(new ClassGatewayHandlerMetadata(handlerType, lifetime is ServiceLifetime.Singleton)); return services; } @@ -51,9 +73,13 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection servi /// The gateway event. /// The delegate that represents the handler. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) + public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(services => new DelegateGatewayHandler(gatewayEvent.Name, services, handler)); + services.AddSingleton(new DelegateGatewayHandlerMetadata( + DelegateHandlerHelper.CreateHandler>(handler, []), + gatewayEvent.Id, + lifetime is ServiceLifetime.Singleton)); + return services; } @@ -65,9 +91,13 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection servi /// The gateway event. /// The delegate that represents the handler. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) + public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(services => new DelegateGatewayHandler(gatewayEvent.Name, services, handler)); + services.AddSingleton(new DelegateGatewayHandlerMetadata( + DelegateHandlerHelper.CreateHandler>(handler, [typeof(T)]), + gatewayEvent.Id, + lifetime is ServiceLifetime.Singleton)); + return services; } @@ -130,7 +160,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) { - services.AddSingleton(services => new DelegateShardedGatewayHandler(gatewayEvent.Name, services, handler)); + services.AddSingleton(services => new DelegateShardedGatewayHandler("", services, handler)); return services; } @@ -144,7 +174,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) { - services.AddSingleton(services => new DelegateShardedGatewayHandler(gatewayEvent.Name, services, handler)); + services.AddSingleton(services => new DelegateShardedGatewayHandler("", services, handler)); return services; } diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs index 98672574a..74f84f042 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs @@ -4,37 +4,28 @@ namespace NetCord.Hosting.Gateway; public interface IGatewayHandler; -internal interface IDelegateGatewayHandlerBase : IGatewayHandler +internal interface IDelegateGatewayHandler { - internal string Name { get; } -} - -internal interface IDelegateGatewayHandler : IDelegateGatewayHandlerBase -{ - public ValueTask HandleAsync(); + public ValueTask HandleAsync(IServiceProvider services); } -internal interface IDelegateGatewayHandler : IDelegateGatewayHandlerBase +internal interface IDelegateGatewayHandler { - public ValueTask HandleAsync(T arg); + public ValueTask HandleAsync(T arg, IServiceProvider services); } -internal class DelegateGatewayHandler(string name, IServiceProvider services, Delegate handler) : IDelegateGatewayHandler +internal class DelegateGatewayHandler(Delegate handler) : IDelegateGatewayHandler { private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, []); - string IDelegateGatewayHandlerBase.Name => name; - - public ValueTask HandleAsync() => _handler(services); + public ValueTask HandleAsync(IServiceProvider services) => _handler(services); } -internal class DelegateGatewayHandler(string name, IServiceProvider services, Delegate handler) : IDelegateGatewayHandler +internal class DelegateGatewayHandler(Delegate handler) : IDelegateGatewayHandler { private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, [typeof(T)]); - string IDelegateGatewayHandlerBase.Name => name; - - public ValueTask HandleAsync(T arg) => _handler(arg, services); + public ValueTask HandleAsync(T arg, IServiceProvider services) => _handler(arg, services); } public interface IShardedGatewayHandler; diff --git a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs index b9fdfe818..3b8e4e9af 100644 --- a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs +++ b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs @@ -52,11 +52,33 @@ private string GenerateEvents(IEventSymbol[] events) StringWriter stringWriter = new(); Setup(stringWriter); + WriteEventsEnum(stringWriter, events); + + stringWriter.WriteLine(); + WriteEvents(stringWriter, events); return stringWriter.ToString(); } + private void WriteEventsEnum(StringWriter stringWriter, IEventSymbol[] events) + { + stringWriter.WriteLine(); + + stringWriter.WriteLine("internal enum GatewayEventId : byte"); + + stringWriter.WriteLine("{"); + + foreach (var eventSymbol in events) + { + stringWriter.WriteIndentation(1); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(","); + } + + stringWriter.WriteLine("}"); + } + private void WriteEvents(StringWriter stringWriter, IEventSymbol[] events) { stringWriter.WriteLine(); @@ -85,9 +107,9 @@ private void WriteEvents(StringWriter stringWriter, IEventSymbol[] events) stringWriter.Write(" "); stringWriter.Write(eventSymbol.Name); - stringWriter.Write(" => new(\""); + stringWriter.Write(" => new(global::NetCord.Hosting.Gateway.GatewayEventId."); stringWriter.Write(eventSymbol.Name); - stringWriter.WriteLine("\");"); + stringWriter.WriteLine(");"); } stringWriter.WriteLine("}"); @@ -242,73 +264,157 @@ private void WriteRegisterDelegateHandlerMethod(StringWriter stringWriter, IEven stringWriter.WriteLine(); stringWriter.WriteIndentation(1); - stringWriter.WriteLine("private static void RegisterDelegateHandler(global::NetCord.Gateway.GatewayClient client, global::NetCord.Hosting.Gateway.IDelegateGatewayHandlerBase handler)"); + stringWriter.WriteLine("private static void RegisterDelegateHandler(IServiceProvider services, global::NetCord.Gateway.GatewayClient client, global::NetCord.Hosting.Gateway.DelegateGatewayHandlerMetadata handlerMetadata)"); stringWriter.WriteIndentation(1); - stringWriter.Write("{"); + stringWriter.WriteLine("{"); - int i = 0; - foreach (var group in events.GroupBy(e => e.Type, SymbolEqualityComparer.Default)) + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("switch (handlerMetadata.EventId)"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("{"); + + int eventsLength = events.Length; + for (int i = 0; i < eventsLength; i++) { - var eventType = (INamedTypeSymbol)group.Key!; + var eventSymbol = events[i]; - stringWriter.WriteLine(); + stringWriter.WriteIndentation(3); + stringWriter.Write("case global::NetCord.Hosting.Gateway.GatewayEventId."); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(":"); - stringWriter.WriteIndentation(2); - stringWriter.Write("if (handler is global::NetCord.Hosting.Gateway.IDelegateGatewayHandler"); + stringWriter.WriteIndentation(4); + stringWriter.Write("var typedHandler"); + stringWriter.Write(i); + stringWriter.Write(" = (global::System.Func<"); + var eventType = (INamedTypeSymbol)eventSymbol.Type; if (eventType.Arity is 2) { - stringWriter.Write("<"); stringWriter.Write(eventType.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); - stringWriter.Write(">"); + stringWriter.Write(", "); } - stringWriter.Write(" delegateGatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(")"); + stringWriter.WriteLine("global::System.IServiceProvider, global::System.Threading.Tasks.ValueTask>)handlerMetadata.Handler;"); - stringWriter.WriteIndentation(2); - stringWriter.WriteLine("{"); + stringWriter.WriteIndentation(4); + stringWriter.Write("client."); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(" += isSingleton"); - stringWriter.WriteIndentation(3); - stringWriter.Write("switch (delegateGatewayHandler"); + stringWriter.WriteIndentation(5); + stringWriter.Write("? ("); + + if (eventType.Arity is not 1) + stringWriter.Write("arg"); + + stringWriter.Write(") => typedHandler"); stringWriter.Write(i); - stringWriter.WriteLine(".Name)"); + stringWriter.Write("("); - stringWriter.WriteIndentation(3); - stringWriter.WriteLine("{"); + if (eventType.Arity is not 1) + stringWriter.Write("arg, "); - foreach (var eventSymbol in group) - { - stringWriter.WriteIndentation(4); - stringWriter.Write("case \""); - stringWriter.Write(eventSymbol.Name); - stringWriter.WriteLine("\":"); + stringWriter.WriteLine("services)"); - stringWriter.WriteIndentation(5); - stringWriter.Write("client."); - stringWriter.Write(eventSymbol.Name); - stringWriter.Write(" += delegateGatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(".HandleAsync;"); + stringWriter.WriteIndentation(5); + stringWriter.WriteLine(eventType.Arity is 1 ? ": async () =>" : ": async (arg) =>"); - stringWriter.WriteIndentation(5); - stringWriter.WriteLine("break;"); - } + stringWriter.WriteIndentation(5); + stringWriter.WriteLine("{"); - stringWriter.WriteIndentation(3); - stringWriter.WriteLine("}"); + stringWriter.WriteIndentation(6); + stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); - stringWriter.WriteIndentation(3); - stringWriter.WriteLine("return;"); + stringWriter.WriteIndentation(6); + stringWriter.Write("await typedHandler"); + stringWriter.Write(i); + stringWriter.Write("("); - stringWriter.WriteIndentation(2); - stringWriter.WriteLine("}"); + if (eventType.Arity is not 1) + stringWriter.Write("arg, "); - i++; + stringWriter.WriteLine("scope.ServiceProvider);"); + + stringWriter.WriteIndentation(5); + stringWriter.WriteLine("};"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("break;"); } + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("}"); + + // stringWriter.WriteIndentation(2); + // stringWriter.WriteLine("var handler = handlerMetadata.Handler;"); + // + // stringWriter.WriteIndentation(2); + // stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); + + // int i = 0; + // foreach (var group in events.GroupBy(e => e.Type, SymbolEqualityComparer.Default)) + // { + // var eventType = (INamedTypeSymbol)group.Key!; + // + // stringWriter.WriteLine(); + // + // stringWriter.WriteIndentation(2); + // stringWriter.Write("if (handler is global::System.Func<"); + // if (eventType.Arity is 2) + // { + // stringWriter.Write(eventType.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); + // stringWriter.Write(", "); + // } + // + // stringWriter.Write("global::System.IServiceProvider, global::System.Threading.Tasks.ValueTask> typedHandler"); + // stringWriter.Write(i); + // stringWriter.WriteLine(")"); + // + // stringWriter.WriteIndentation(2); + // stringWriter.WriteLine("{"); + // + // stringWriter.WriteIndentation(3); + // stringWriter.Write("switch (handlerMetadata.EventName)"); + // + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("{"); + // + // foreach (var eventSymbol in group) + // { + // stringWriter.WriteIndentation(4); + // stringWriter.Write("case \""); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.WriteLine("\":"); + // + // stringWriter.WriteIndentation(5); + // stringWriter.Write("client."); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.Write(eventType.Arity is 1 ? " += () => typedHandler" : " += (arg) => typedHandler"); + // stringWriter.Write(i); + // stringWriter.Write(eventType.Arity is 1 ? "(services);" : "(arg, services);"); + // + // stringWriter.WriteIndentation(5); + // stringWriter.WriteLine("break;"); + // } + // + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("}"); + // + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("return;"); + // + // stringWriter.WriteIndentation(2); + // stringWriter.WriteLine("}"); + // + // i++; + // } + stringWriter.WriteIndentation(1); stringWriter.WriteLine("}"); } @@ -318,10 +424,16 @@ private void WriteRegisterClassHandlerMethod(StringWriter stringWriter, IEventSy stringWriter.WriteLine(); stringWriter.WriteIndentation(1); - stringWriter.WriteLine("private static void RegisterClassHandler(global::NetCord.Gateway.GatewayClient client, global::NetCord.Hosting.Gateway.IGatewayHandler handler)"); + stringWriter.WriteLine("private static void RegisterClassHandler(global::System.IServiceProvider services, global::NetCord.Gateway.GatewayClient client, global::NetCord.Hosting.Gateway.ClassGatewayHandlerMetadata handlerMetadata)"); stringWriter.WriteIndentation(1); - stringWriter.Write("{"); + stringWriter.WriteLine("{"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var handlerType = handlerMetadata.HandlerType;"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); int eventsLength = events.Length; @@ -329,21 +441,89 @@ private void WriteRegisterClassHandlerMethod(StringWriter stringWriter, IEventSy { var eventSymbol = events[i]; + var eventType = (INamedTypeSymbol)eventSymbol.Type; + stringWriter.WriteLine(); stringWriter.WriteIndentation(2); - stringWriter.Write("if (handler is global::NetCord.Hosting.Gateway.I"); + stringWriter.Write("if (typeof(global::NetCord.Hosting.Gateway.I"); stringWriter.Write(eventSymbol.Name); - stringWriter.Write("GatewayHandler gatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(")"); + stringWriter.WriteLine("GatewayHandler).IsAssignableFrom(handlerType))"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("{"); stringWriter.WriteIndentation(3); stringWriter.Write("client."); stringWriter.Write(eventSymbol.Name); - stringWriter.Write(" += gatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(".HandleAsync;"); + stringWriter.WriteLine(" += isSingleton"); + + stringWriter.WriteIndentation(4); + stringWriter.Write("? ((global::NetCord.Hosting.Gateway.I"); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine("GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(services, handlerMetadata.HandlerType)).HandleAsync"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine(eventType.Arity is 1 ? ": async () =>" : ": async (arg) =>"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("{"); + + stringWriter.WriteIndentation(5); + stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); + + stringWriter.WriteIndentation(5); + stringWriter.Write("await ((global::NetCord.Hosting.Gateway.I"); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(eventType.Arity is 1 + ? "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync();" + : "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync(arg);"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("};"); + + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("if (lifetime is global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)"); + // + // stringWriter.WriteIndentation(4); + // stringWriter.Write("client."); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.Write(" += ((global::NetCord.Hosting.Gateway.I"); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.WriteLine("GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(services, handlerMetadata.HandlerType)).HandleAsync;"); + // + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("else"); + // + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("{"); + // + // stringWriter.WriteIndentation(4); + // stringWriter.Write("client."); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.WriteLine(eventType.Arity is 1 ? " += async () =>" : " += async (arg) =>"); + // + // stringWriter.WriteIndentation(4); + // stringWriter.WriteLine("{"); + // + // stringWriter.WriteIndentation(5); + // stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); + // + // stringWriter.WriteIndentation(5); + // stringWriter.Write("await ((global::NetCord.Hosting.Gateway.I"); + // stringWriter.Write(eventSymbol.Name); + // stringWriter.WriteLine(eventType.Arity is 1 + // ? "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync();" + // : "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync(arg);"); + // + // stringWriter.WriteIndentation(4); + // stringWriter.WriteLine("};"); + + // stringWriter.WriteIndentation(3); + // stringWriter.WriteLine("}"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("}"); } stringWriter.WriteIndentation(1); diff --git a/Tests/NetCord.Test.Hosting/Program.cs b/Tests/NetCord.Test.Hosting/Program.cs index c51d53a60..cc8d7477e 100644 --- a/Tests/NetCord.Test.Hosting/Program.cs +++ b/Tests/NetCord.Test.Hosting/Program.cs @@ -61,9 +61,9 @@ .AddComponentInteractions() .AddComponentInteractions() .AddCommands() - .AddGatewayHandler(GatewayEvent.MessageCreate, (Message message, ILogger logger) => logger.LogInformation("Content: {}", message.Content)) + .AddGatewayHandler(GatewayEvent.MessageCreate, (Message message, ILogger logger, IServiceProvider p) => logger.LogInformation("Content: {}", message.Content), ServiceLifetime.Scoped) .AddGatewayHandler() - .AddGatewayHandler() + .AddGatewayHandler(ServiceLifetime.Scoped) .AddGatewayHandler() .AddSingleton("Wzium") .AddKeyedSingleton("key", "Wzium2"); From ee963f07ec4ec745a5c047d4d475210ba28f73f6 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Thu, 2 Jul 2026 19:21:30 +0200 Subject: [PATCH 2/5] Cleanup --- .../HostingGatewayEventsGenerator.cs | 122 ++---------------- 1 file changed, 13 insertions(+), 109 deletions(-) diff --git a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs index 3b8e4e9af..ee898af91 100644 --- a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs +++ b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs @@ -294,7 +294,7 @@ private void WriteRegisterDelegateHandlerMethod(StringWriter stringWriter, IEven stringWriter.Write(" = (global::System.Func<"); var eventType = (INamedTypeSymbol)eventSymbol.Type; - if (eventType.Arity is 2) + if (eventType.Arity is not 1) { stringWriter.Write(eventType.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); stringWriter.Write(", "); @@ -323,7 +323,12 @@ private void WriteRegisterDelegateHandlerMethod(StringWriter stringWriter, IEven stringWriter.WriteLine("services)"); stringWriter.WriteIndentation(5); - stringWriter.WriteLine(eventType.Arity is 1 ? ": async () =>" : ": async (arg) =>"); + stringWriter.Write(": async ("); + + if (eventType.Arity is not 1) + stringWriter.Write("arg"); + + stringWriter.WriteLine(") =>"); stringWriter.WriteIndentation(5); stringWriter.WriteLine("{"); @@ -351,70 +356,6 @@ private void WriteRegisterDelegateHandlerMethod(StringWriter stringWriter, IEven stringWriter.WriteIndentation(2); stringWriter.WriteLine("}"); - // stringWriter.WriteIndentation(2); - // stringWriter.WriteLine("var handler = handlerMetadata.Handler;"); - // - // stringWriter.WriteIndentation(2); - // stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); - - // int i = 0; - // foreach (var group in events.GroupBy(e => e.Type, SymbolEqualityComparer.Default)) - // { - // var eventType = (INamedTypeSymbol)group.Key!; - // - // stringWriter.WriteLine(); - // - // stringWriter.WriteIndentation(2); - // stringWriter.Write("if (handler is global::System.Func<"); - // if (eventType.Arity is 2) - // { - // stringWriter.Write(eventType.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); - // stringWriter.Write(", "); - // } - // - // stringWriter.Write("global::System.IServiceProvider, global::System.Threading.Tasks.ValueTask> typedHandler"); - // stringWriter.Write(i); - // stringWriter.WriteLine(")"); - // - // stringWriter.WriteIndentation(2); - // stringWriter.WriteLine("{"); - // - // stringWriter.WriteIndentation(3); - // stringWriter.Write("switch (handlerMetadata.EventName)"); - // - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("{"); - // - // foreach (var eventSymbol in group) - // { - // stringWriter.WriteIndentation(4); - // stringWriter.Write("case \""); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.WriteLine("\":"); - // - // stringWriter.WriteIndentation(5); - // stringWriter.Write("client."); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.Write(eventType.Arity is 1 ? " += () => typedHandler" : " += (arg) => typedHandler"); - // stringWriter.Write(i); - // stringWriter.Write(eventType.Arity is 1 ? "(services);" : "(arg, services);"); - // - // stringWriter.WriteIndentation(5); - // stringWriter.WriteLine("break;"); - // } - // - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("}"); - // - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("return;"); - // - // stringWriter.WriteIndentation(2); - // stringWriter.WriteLine("}"); - // - // i++; - // } - stringWriter.WriteIndentation(1); stringWriter.WriteLine("}"); } @@ -475,53 +416,16 @@ private void WriteRegisterClassHandlerMethod(StringWriter stringWriter, IEventSy stringWriter.WriteIndentation(5); stringWriter.Write("await ((global::NetCord.Hosting.Gateway.I"); stringWriter.Write(eventSymbol.Name); - stringWriter.WriteLine(eventType.Arity is 1 - ? "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync();" - : "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync(arg);"); + stringWriter.Write("GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync("); + + if (eventType.Arity is not 1) + stringWriter.Write("arg"); + + stringWriter.WriteLine(");"); stringWriter.WriteIndentation(4); stringWriter.WriteLine("};"); - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("if (lifetime is global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)"); - // - // stringWriter.WriteIndentation(4); - // stringWriter.Write("client."); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.Write(" += ((global::NetCord.Hosting.Gateway.I"); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.WriteLine("GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(services, handlerMetadata.HandlerType)).HandleAsync;"); - // - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("else"); - // - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("{"); - // - // stringWriter.WriteIndentation(4); - // stringWriter.Write("client."); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.WriteLine(eventType.Arity is 1 ? " += async () =>" : " += async (arg) =>"); - // - // stringWriter.WriteIndentation(4); - // stringWriter.WriteLine("{"); - // - // stringWriter.WriteIndentation(5); - // stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); - // - // stringWriter.WriteIndentation(5); - // stringWriter.Write("await ((global::NetCord.Hosting.Gateway.I"); - // stringWriter.Write(eventSymbol.Name); - // stringWriter.WriteLine(eventType.Arity is 1 - // ? "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync();" - // : "GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync(arg);"); - // - // stringWriter.WriteIndentation(4); - // stringWriter.WriteLine("};"); - - // stringWriter.WriteIndentation(3); - // stringWriter.WriteLine("}"); - stringWriter.WriteIndentation(2); stringWriter.WriteLine("}"); } From 13a5a443d08eba081e2f1867a217e7796c4899d9 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Thu, 2 Jul 2026 20:17:08 +0200 Subject: [PATCH 3/5] Add ShardedGatewayClient handler scopes --- ...tewayHandlerServiceCollectionExtensions.cs | 76 +++++--- .../Gateway/GatewayHandlers.cs | 59 ------ .../ShardedGatewayClientHostedService.cs | 16 +- .../HostingGatewayEventsGenerator.cs | 182 ++++++++++++------ 4 files changed, 192 insertions(+), 141 deletions(-) diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs index 7864bc5f9..35a5afb71 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs @@ -4,6 +4,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using NetCord.Gateway; + namespace NetCord.Hosting.Gateway; internal abstract class GatewayHandlerMetadata(bool isSingleton) @@ -14,7 +16,6 @@ internal abstract class GatewayHandlerMetadata(bool isSingleton) internal sealed class ClassGatewayHandlerMetadata(Type handlerType, bool isSingleton) : GatewayHandlerMetadata(isSingleton) { public Type HandlerType => handlerType; - } internal sealed class DelegateGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : GatewayHandlerMetadata(isSingleton) @@ -24,6 +25,23 @@ internal sealed class DelegateGatewayHandlerMetadata(Delegate handler, GatewayEv public GatewayEventId EventId => eventId; } +internal abstract class ShardedGatewayHandlerMetadata(bool isSingleton) +{ + public bool IsSingleton => isSingleton; +} + +internal sealed class ClassShardedGatewayHandlerMetadata(Type handlerType, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) +{ + public Type HandlerType => handlerType; +} + +internal sealed class DelegateShardedGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) +{ + public Delegate Handler => handler; + + public GatewayEventId EventId => eventId; +} + public static class GatewayHandlerServiceCollectionExtensions { /// @@ -36,6 +54,7 @@ public static class GatewayHandlerServiceCollectionExtensions { services.TryAdd(ServiceDescriptor.Describe(typeof(T), typeof(T), lifetime)); services.AddSingleton(new ClassGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); + return services; } @@ -50,6 +69,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection se { services.TryAdd(ServiceDescriptor.Describe(typeof(T), implementationFactory, lifetime)); services.AddSingleton(new ClassGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); + return services; } @@ -63,6 +83,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection servi { services.TryAdd(ServiceDescriptor.Describe(handlerType, handlerType, lifetime)); services.AddSingleton(new ClassGatewayHandlerMetadata(handlerType, lifetime is ServiceLifetime.Singleton)); + return services; } @@ -108,9 +129,11 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection se /// The assembly to scan for implementations. /// A reference to this instance after the operation has completed. [RequiresUnreferencedCode("Types might be removed")] - public static IServiceCollection AddGatewayHandlers(this IServiceCollection services, Assembly assembly) + public static IServiceCollection AddGatewayHandlers(this IServiceCollection services, Assembly assembly, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - AddGatewayHandlers(services, typeof(IGatewayHandler), assembly); + foreach (var type in HandlerHelpers.GetHandlers(typeof(IGatewayHandler), assembly)) + AddGatewayHandler(services, type, lifetime); + return services; } @@ -120,9 +143,11 @@ public static IServiceCollection AddGatewayHandlers(this IServiceCollection serv /// The type of the to add. /// The to add the to. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddShardedGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services) where T : class, IShardedGatewayHandler + public static IServiceCollection AddShardedGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IShardedGatewayHandler { - services.AddSingleton(); + services.TryAdd(ServiceDescriptor.Describe(typeof(T), typeof(T), lifetime)); + services.AddSingleton(new ClassShardedGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); + return services; } @@ -133,9 +158,11 @@ public static IServiceCollection AddGatewayHandlers(this IServiceCollection serv /// The to add the to. /// The factory that creates the . /// A reference to this instance after the operation has completed. - public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, Func implementationFactory) where T : class, IShardedGatewayHandler + public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IShardedGatewayHandler { - services.AddSingleton(implementationFactory); + services.TryAdd(ServiceDescriptor.Describe(typeof(T), implementationFactory, lifetime)); + services.AddSingleton(new ClassShardedGatewayHandlerMetadata(typeof(T), lifetime is ServiceLifetime.Singleton)); + return services; } @@ -145,9 +172,11 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollec /// The to add the to. /// The type of the to add. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType) + public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(typeof(IShardedGatewayHandler), handlerType); + services.TryAdd(ServiceDescriptor.Describe(handlerType, handlerType, lifetime)); + services.AddSingleton(new ClassGatewayHandlerMetadata(handlerType, lifetime is ServiceLifetime.Singleton)); + return services; } @@ -158,9 +187,13 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// The gateway event. /// The delegate that represents the handler. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) + public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(services => new DelegateShardedGatewayHandler("", services, handler)); + services.AddSingleton(new DelegateShardedGatewayHandlerMetadata( + DelegateHandlerHelper.CreateHandler>(handler, [typeof(GatewayClient)]), + gatewayEvent.Id, + lifetime is ServiceLifetime.Singleton)); + return services; } @@ -172,9 +205,13 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// The gateway event. /// The delegate that represents the handler. /// A reference to this instance after the operation has completed. - public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler) + public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddSingleton(services => new DelegateShardedGatewayHandler("", services, handler)); + services.AddSingleton(new DelegateShardedGatewayHandlerMetadata( + DelegateHandlerHelper.CreateHandler>(handler, [typeof(GatewayClient), typeof(T)]), + gatewayEvent.Id, + lifetime is ServiceLifetime.Singleton)); + return services; } @@ -185,16 +222,11 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollec /// The assembly to scan for implementations. /// A reference to this instance after the operation has completed. [RequiresUnreferencedCode("Types might be removed")] - public static IServiceCollection AddShardedGatewayHandlers(this IServiceCollection services, Assembly assembly) + public static IServiceCollection AddShardedGatewayHandlers(this IServiceCollection services, Assembly assembly, ServiceLifetime lifetime = ServiceLifetime.Singleton) { - AddGatewayHandlers(services, typeof(IShardedGatewayHandler), assembly); - return services; - } + foreach (var type in HandlerHelpers.GetHandlers(typeof(IShardedGatewayHandler), assembly)) + AddShardedGatewayHandler(services, type, lifetime); - [RequiresUnreferencedCode("Types might be removed")] - private static void AddGatewayHandlers(IServiceCollection services, Type handlerBase, Assembly assembly) - { - foreach (var type in HandlerHelpers.GetHandlers(handlerBase, assembly)) - services.AddSingleton(handlerBase, type); + return services; } } diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs index 74f84f042..15eaac7bb 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs @@ -1,64 +1,5 @@ -using NetCord.Gateway; - namespace NetCord.Hosting.Gateway; public interface IGatewayHandler; -internal interface IDelegateGatewayHandler -{ - public ValueTask HandleAsync(IServiceProvider services); -} - -internal interface IDelegateGatewayHandler -{ - public ValueTask HandleAsync(T arg, IServiceProvider services); -} - -internal class DelegateGatewayHandler(Delegate handler) : IDelegateGatewayHandler -{ - private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, []); - - public ValueTask HandleAsync(IServiceProvider services) => _handler(services); -} - -internal class DelegateGatewayHandler(Delegate handler) : IDelegateGatewayHandler -{ - private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, [typeof(T)]); - - public ValueTask HandleAsync(T arg, IServiceProvider services) => _handler(arg, services); -} - public interface IShardedGatewayHandler; - -internal interface IDelegateShardedGatewayHandlerBase : IShardedGatewayHandler -{ - internal string Name { get; } -} - -internal interface IDelegateShardedGatewayHandler : IDelegateShardedGatewayHandlerBase -{ - public ValueTask HandleAsync(GatewayClient client); -} - -internal interface IDelegateShardedGatewayHandler : IDelegateShardedGatewayHandlerBase -{ - public ValueTask HandleAsync(GatewayClient client, T arg); -} - -internal class DelegateShardedGatewayHandler(string name, IServiceProvider services, Delegate handler) : IDelegateShardedGatewayHandler -{ - private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, [typeof(GatewayClient)]); - - string IDelegateShardedGatewayHandlerBase.Name => name; - - public ValueTask HandleAsync(GatewayClient client) => _handler(client, services); -} - -internal class DelegateShardedGatewayHandler(string name, IServiceProvider services, Delegate handler) : IDelegateShardedGatewayHandler -{ - private readonly Func _handler = DelegateHandlerHelper.CreateHandler>(handler, [typeof(GatewayClient), typeof(T)]); - - string IDelegateShardedGatewayHandlerBase.Name => name; - - public ValueTask HandleAsync(GatewayClient client, T arg) => _handler(client, arg, services); -} diff --git a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs index f5ebd4cec..5040f36f2 100644 --- a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs +++ b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs @@ -12,14 +12,22 @@ public Task StartAsync(CancellationToken cancellationToken) { var client = services.GetRequiredService(); - foreach (var handler in services.GetServices()) + foreach (var handlerMetadata in services.GetServices()) { - if (handler is IDelegateShardedGatewayHandlerBase delegateHandler) - RegisterDelegateShardedHandler(client, delegateHandler); + if (handlerMetadata is ClassShardedGatewayHandlerMetadata classHandlerMetadata) + RegisterClassShardedHandler(services, client, classHandlerMetadata); else - RegisterClassShardedHandler(client, handler); + RegisterDelegateShardedHandler(services, client, (DelegateShardedGatewayHandlerMetadata)handlerMetadata); } + // foreach (var handler in services.GetServices()) + // { + // if (handler is IDelegateShardedGatewayHandlerBase delegateHandler) + // RegisterDelegateShardedHandler(client, delegateHandler); + // else + // RegisterClassShardedHandler(client, handler); + // } + var options = services.GetRequiredService>().Value; return options.AutoStartStop.GetValueOrDefault(true) diff --git a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs index ee898af91..d4796eba5 100644 --- a/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs +++ b/SourceGenerators/HostingGatewayEventsGenerator/HostingGatewayEventsGenerator.cs @@ -54,8 +54,6 @@ private string GenerateEvents(IEventSymbol[] events) WriteEventsEnum(stringWriter, events); - stringWriter.WriteLine(); - WriteEvents(stringWriter, events); return stringWriter.ToString(); @@ -405,7 +403,12 @@ private void WriteRegisterClassHandlerMethod(StringWriter stringWriter, IEventSy stringWriter.WriteLine("GatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(services, handlerMetadata.HandlerType)).HandleAsync"); stringWriter.WriteIndentation(4); - stringWriter.WriteLine(eventType.Arity is 1 ? ": async () =>" : ": async (arg) =>"); + stringWriter.Write(": async ("); + + if (eventType.Arity is not 1) + stringWriter.Write("arg"); + + stringWriter.WriteLine(") =>"); stringWriter.WriteIndentation(4); stringWriter.WriteLine("{"); @@ -439,73 +442,98 @@ private void WriteRegisterDelegateShardedHandlerMethod(StringWriter stringWriter stringWriter.WriteLine(); stringWriter.WriteIndentation(1); - stringWriter.WriteLine("private static void RegisterDelegateShardedHandler(global::NetCord.Gateway.ShardedGatewayClient client, global::NetCord.Hosting.Gateway.IDelegateShardedGatewayHandlerBase handler)"); + stringWriter.WriteLine("private static void RegisterDelegateShardedHandler(IServiceProvider services, global::NetCord.Gateway.ShardedGatewayClient client, global::NetCord.Hosting.Gateway.DelegateShardedGatewayHandlerMetadata handlerMetadata)"); stringWriter.WriteIndentation(1); - stringWriter.Write("{"); + stringWriter.WriteLine("{"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("switch (handlerMetadata.EventId)"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("{"); - int i = 0; - foreach (var group in events.GroupBy(e => e.Type, SymbolEqualityComparer.Default)) + int eventsLength = events.Length; + for (int i = 0; i < eventsLength; i++) { - var eventType = (INamedTypeSymbol)group.Key!; + var eventSymbol = events[i]; - stringWriter.WriteLine(); + stringWriter.WriteIndentation(3); + stringWriter.Write("case global::NetCord.Hosting.Gateway.GatewayEventId."); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(":"); - stringWriter.WriteIndentation(2); - stringWriter.Write("if (handler is global::NetCord.Hosting.Gateway.IDelegateShardedGatewayHandler"); + stringWriter.WriteIndentation(4); + stringWriter.Write("var typedHandler"); + stringWriter.Write(i); + stringWriter.Write(" = (global::System.Func"); + stringWriter.Write(", "); } - stringWriter.Write(" delegateGatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(")"); + stringWriter.WriteLine("global::System.IServiceProvider, global::System.Threading.Tasks.ValueTask>)handlerMetadata.Handler;"); - stringWriter.WriteIndentation(2); - stringWriter.WriteLine("{"); + stringWriter.WriteIndentation(4); + stringWriter.Write("client."); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine(" += isSingleton"); - stringWriter.WriteIndentation(3); - stringWriter.Write("switch (delegateGatewayHandler"); + stringWriter.WriteIndentation(5); + stringWriter.Write("? (client"); + + if (eventType.Arity is not 1) + stringWriter.Write(", arg"); + + stringWriter.Write(") => typedHandler"); stringWriter.Write(i); - stringWriter.WriteLine(".Name)"); + stringWriter.Write("(client, "); - stringWriter.WriteIndentation(3); + if (eventType.Arity is not 1) + stringWriter.Write("arg, "); + + stringWriter.WriteLine("services)"); + + stringWriter.WriteIndentation(5); + stringWriter.Write(": async (client"); + + if (eventType.Arity is not 1) + stringWriter.Write(", arg"); + + stringWriter.WriteLine(") =>"); + + stringWriter.WriteIndentation(5); stringWriter.WriteLine("{"); - foreach (var eventSymbol in group) - { - stringWriter.WriteIndentation(4); - stringWriter.Write("case \""); - stringWriter.Write(eventSymbol.Name); - stringWriter.WriteLine("\":"); - - stringWriter.WriteIndentation(5); - stringWriter.Write("client."); - stringWriter.Write(eventSymbol.Name); - stringWriter.Write(" += delegateGatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(".HandleAsync;"); - - stringWriter.WriteIndentation(5); - stringWriter.WriteLine("break;"); - } + stringWriter.WriteIndentation(6); + stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); - stringWriter.WriteIndentation(3); - stringWriter.WriteLine("}"); + stringWriter.WriteIndentation(6); + stringWriter.Write("await typedHandler"); + stringWriter.Write(i); + stringWriter.Write("(client, "); - stringWriter.WriteIndentation(3); - stringWriter.WriteLine("return;"); + if (eventType.Arity is not 1) + stringWriter.Write("arg, "); - stringWriter.WriteIndentation(2); - stringWriter.WriteLine("}"); + stringWriter.WriteLine("scope.ServiceProvider);"); + + stringWriter.WriteIndentation(5); + stringWriter.WriteLine("};"); - i++; + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("break;"); } + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("}"); + stringWriter.WriteIndentation(1); stringWriter.WriteLine("}"); } @@ -515,10 +543,16 @@ private void WriteRegisterClassShardedHandlerMethod(StringWriter stringWriter, I stringWriter.WriteLine(); stringWriter.WriteIndentation(1); - stringWriter.WriteLine("private static void RegisterClassShardedHandler(global::NetCord.Gateway.ShardedGatewayClient client, global::NetCord.Hosting.Gateway.IShardedGatewayHandler handler)"); + stringWriter.WriteLine("private static void RegisterClassShardedHandler(global::System.IServiceProvider services, global::NetCord.Gateway.ShardedGatewayClient client, global::NetCord.Hosting.Gateway.ClassShardedGatewayHandlerMetadata handlerMetadata)"); stringWriter.WriteIndentation(1); - stringWriter.Write("{"); + stringWriter.WriteLine("{"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var handlerType = handlerMetadata.HandlerType;"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("var isSingleton = handlerMetadata.IsSingleton;"); int eventsLength = events.Length; @@ -526,21 +560,57 @@ private void WriteRegisterClassShardedHandlerMethod(StringWriter stringWriter, I { var eventSymbol = events[i]; + var eventType = (INamedTypeSymbol)eventSymbol.Type; + stringWriter.WriteLine(); stringWriter.WriteIndentation(2); - stringWriter.Write("if (handler is global::NetCord.Hosting.Gateway.I"); + stringWriter.Write("if (typeof(global::NetCord.Hosting.Gateway.I"); stringWriter.Write(eventSymbol.Name); - stringWriter.Write("ShardedGatewayHandler gatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(")"); + stringWriter.WriteLine("ShardedGatewayHandler).IsAssignableFrom(handlerType))"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("{"); stringWriter.WriteIndentation(3); stringWriter.Write("client."); stringWriter.Write(eventSymbol.Name); - stringWriter.Write(" += gatewayHandler"); - stringWriter.Write(i); - stringWriter.WriteLine(".HandleAsync;"); + stringWriter.WriteLine(" += isSingleton"); + + stringWriter.WriteIndentation(4); + stringWriter.Write("? ((global::NetCord.Hosting.Gateway.I"); + stringWriter.Write(eventSymbol.Name); + stringWriter.WriteLine("ShardedGatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(services, handlerMetadata.HandlerType)).HandleAsync"); + + stringWriter.WriteIndentation(4); + stringWriter.Write(": async (client"); + + if (eventType.Arity is not 1) + stringWriter.Write(", arg"); + + stringWriter.WriteLine(") =>"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("{"); + + stringWriter.WriteIndentation(5); + stringWriter.WriteLine("await using var scope = global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.CreateAsyncScope(services);"); + + stringWriter.WriteIndentation(5); + stringWriter.Write("await ((global::NetCord.Hosting.Gateway.I"); + stringWriter.Write(eventSymbol.Name); + stringWriter.Write("ShardedGatewayHandler)global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(scope.ServiceProvider, handlerMetadata.HandlerType)).HandleAsync(client"); + + if (eventType.Arity is not 1) + stringWriter.Write(", arg"); + + stringWriter.WriteLine(");"); + + stringWriter.WriteIndentation(4); + stringWriter.WriteLine("};"); + + stringWriter.WriteIndentation(2); + stringWriter.WriteLine("}"); } stringWriter.WriteIndentation(1); From bbf40994ed8e25218805e6fc71114148e2632fe0 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Thu, 2 Jul 2026 20:22:14 +0200 Subject: [PATCH 4/5] Add missing xml comments and move handler metadata to GatewayHandlers.cs --- ...tewayHandlerServiceCollectionExtensions.cs | 46 +++++-------------- .../Gateway/GatewayHandlers.cs | 34 ++++++++++++++ 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs index 35a5afb71..55d537eb2 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlerServiceCollectionExtensions.cs @@ -8,40 +8,6 @@ namespace NetCord.Hosting.Gateway; -internal abstract class GatewayHandlerMetadata(bool isSingleton) -{ - public bool IsSingleton => isSingleton; -} - -internal sealed class ClassGatewayHandlerMetadata(Type handlerType, bool isSingleton) : GatewayHandlerMetadata(isSingleton) -{ - public Type HandlerType => handlerType; -} - -internal sealed class DelegateGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : GatewayHandlerMetadata(isSingleton) -{ - public Delegate Handler => handler; - - public GatewayEventId EventId => eventId; -} - -internal abstract class ShardedGatewayHandlerMetadata(bool isSingleton) -{ - public bool IsSingleton => isSingleton; -} - -internal sealed class ClassShardedGatewayHandlerMetadata(Type handlerType, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) -{ - public Type HandlerType => handlerType; -} - -internal sealed class DelegateShardedGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) -{ - public Delegate Handler => handler; - - public GatewayEventId EventId => eventId; -} - public static class GatewayHandlerServiceCollectionExtensions { /// @@ -49,6 +15,7 @@ public static class GatewayHandlerServiceCollectionExtensions /// /// The type of the to add. /// The to add the to. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IGatewayHandler { @@ -64,6 +31,7 @@ public static class GatewayHandlerServiceCollectionExtensions /// The type of the to add. /// The to add the to. /// The factory that creates the . + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddGatewayHandler(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IGatewayHandler { @@ -78,6 +46,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection se /// /// The to add the to. /// The type of the to add. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -93,6 +62,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection servi /// The to add the to. /// The gateway event. /// The delegate that represents the handler. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -111,6 +81,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection servi /// The to add the to. /// The gateway event. /// The delegate that represents the handler. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -127,6 +98,7 @@ public static IServiceCollection AddGatewayHandler(this IServiceCollection se /// /// The to add the implementations to. /// The assembly to scan for implementations. + /// The of the implementations. /// A reference to this instance after the operation has completed. [RequiresUnreferencedCode("Types might be removed")] public static IServiceCollection AddGatewayHandlers(this IServiceCollection services, Assembly assembly, ServiceLifetime lifetime = ServiceLifetime.Singleton) @@ -142,6 +114,7 @@ public static IServiceCollection AddGatewayHandlers(this IServiceCollection serv /// /// The type of the to add. /// The to add the to. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler<[DAM(DAMT.PublicConstructors)] T>(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IShardedGatewayHandler { @@ -157,6 +130,7 @@ public static IServiceCollection AddGatewayHandlers(this IServiceCollection serv /// The type of the to add. /// The to add the to. /// The factory that creates the . + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IShardedGatewayHandler { @@ -171,6 +145,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollec /// /// The to add the to. /// The type of the to add. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, [DAM(DAMT.PublicConstructors)] Type handlerType, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -186,6 +161,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// The to add the to. /// The gateway event. /// The delegate that represents the handler. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -204,6 +180,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollectio /// The to add the to. /// The gateway event. /// The delegate that represents the handler. + /// The of the . /// A reference to this instance after the operation has completed. public static IServiceCollection AddShardedGatewayHandler(this IServiceCollection services, GatewayEvent gatewayEvent, Delegate handler, ServiceLifetime lifetime = ServiceLifetime.Singleton) { @@ -220,6 +197,7 @@ public static IServiceCollection AddShardedGatewayHandler(this IServiceCollec /// /// The to add the implementations to. /// The assembly to scan for implementations. + /// The of the implementations. /// A reference to this instance after the operation has completed. [RequiresUnreferencedCode("Types might be removed")] public static IServiceCollection AddShardedGatewayHandlers(this IServiceCollection services, Assembly assembly, ServiceLifetime lifetime = ServiceLifetime.Singleton) diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs index 15eaac7bb..1e7995f78 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayHandlers.cs @@ -3,3 +3,37 @@ namespace NetCord.Hosting.Gateway; public interface IGatewayHandler; public interface IShardedGatewayHandler; + +internal abstract class GatewayHandlerMetadata(bool isSingleton) +{ + public bool IsSingleton => isSingleton; +} + +internal sealed class ClassGatewayHandlerMetadata(Type handlerType, bool isSingleton) : GatewayHandlerMetadata(isSingleton) +{ + public Type HandlerType => handlerType; +} + +internal sealed class DelegateGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : GatewayHandlerMetadata(isSingleton) +{ + public Delegate Handler => handler; + + public GatewayEventId EventId => eventId; +} + +internal abstract class ShardedGatewayHandlerMetadata(bool isSingleton) +{ + public bool IsSingleton => isSingleton; +} + +internal sealed class ClassShardedGatewayHandlerMetadata(Type handlerType, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) +{ + public Type HandlerType => handlerType; +} + +internal sealed class DelegateShardedGatewayHandlerMetadata(Delegate handler, GatewayEventId eventId, bool isSingleton) : ShardedGatewayHandlerMetadata(isSingleton) +{ + public Delegate Handler => handler; + + public GatewayEventId EventId => eventId; +} From 9dfbe03ed264cd57f1d79ddfcaae1383125af5c2 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Thu, 2 Jul 2026 20:23:25 +0200 Subject: [PATCH 5/5] Remove commented out code --- .../Gateway/ShardedGatewayClientHostedService.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs index 5040f36f2..5c71d0e09 100644 --- a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs +++ b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostedService.cs @@ -20,14 +20,6 @@ public Task StartAsync(CancellationToken cancellationToken) RegisterDelegateShardedHandler(services, client, (DelegateShardedGatewayHandlerMetadata)handlerMetadata); } - // foreach (var handler in services.GetServices()) - // { - // if (handler is IDelegateShardedGatewayHandlerBase delegateHandler) - // RegisterDelegateShardedHandler(client, delegateHandler); - // else - // RegisterClassShardedHandler(client, handler); - // } - var options = services.GetRequiredService>().Value; return options.AutoStartStop.GetValueOrDefault(true)