From ca6b81f3d6387f21974bfec7d6fecab5471905a2 Mon Sep 17 00:00:00 2001 From: KubaZ2 Date: Sat, 14 Sep 2024 18:11:18 +0200 Subject: [PATCH] Improve configuration in hosting --- .../events/FirstEventsHosting/Program.cs | 7 +- .../guides/events/IntentsHosting/Program.cs | 5 +- .../services/DependencyInjection/Program.cs | 2 +- .../LocalizationsHosting/Program.cs | 5 +- .../ApplicationCommandInteractionHandler.cs | 4 +- ...tionCommandServiceHostBuilderExtensions.cs | 50 +++++++++ .../ApplicationCommandServiceOptions.cs | 102 ++++++++++++++++- ...mmandServiceServiceCollectionExtensions.cs | 76 ++++++++++++- .../AutocompleteInteractionHandler.cs | 4 +- .../Commands/CommandHandler.cs | 6 +- .../CommandServiceHostBuilderExtensions.cs | 30 +++++ .../Commands/CommandServiceOptions.cs | 101 ++++++++++++++++- ...mmandServiceServiceCollectionExtensions.cs | 44 +++++++- .../ComponentInteractionHandler.cs | 4 +- ...InteractionServiceHostBuilderExtensions.cs | 32 ++++++ .../ComponentInteractionServiceOptions.cs | 77 ++++++++++++- ...ctionServiceServiceCollectionExtensions.cs | 47 +++++++- .../GatewayClientHostBuilderExtensions.cs | 14 +++ .../Gateway/GatewayClientOptions.cs | 57 +++++++++- ...atewayClientServiceCollectionExtensions.cs | 23 +++- ...ardedGatewayClientHostBuilderExtensions.cs | 14 +++ .../Gateway/ShardedGatewayClientOptions.cs | 97 ++++++++++++++++- ...atewayClientServiceCollectionExtensions.cs | 22 +++- .../NetCord.Hosting/NetCord.Hosting.csproj | 2 + .../Rest/RestClientHostBuilderExtensions.cs | 14 +++ .../NetCord.Hosting/Rest/RestClientOptions.cs | 23 +++- .../RestClientServiceCollectionExtensions.cs | 23 +++- NetCord/Gateway/GatewayClient.cs | 40 ++++--- NetCord/Gateway/GatewayClientConfiguration.cs | 11 +- .../GatewayClientConfigurationFactory.cs | 48 ++++++++ NetCord/Gateway/ShardedGatewayClient.cs | 103 +++++++++--------- .../ShardedGatewayClientConfiguration.cs | 6 +- ...hardedGatewayClientConfigurationFactory.cs | 48 ++++++++ NetCord/Gateway/Voice/VoiceClient.cs | 4 +- .../Gateway/Voice/VoiceClientConfiguration.cs | 4 +- NetCord/Rest/RestClient.cs | 2 +- NetCord/Rest/RestClientConfiguration.cs | 2 +- Tests/NetCord.Test.Hosting/Program.cs | 10 +- Tests/NetCord.Test.Sharded.Hosting/Program.cs | 10 +- 39 files changed, 1027 insertions(+), 146 deletions(-) create mode 100644 NetCord/Gateway/GatewayClientConfigurationFactory.cs create mode 100644 NetCord/Gateway/ShardedGatewayClientConfigurationFactory.cs diff --git a/Documentation/guides/events/FirstEventsHosting/Program.cs b/Documentation/guides/events/FirstEventsHosting/Program.cs index 4f2da94f..4e894582 100644 --- a/Documentation/guides/events/FirstEventsHosting/Program.cs +++ b/Documentation/guides/events/FirstEventsHosting/Program.cs @@ -8,14 +8,11 @@ builder.Services .AddDiscordGateway(options => { - options.Configuration = new() - { - Intents = GatewayIntents.GuildMessages + options.Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent | GatewayIntents.DirectMessageReactions - | GatewayIntents.GuildMessageReactions, - }; + | GatewayIntents.GuildMessageReactions; }) .AddGatewayEventHandlers(typeof(Program).Assembly); diff --git a/Documentation/guides/events/IntentsHosting/Program.cs b/Documentation/guides/events/IntentsHosting/Program.cs index 86948c93..a918e937 100644 --- a/Documentation/guides/events/IntentsHosting/Program.cs +++ b/Documentation/guides/events/IntentsHosting/Program.cs @@ -8,8 +8,5 @@ builder.Services .AddDiscordGateway(options => { - options.Configuration = new() - { - Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent, - }; + options.Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent; }); diff --git a/Documentation/guides/services/DependencyInjection/Program.cs b/Documentation/guides/services/DependencyInjection/Program.cs index b9c81365..199b986b 100644 --- a/Documentation/guides/services/DependencyInjection/Program.cs +++ b/Documentation/guides/services/DependencyInjection/Program.cs @@ -16,7 +16,7 @@ builder.Services .AddSingleton() - .AddDiscordGateway(o => o.Configuration = new() { Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent }) + .AddDiscordGateway(o => o.Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent) .AddCommands() .AddApplicationCommands(); diff --git a/Documentation/guides/services/application-commands/LocalizationsHosting/Program.cs b/Documentation/guides/services/application-commands/LocalizationsHosting/Program.cs index 69c77942..92400880 100644 --- a/Documentation/guides/services/application-commands/LocalizationsHosting/Program.cs +++ b/Documentation/guides/services/application-commands/LocalizationsHosting/Program.cs @@ -11,10 +11,7 @@ builder.Services .AddApplicationCommands(options => { - options.Configuration = ApplicationCommandServiceConfiguration.Default with - { - LocalizationsProvider = new JsonLocalizationsProvider(), - }; + options.LocalizationsProvider = new JsonLocalizationsProvider(); }) .AddDiscordGateway(); diff --git a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandInteractionHandler.cs b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandInteractionHandler.cs index 54d49683..64168fe0 100644 --- a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandInteractionHandler.cs +++ b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandInteractionHandler.cs @@ -34,7 +34,7 @@ public ApplicationCommandInteractionHandler(IServiceProvider services, var optionsValue = options.Value; - if (optionsValue.UseScopes) + if (optionsValue.UseScopes.GetValueOrDefault(true)) { _scopeFactory = services.GetService() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes."); _handleAsync = &HandleInteractionWithScopeAsync; @@ -43,7 +43,7 @@ public ApplicationCommandInteractionHandler(IServiceProvider services, _handleAsync = &HandleInteractionAsync; _createContext = optionsValue.CreateContext ?? ContextHelper.CreateContextDelegate(); - _resultHandler = optionsValue.ResultHandler; + _resultHandler = optionsValue.ResultHandler ?? new ApplicationCommandResultHandler(); _client = client; } diff --git a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceHostBuilderExtensions.cs b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceHostBuilderExtensions.cs index 32ef994d..172501a1 100644 --- a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceHostBuilderExtensions.cs @@ -6,6 +6,56 @@ namespace NetCord.Hosting.Services.ApplicationCommands; public static class ApplicationCommandServiceHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions)); + } + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + { + return builder.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action, IServiceProvider> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + { + return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions)); + } + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + where TAutocompleteContext : IAutocompleteInteractionContext + { + return builder.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder, + Action, IServiceProvider> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + where TAutocompleteContext : IAutocompleteInteractionContext + { + return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions)); + } + + // Use + public static IHostBuilder UseApplicationCommands(this IHostBuilder builder) where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext diff --git a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceOptions.cs b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceOptions.cs index 29af31e2..945dfe98 100644 --- a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceOptions.cs +++ b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceOptions.cs @@ -1,22 +1,114 @@ -using NetCord.Gateway; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +using Microsoft.Extensions.Options; + +using NetCord.Gateway; +using NetCord.Services; using NetCord.Services.ApplicationCommands; namespace NetCord.Hosting.Services.ApplicationCommands; +public class ApplicationCommandServiceOptions +{ + public bool? DefaultDMPermission { get; set; } + + public IEnumerable? DefaultIntegrationTypes { get; set; } + + public IEnumerable? DefaultContexts { get; set; } + + /// + /// {0} - parameter name + /// + [StringSyntax(StringSyntaxAttribute.CompositeFormat)] + public string? DefaultParameterDescriptionFormat { get; set; } + + public ILocalizationsProvider? LocalizationsProvider { get; set; } + + public bool? UseScopes { get; set; } +} + public class ApplicationCommandServiceOptions where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext { - public ApplicationCommandServiceConfiguration Configuration { get; set; } = ApplicationCommandServiceConfiguration.Default; + public Dictionary> TypeReaders { get; set; } = ApplicationCommandServiceConfiguration.Default.TypeReaders.ToDictionary(); + + public SlashCommandTypeReader? EnumTypeReader { get; set; } + + public bool? DefaultDMPermission { get; set; } + + public IEnumerable? DefaultIntegrationTypes { get; set; } + + public IEnumerable? DefaultContexts { get; set; } - public bool UseScopes { get; set; } = true; + public ISlashCommandParameterNameProcessor? ParameterNameProcessor { get; set; } + + /// + /// {0} - parameter name + /// + [StringSyntax(StringSyntaxAttribute.CompositeFormat)] + public string? DefaultParameterDescriptionFormat { get; set; } + + public IResultResolverProvider? ResultResolverProvider { get; set; } + + public ILocalizationsProvider? LocalizationsProvider { get; set; } + + public bool? UseScopes { get; set; } public Func? CreateContext { get; set; } - public IApplicationCommandResultHandler ResultHandler { get; set; } = new ApplicationCommandResultHandler(); + public IApplicationCommandResultHandler? ResultHandler { get; set; } + + internal void Apply(IOptions options) + { + var value = options.Value; + + var defaultDMPermission = value.DefaultDMPermission; + if (defaultDMPermission.HasValue) + DefaultDMPermission = defaultDMPermission.GetValueOrDefault(); + + var defaultIntegrationTypes = value.DefaultIntegrationTypes; + if (defaultIntegrationTypes is not null) + DefaultIntegrationTypes = defaultIntegrationTypes; + + var defaultContexts = value.DefaultContexts; + if (defaultContexts is not null) + DefaultContexts = defaultContexts; + + var defaultParameterDescriptionFormat = value.DefaultParameterDescriptionFormat; + if (defaultParameterDescriptionFormat is not null) + DefaultParameterDescriptionFormat = defaultParameterDescriptionFormat; + + var localizationsProvider = value.LocalizationsProvider; + if (localizationsProvider is not null) + LocalizationsProvider = localizationsProvider; + + var useScopes = value.UseScopes; + if (useScopes.HasValue) + UseScopes = useScopes; + } + + internal ApplicationCommandServiceConfiguration CreateConfiguration() + { + var configuration = ApplicationCommandServiceConfiguration.Default; + + return configuration with + { + TypeReaders = TypeReaders.ToImmutableDictionary(), + EnumTypeReader = EnumTypeReader ?? configuration.EnumTypeReader, + DefaultDMPermission = DefaultDMPermission ?? configuration.DefaultDMPermission, + DefaultIntegrationTypes = DefaultIntegrationTypes ?? configuration.DefaultIntegrationTypes, + DefaultContexts = DefaultContexts ?? configuration.DefaultContexts, + ParameterNameProcessor = ParameterNameProcessor ?? configuration.ParameterNameProcessor, + DefaultParameterDescriptionFormat = DefaultParameterDescriptionFormat ?? configuration.DefaultParameterDescriptionFormat, + ResultResolverProvider = ResultResolverProvider ?? configuration.ResultResolverProvider, + LocalizationsProvider = LocalizationsProvider ?? configuration.LocalizationsProvider, + }; + } } public class ApplicationCommandServiceOptions : ApplicationCommandServiceOptions where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext where TAutocompleteContext : IAutocompleteInteractionContext { public Func? CreateAutocompleteContext { get; set; } - public IAutocompleteInteractionResultHandler AutocompleteResultHandler { get; set; } = new AutocompleteInteractionResultHandler(); + public IAutocompleteInteractionResultHandler? AutocompleteResultHandler { get; set; } } diff --git a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceServiceCollectionExtensions.cs index 9cc52704..a9ed8676 100644 --- a/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/ApplicationCommands/ApplicationCommandServiceServiceCollectionExtensions.cs @@ -9,6 +9,68 @@ namespace NetCord.Hosting.Services.ApplicationCommands; public static class ApplicationCommandServiceServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action configureOptions) + { + return services.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + { + return services.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action, IServiceProvider> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + { + services + .AddOptions>() + .PostConfigure(configureOptions); + + return services; + } + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + where TAutocompleteContext : IAutocompleteInteractionContext + { + return services.ConfigureApplicationCommands((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services, + Action, IServiceProvider> configureOptions) + where TInteraction : ApplicationCommandInteraction + where TContext : IApplicationCommandContext + where TAutocompleteContext : IAutocompleteInteractionContext + { + services + .AddOptions>() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddApplicationCommands(this IServiceCollection services) where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext @@ -31,12 +93,15 @@ public static IServiceCollection AddApplicationCommands( { services .AddOptions>() - .Configure(configureOptions); + .BindConfiguration("Discord") + .BindConfiguration("Discord:ApplicationCommands") + .Configure>((options, baseOptions) => options.Apply(baseOptions)) + .PostConfigure(configureOptions); services.AddSingleton(services => { var options = services.GetRequiredService>>().Value; - return new ApplicationCommandService(options.Configuration); + return new ApplicationCommandService(options.CreateConfiguration()); }); services.AddSingleton(services => services.GetRequiredService>()); services.AddSingleton(services => services.GetRequiredService>()); @@ -75,14 +140,17 @@ public static IServiceCollection AddApplicationCommands>() - .Configure(configureOptions); + .BindConfiguration("Discord") + .BindConfiguration("Discord:ApplicationCommands") + .Configure>((options, baseOptions) => options.Apply(baseOptions)) + .PostConfigure(configureOptions); services.AddSingleton>>(services => services.GetRequiredService>>()); services.AddSingleton(services => { var options = services.GetRequiredService>>().Value; - return new ApplicationCommandService(options.Configuration); + return new ApplicationCommandService(options.CreateConfiguration()); }); services.AddSingleton>(services => services.GetRequiredService>()); services.AddSingleton(services => services.GetRequiredService>()); diff --git a/Hosting/NetCord.Hosting.Services/ApplicationCommands/AutocompleteInteractionHandler.cs b/Hosting/NetCord.Hosting.Services/ApplicationCommands/AutocompleteInteractionHandler.cs index 4b72bba2..db92b732 100644 --- a/Hosting/NetCord.Hosting.Services/ApplicationCommands/AutocompleteInteractionHandler.cs +++ b/Hosting/NetCord.Hosting.Services/ApplicationCommands/AutocompleteInteractionHandler.cs @@ -34,7 +34,7 @@ public AutocompleteInteractionHandler(IServiceProvider services, var optionsValue = options.Value; - if (optionsValue.UseScopes) + if (optionsValue.UseScopes.GetValueOrDefault(true)) { _scopeFactory = services.GetService() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes."); _handleAsync = &HandleInteractionWithScopeAsync; @@ -43,7 +43,7 @@ public AutocompleteInteractionHandler(IServiceProvider services, _handleAsync = &HandleInteractionAsync; _createContext = optionsValue.CreateAutocompleteContext ?? ContextHelper.CreateContextDelegate(); - _resultHandler = optionsValue.AutocompleteResultHandler; + _resultHandler = optionsValue.AutocompleteResultHandler ?? new AutocompleteInteractionResultHandler(); _client = client; } diff --git a/Hosting/NetCord.Hosting.Services/Commands/CommandHandler.cs b/Hosting/NetCord.Hosting.Services/Commands/CommandHandler.cs index 258a6d99..68cc1ed3 100644 --- a/Hosting/NetCord.Hosting.Services/Commands/CommandHandler.cs +++ b/Hosting/NetCord.Hosting.Services/Commands/CommandHandler.cs @@ -35,7 +35,7 @@ public CommandHandler(IServiceProvider services, var optionsValue = options.Value; - if (optionsValue.UseScopes) + if (optionsValue.UseScopes.GetValueOrDefault(true)) { _scopeFactory = services.GetService() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes."); _handleAsync = &HandleMessageWithScopeAsync; @@ -45,7 +45,7 @@ public CommandHandler(IServiceProvider services, _getPrefixLengthAsync = GetGetPrefixLengthAsyncDelegate(optionsValue); _createContext = optionsValue.CreateContext ?? ContextHelper.CreateContextDelegate(); - _resultHandler = optionsValue.ResultHandler; + _resultHandler = optionsValue.ResultHandler ?? new CommandResultHandler(); _client = client; } @@ -60,7 +60,7 @@ private static Func> Ge if (prefix is not null) { if (prefixes is not null) - throw new InvalidOperationException($"Both '{nameof(options.Prefix)}' and '{options.Prefixes}' cannot be set at the same time."); + throw new InvalidOperationException($"Both '{nameof(options.Prefix)}' and '{nameof(options.Prefixes)}' cannot be set at the same time."); return (message, _, _) => new(!message.Author.IsBot && message.Content.StartsWith(prefix) ? prefix.Length : -1); } diff --git a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceHostBuilderExtensions.cs b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceHostBuilderExtensions.cs index b166f1b4..ff14d6ef 100644 --- a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceHostBuilderExtensions.cs @@ -6,6 +6,36 @@ namespace NetCord.Hosting.Services.Commands; public static class CommandServiceHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureCommands(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureCommands((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureCommands(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureServices((context, services) => services.ConfigureCommands(configureOptions)); + } + + public static IHostBuilder ConfigureCommands(this IHostBuilder builder, + Action> configureOptions) + where TContext : ICommandContext + { + return builder.ConfigureCommands((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureCommands(this IHostBuilder builder, + Action, IServiceProvider> configureOptions) + where TContext : ICommandContext + { + return builder.ConfigureServices((context, services) => services.ConfigureCommands(configureOptions)); + } + + // Use + public static IHostBuilder UseCommands(this IHostBuilder builder) where TContext : ICommandContext { diff --git a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceOptions.cs b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceOptions.cs index de132b81..f2d82c1c 100644 --- a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceOptions.cs +++ b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceOptions.cs @@ -1,13 +1,58 @@ -using NetCord.Gateway; +using System.Collections.Immutable; +using System.Globalization; + +using Microsoft.Extensions.Options; + +using NetCord.Gateway; +using NetCord.Services; using NetCord.Services.Commands; namespace NetCord.Hosting.Services.Commands; +public class CommandServiceOptions +{ + /// + /// Default = ' ', '\n' + /// + public IEnumerable? ParameterSeparators { get; set; } + + /// + /// Default = + /// + public bool? IgnoreCase { get; set; } + + public CultureInfo? CultureInfo { get; set; } + + public bool? UseScopes { get; set; } + + public string? Prefix { get; set; } + + public IReadOnlyList? Prefixes { get; set; } + + public Func>? GetPrefixLengthAsync { get; set; } +} + public class CommandServiceOptions where TContext : ICommandContext { - public CommandServiceConfiguration Configuration { get; set; } = CommandServiceConfiguration.Default; + public Dictionary> TypeReaders { get; set; } = CommandServiceConfiguration.Default.TypeReaders.ToDictionary(); + + public CommandTypeReader? EnumTypeReader { get; set; } - public bool UseScopes { get; set; } = true; + /// + /// Default = ' ', '\n' + /// + public IEnumerable? ParameterSeparators { get; set; } + + /// + /// Default = + /// + public bool? IgnoreCase { get; set; } + + public CultureInfo? CultureInfo { get; set; } + + public IResultResolverProvider? ResultResolverProvider { get; set; } + + public bool? UseScopes { get; set; } public string? Prefix { get; set; } @@ -17,5 +62,53 @@ public class CommandServiceOptions where TContext : ICommandContext public Func? CreateContext { get; set; } - public ICommandResultHandler ResultHandler { get; set; } = new CommandResultHandler(); + public ICommandResultHandler? ResultHandler { get; set; } + + internal void Apply(IOptions options) + { + var value = options.Value; + + var parameterSeparators = value.ParameterSeparators; + if (parameterSeparators is not null) + ParameterSeparators = parameterSeparators; + + var ignoreCase = value.IgnoreCase; + if (ignoreCase.HasValue) + IgnoreCase = ignoreCase; + + var cultureInfo = value.CultureInfo; + if (cultureInfo is not null) + CultureInfo = cultureInfo; + + var useScopes = value.UseScopes; + if (useScopes.HasValue) + UseScopes = useScopes; + + var prefix = value.Prefix; + if (prefix is not null) + Prefix = prefix; + + var prefixes = value.Prefixes; + if (prefixes is not null) + Prefixes = prefixes; + + var getPrefixLengthAsync = value.GetPrefixLengthAsync; + if (getPrefixLengthAsync is not null) + GetPrefixLengthAsync = getPrefixLengthAsync; + } + + internal CommandServiceConfiguration CreateConfiguration() + { + var configuration = CommandServiceConfiguration.Default; + + return configuration with + { + TypeReaders = TypeReaders.ToImmutableDictionary(), + EnumTypeReader = EnumTypeReader ?? configuration.EnumTypeReader, + ParameterSeparators = ParameterSeparators ?? configuration.ParameterSeparators, + IgnoreCase = IgnoreCase ?? configuration.IgnoreCase, + CultureInfo = CultureInfo ?? configuration.CultureInfo, + ResultResolverProvider = ResultResolverProvider ?? configuration.ResultResolverProvider, + }; + } } diff --git a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceServiceCollectionExtensions.cs index 7228ac6e..4d4c7ebb 100644 --- a/Hosting/NetCord.Hosting.Services/Commands/CommandServiceServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/Commands/CommandServiceServiceCollectionExtensions.cs @@ -9,6 +9,44 @@ namespace NetCord.Hosting.Services.Commands; public static class CommandServiceServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureCommands(this IServiceCollection services, + Action configureOptions) + { + return services.ConfigureCommands((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureCommands(this IServiceCollection services, + Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + public static IServiceCollection ConfigureCommands(this IServiceCollection services, + Action> configureOptions) + where TContext : ICommandContext + { + return services.ConfigureCommands((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureCommands(this IServiceCollection services, + Action, IServiceProvider> configureOptions) + where TContext : ICommandContext + { + services + .AddOptions>() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddCommands(this IServiceCollection services) where TContext : ICommandContext { @@ -29,12 +67,14 @@ public static IServiceCollection AddCommands(this IServiceCollection s services .AddOptions>() .BindConfiguration("Discord") - .Configure(configureOptions); + .BindConfiguration("Discord:Commands") + .Configure>((options, baseOptions) => options.Apply(baseOptions)) + .PostConfigure(configureOptions); services.AddSingleton(services => { var options = services.GetRequiredService>>().Value; - return new CommandService(options.Configuration); + return new CommandService(options.CreateConfiguration()); }); services.AddSingleton(services => services.GetRequiredService>()); diff --git a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionHandler.cs b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionHandler.cs index 7a841413..54015bc1 100644 --- a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionHandler.cs +++ b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionHandler.cs @@ -34,7 +34,7 @@ public ComponentInteractionHandler(IServiceProvider services, var optionsValue = options.Value; - if (optionsValue.UseScopes) + if (optionsValue.UseScopes.GetValueOrDefault(true)) { _scopeFactory = services.GetService() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes."); _handleAsync = &HandleInteractionWithScopeAsync; @@ -43,7 +43,7 @@ public ComponentInteractionHandler(IServiceProvider services, _handleAsync = &HandleInteractionAsync; _createContext = optionsValue.CreateContext ?? ContextHelper.CreateContextDelegate(); - _resultHandler = optionsValue.ResultHandler; + _resultHandler = optionsValue.ResultHandler ?? new ComponentInteractionResultHandler(); _client = client; } diff --git a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceHostBuilderExtensions.cs b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceHostBuilderExtensions.cs index d10fa149..161ae8f6 100644 --- a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceHostBuilderExtensions.cs @@ -6,6 +6,38 @@ namespace NetCord.Hosting.Services.ComponentInteractions; public static class ComponentInteractionServiceHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureComponentInteractions(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureComponentInteractions((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureComponentInteractions(this IHostBuilder builder, + Action configureOptions) + { + return builder.ConfigureServices((context, services) => services.ConfigureComponentInteractions(configureOptions)); + } + + public static IHostBuilder ConfigureComponentInteractions(this IHostBuilder builder, + Action> configureOptions) + where TInteraction : ComponentInteraction + where TContext : IComponentInteractionContext + { + return builder.ConfigureComponentInteractions((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureComponentInteractions(this IHostBuilder builder, + Action, IServiceProvider> configureOptions) + where TInteraction : ComponentInteraction + where TContext : IComponentInteractionContext + { + return builder.ConfigureServices((context, services) => services.ConfigureComponentInteractions(configureOptions)); + } + + // Use + public static IHostBuilder UseComponentInteractions(this IHostBuilder builder) where TInteraction : ComponentInteraction where TContext : IComponentInteractionContext diff --git a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceOptions.cs b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceOptions.cs index 21d5d51f..7fcc6796 100644 --- a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceOptions.cs +++ b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceOptions.cs @@ -1,15 +1,84 @@ -using NetCord.Gateway; +using System.Collections.Immutable; +using System.Globalization; + +using Microsoft.Extensions.Options; + +using NetCord.Gateway; +using NetCord.Services; using NetCord.Services.ComponentInteractions; namespace NetCord.Hosting.Services.ComponentInteractions; +public class ComponentInteractionServiceOptions +{ + /// + /// Default = + /// + public bool? IgnoreCase { get; set; } + + public char? ParameterSeparator { get; set; } + + public CultureInfo? CultureInfo { get; set; } + + public bool? UseScopes { get; set; } +} + public class ComponentInteractionServiceOptions where TInteraction : Interaction where TContext : IComponentInteractionContext { - public ComponentInteractionServiceConfiguration Configuration { get; set; } = ComponentInteractionServiceConfiguration.Default; + public Dictionary> TypeReaders { get; set; } = ComponentInteractionServiceConfiguration.Default.TypeReaders.ToDictionary(); + + public ComponentInteractionTypeReader? EnumTypeReader { get; set; } + + /// + /// Default = + /// + public bool? IgnoreCase { get; set; } - public bool UseScopes { get; set; } = true; + public char? ParameterSeparator { get; set; } + + public CultureInfo? CultureInfo { get; set; } + + public IResultResolverProvider? ResultResolverProvider { get; set; } + + public bool? UseScopes { get; set; } public Func? CreateContext { get; set; } - public IComponentInteractionResultHandler ResultHandler { get; set; } = new ComponentInteractionResultHandler(); + public IComponentInteractionResultHandler? ResultHandler { get; set; } + + internal void Apply(IOptions options) + { + var value = options.Value; + + var ignoreCase = value.IgnoreCase; + if (ignoreCase.HasValue) + IgnoreCase = ignoreCase; + + var parameterSeparator = value.ParameterSeparator; + if (parameterSeparator.HasValue) + ParameterSeparator = parameterSeparator; + + var cultureInfo = value.CultureInfo; + if (cultureInfo is not null) + CultureInfo = cultureInfo; + + var useScopes = value.UseScopes; + if (useScopes.HasValue) + UseScopes = useScopes; + } + + internal ComponentInteractionServiceConfiguration CreateConfiguration() + { + var configuration = ComponentInteractionServiceConfiguration.Default; + + return configuration with + { + TypeReaders = TypeReaders.ToImmutableDictionary(), + EnumTypeReader = EnumTypeReader ?? configuration.EnumTypeReader, + IgnoreCase = IgnoreCase ?? configuration.IgnoreCase, + ParameterSeparator = ParameterSeparator ?? configuration.ParameterSeparator, + CultureInfo = CultureInfo ?? configuration.CultureInfo, + ResultResolverProvider = ResultResolverProvider ?? configuration.ResultResolverProvider, + }; + } } diff --git a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceServiceCollectionExtensions.cs index a154f24d..47aa7b0a 100644 --- a/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting.Services/ComponentInteractions/ComponentInteractionServiceServiceCollectionExtensions.cs @@ -9,6 +9,46 @@ namespace NetCord.Hosting.Services.ComponentInteractions; public static class ComponentInteractionServiceServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureComponentInteractions(this IServiceCollection services, + Action configureOptions) + { + return services.ConfigureComponentInteractions((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureComponentInteractions(this IServiceCollection services, + Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + public static IServiceCollection ConfigureComponentInteractions(this IServiceCollection services, + Action> configureOptions) + where TInteraction : ComponentInteraction + where TContext : IComponentInteractionContext + { + return services.ConfigureComponentInteractions((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureComponentInteractions(this IServiceCollection services, + Action, IServiceProvider> configureOptions) + where TInteraction : ComponentInteraction + where TContext : IComponentInteractionContext + { + services + .AddOptions>() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddComponentInteractions(this IServiceCollection services) where TInteraction : ComponentInteraction where TContext : IComponentInteractionContext @@ -31,12 +71,15 @@ public static IServiceCollection AddComponentInteractions>() - .Configure(configureOptions); + .BindConfiguration("Discord") + .BindConfiguration("Discord:ComponentInteractions") + .Configure>((options, baseOptions) => options.Apply(baseOptions)) + .PostConfigure(configureOptions); services.AddSingleton(services => { var options = services.GetRequiredService>>().Value; - return new ComponentInteractionService(options.Configuration); + return new ComponentInteractionService(options.CreateConfiguration()); }); services.AddSingleton(services => services.GetRequiredService>()); diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayClientHostBuilderExtensions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayClientHostBuilderExtensions.cs index 9c1b67f2..7ef326c1 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayClientHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayClientHostBuilderExtensions.cs @@ -4,6 +4,20 @@ namespace NetCord.Hosting.Gateway; public static class GatewayClientHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureDiscordGateway(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureDiscordGateway((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureDiscordGateway(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureServices((_, services) => services.ConfigureDiscordGateway(configureOptions)); + } + + // Use + public static IHostBuilder UseDiscordGateway(this IHostBuilder builder) { return builder.UseDiscordGateway((_, _) => { }); diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayClientOptions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayClientOptions.cs index 4f6ba267..7ef3fd62 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayClientOptions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayClientOptions.cs @@ -1,6 +1,11 @@ using System.ComponentModel.DataAnnotations; using NetCord.Gateway; +using NetCord.Gateway.Compression; +using NetCord.Gateway.LatencyTimers; +using NetCord.Gateway.ReconnectStrategies; +using NetCord.Gateway.WebSockets; +using NetCord.Rest; namespace NetCord.Hosting.Gateway; @@ -11,5 +16,55 @@ public class GatewayClientOptions : IDiscordOptions public string? PublicKey { get; set; } - public GatewayClientConfiguration? Configuration { get; set; } + public IWebSocketConnectionProvider? WebSocketConnectionProvider { get; set; } + + public IRateLimiterProvider? RateLimiterProvider { get; set; } + + public WebSocketPayloadProperties? DefaultPayloadProperties { get; set; } + + public IReconnectStrategy? ReconnectStrategy { get; set; } + + public ILatencyTimer? LatencyTimer { get; set; } + + public ApiVersion? Version { get; set; } + + public IGatewayClientCache? Cache { get; set; } + + public IGatewayCompression? Compression { get; set; } + + public GatewayIntents? Intents { get; set; } + + public string? Hostname { get; set; } + + public ConnectionPropertiesProperties? ConnectionProperties { get; set; } + + public int? LargeThreshold { get; set; } + + public PresenceProperties? Presence { get; set; } + + public Shard? Shard { get; set; } + + public bool? CacheDMChannels { get; set; } + + public RestClientConfiguration? RestClientConfiguration { get; set; } + + internal GatewayClientConfiguration CreateConfiguration() + { + return GatewayClientConfigurationFactory.Create(WebSocketConnectionProvider, + RateLimiterProvider, + DefaultPayloadProperties, + ReconnectStrategy, + LatencyTimer, + Version, + Cache, + Compression, + Intents, + Hostname, + ConnectionProperties, + LargeThreshold, + Presence, + Shard, + CacheDMChannels, + RestClientConfiguration); + } } diff --git a/Hosting/NetCord.Hosting/Gateway/GatewayClientServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Gateway/GatewayClientServiceCollectionExtensions.cs index 452d1fd8..7f1b2b15 100644 --- a/Hosting/NetCord.Hosting/Gateway/GatewayClientServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/GatewayClientServiceCollectionExtensions.cs @@ -7,6 +7,25 @@ namespace NetCord.Hosting.Gateway; public static class GatewayClientServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureDiscordGateway(this IServiceCollection services, Action configureOptions) + { + return services.ConfigureDiscordGateway((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureDiscordGateway(this IServiceCollection services, + Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddDiscordGateway(this IServiceCollection services) { return services.AddDiscordGateway((_, _) => { }); @@ -22,7 +41,7 @@ public static IServiceCollection AddDiscordGateway(this IServiceCollection servi services .AddOptions() .BindConfiguration("Discord") - .Configure(configureOptions) + .PostConfigure(configureOptions) .ValidateDataAnnotations(); services.AddSingleton>(services => services.GetRequiredService>()); @@ -36,7 +55,7 @@ public static IServiceCollection AddDiscordGateway(this IServiceCollection servi if (token is not IEntityToken entityToken) throw new InvalidOperationException($"Unable to initialize '{nameof(GatewayClient)}'. The provided token must implement the '{nameof(IEntityToken)}' interface."); - return new GatewayClient(entityToken, options.Configuration); + return new GatewayClient(entityToken, options.CreateConfiguration()); }); services.AddSingleton(services => services.GetRequiredService().Rest); diff --git a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostBuilderExtensions.cs b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostBuilderExtensions.cs index d094491e..1aa5b7e8 100644 --- a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientHostBuilderExtensions.cs @@ -4,6 +4,20 @@ namespace NetCord.Hosting.Gateway; public static class ShardedGatewayClientHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureDiscordShardedGateway(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureDiscordShardedGateway((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureDiscordShardedGateway(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureServices((_, services) => services.ConfigureDiscordShardedGateway(configureOptions)); + } + + // Use + public static IHostBuilder UseDiscordShardedGateway(this IHostBuilder builder) { return builder.UseDiscordShardedGateway((_, _) => { }); diff --git a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientOptions.cs b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientOptions.cs index 28186324..ddf47844 100644 --- a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientOptions.cs +++ b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientOptions.cs @@ -1,6 +1,12 @@ using System.ComponentModel.DataAnnotations; +using System.Runtime.CompilerServices; using NetCord.Gateway; +using NetCord.Gateway.Compression; +using NetCord.Gateway.LatencyTimers; +using NetCord.Gateway.ReconnectStrategies; +using NetCord.Gateway.WebSockets; +using NetCord.Rest; namespace NetCord.Hosting.Gateway; @@ -11,5 +17,94 @@ public class ShardedGatewayClientOptions : IDiscordOptions public string? PublicKey { get; set; } - public ShardedGatewayClientConfiguration? Configuration { get; set; } + public Func? WebSocketConnectionProviderFactory { get; set; } + + public Func? RateLimiterProviderFactory { get; set; } + + public Func? DefaultPayloadPropertiesFactory { get; set; } + + public Func? ReconnectStrategyFactory { get; set; } + + public Func? LatencyTimerFactory { get; set; } + + public Func? VersionFactory { get; set; } + + public Func? CacheFactory { get; set; } + + public Func? CompressionFactory { get; set; } + + public Func? IntentsFactory { get; set; } + + public string? Hostname { get; set; } + + public Func? ConnectionPropertiesFactory { get; set; } + + public Func? LargeThresholdFactory { get; set; } + + public Func? PresenceFactory { get; set; } + + public int? ShardCount { get; set; } + + public bool? CacheDMChannels { get; set; } + + public RestClientConfiguration? RestClientConfiguration { get; set; } + + // Simple properties + + public IWebSocketConnectionProvider? WebSocketConnectionProvider { get; set; } + + public IRateLimiterProvider? RateLimiterProvider { get; set; } + + public WebSocketPayloadProperties? DefaultPayloadProperties { get; set; } + + public IReconnectStrategy? ReconnectStrategy { get; set; } + + public ILatencyTimer? LatencyTimer { get; set; } + + public ApiVersion? Version { get; set; } + + public IGatewayClientCache? Cache { get; set; } + + public IGatewayCompression? Compression { get; set; } + + public GatewayIntents? Intents { get; set; } + + public ConnectionPropertiesProperties? ConnectionProperties { get; set; } + + public int? LargeThreshold { get; set; } + + public PresenceProperties? Presence { get; set; } + + internal ShardedGatewayClientConfiguration CreateConfiguration() + { + return ShardedGatewayClientConfigurationFactory.Create(CreateFactory(WebSocketConnectionProvider, WebSocketConnectionProviderFactory), + CreateFactory(RateLimiterProvider, RateLimiterProviderFactory), + CreateFactory(DefaultPayloadProperties, DefaultPayloadPropertiesFactory), + CreateFactory(ReconnectStrategy, ReconnectStrategyFactory), + CreateFactory(LatencyTimer, LatencyTimerFactory), + CreateFactory(Version, VersionFactory), + CreateFactory(Cache, CacheFactory), + CreateFactory(Compression, CompressionFactory), + CreateFactory(Intents, IntentsFactory), + Hostname, + CreateFactory(ConnectionProperties, ConnectionPropertiesFactory), + CreateFactory(LargeThreshold, LargeThresholdFactory), + CreateFactory(Presence, PresenceFactory), + ShardCount, + CacheDMChannels, + RestClientConfiguration); + + static Func? CreateFactory(T? value, Func? func, [CallerArgumentExpression(nameof(value))] string valueName = "", [CallerArgumentExpression(nameof(func))] string funcName = "") + { + if (value is not null) + { + if (func is not null) + throw new InvalidOperationException($"Cannot specify both '{valueName}' and '{funcName}' at the same time."); + + return _ => value; + } + + return func; + } + } } diff --git a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientServiceCollectionExtensions.cs index bec0fcd5..e2724261 100644 --- a/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Gateway/ShardedGatewayClientServiceCollectionExtensions.cs @@ -7,6 +7,24 @@ namespace NetCord.Hosting.Gateway; public static class ShardedGatewayClientServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureDiscordShardedGateway(this IServiceCollection services, Action configureOptions) + { + return services.ConfigureDiscordShardedGateway((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureDiscordShardedGateway(this IServiceCollection services, Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddDiscordShardedGateway(this IServiceCollection services) { return services.AddDiscordShardedGateway((_, _) => { }); @@ -22,7 +40,7 @@ public static IServiceCollection AddDiscordShardedGateway(this IServiceCollectio services .AddOptions() .BindConfiguration("Discord") - .Configure(configureOptions) + .PostConfigure(configureOptions) .ValidateDataAnnotations(); services.AddSingleton>(services => services.GetRequiredService>()); @@ -36,7 +54,7 @@ public static IServiceCollection AddDiscordShardedGateway(this IServiceCollectio if (token is not IEntityToken entityToken) throw new InvalidOperationException($"Unable to initialize '{nameof(ShardedGatewayClient)}'. The provided token must implement the '{nameof(IEntityToken)}' interface."); - return new ShardedGatewayClient(entityToken, options.Configuration); + return new ShardedGatewayClient(entityToken, options.CreateConfiguration()); }); services.AddSingleton(services => services.GetRequiredService().Rest); diff --git a/Hosting/NetCord.Hosting/NetCord.Hosting.csproj b/Hosting/NetCord.Hosting/NetCord.Hosting.csproj index 9df691d3..508b5ac4 100644 --- a/Hosting/NetCord.Hosting/NetCord.Hosting.csproj +++ b/Hosting/NetCord.Hosting/NetCord.Hosting.csproj @@ -35,6 +35,8 @@ + + diff --git a/Hosting/NetCord.Hosting/Rest/RestClientHostBuilderExtensions.cs b/Hosting/NetCord.Hosting/Rest/RestClientHostBuilderExtensions.cs index fabec41b..cd10563e 100644 --- a/Hosting/NetCord.Hosting/Rest/RestClientHostBuilderExtensions.cs +++ b/Hosting/NetCord.Hosting/Rest/RestClientHostBuilderExtensions.cs @@ -4,6 +4,20 @@ namespace NetCord.Hosting.Rest; public static class RestClientHostBuilderExtensions { + // Configure + + public static IHostBuilder ConfigureDiscordRest(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureDiscordRest((options, _) => configureOptions(options)); + } + + public static IHostBuilder ConfigureDiscordRest(this IHostBuilder builder, Action configureOptions) + { + return builder.ConfigureServices((_, services) => services.ConfigureDiscordRest(configureOptions)); + } + + // Use + public static IHostBuilder UseDiscordRest(this IHostBuilder builder) { return builder.UseDiscordRest((options, _) => { }); diff --git a/Hosting/NetCord.Hosting/Rest/RestClientOptions.cs b/Hosting/NetCord.Hosting/Rest/RestClientOptions.cs index 489f5f09..76fd2ae5 100644 --- a/Hosting/NetCord.Hosting/Rest/RestClientOptions.cs +++ b/Hosting/NetCord.Hosting/Rest/RestClientOptions.cs @@ -1,4 +1,5 @@ using NetCord.Rest; +using NetCord.Rest.RateLimits; namespace NetCord.Hosting.Rest; @@ -8,5 +9,25 @@ public class RestClientOptions : IDiscordOptions public string? PublicKey { get; set; } - public RestClientConfiguration? Configuration { get; set; } + public string? Hostname { get; set; } + + public ApiVersion? Version { get; set; } + + public IRestRequestHandler? RequestHandler { get; set; } + + public RestRequestProperties? DefaultRequestProperties { get; set; } + + public IRateLimitManager? RateLimitManager { get; set; } + + internal RestClientConfiguration CreateConfiguration() + { + return new() + { + Hostname = Hostname, + Version = Version, + RequestHandler = RequestHandler, + DefaultRequestProperties = DefaultRequestProperties, + RateLimitManager = RateLimitManager, + }; + } } diff --git a/Hosting/NetCord.Hosting/Rest/RestClientServiceCollectionExtensions.cs b/Hosting/NetCord.Hosting/Rest/RestClientServiceCollectionExtensions.cs index 6df33473..23e60b26 100644 --- a/Hosting/NetCord.Hosting/Rest/RestClientServiceCollectionExtensions.cs +++ b/Hosting/NetCord.Hosting/Rest/RestClientServiceCollectionExtensions.cs @@ -7,6 +7,24 @@ namespace NetCord.Hosting.Rest; public static class RestClientServiceCollectionExtensions { + // Configure + + public static IServiceCollection ConfigureDiscordRest(this IServiceCollection services, Action configureOptions) + { + return services.ConfigureDiscordRest((options, _) => configureOptions(options)); + } + + public static IServiceCollection ConfigureDiscordRest(this IServiceCollection services, Action configureOptions) + { + services + .AddOptions() + .PostConfigure(configureOptions); + + return services; + } + + // Add + public static IServiceCollection AddDiscordRest(this IServiceCollection services) { return services.AddDiscordRest((_, _) => { }); @@ -22,7 +40,7 @@ public static IServiceCollection AddDiscordRest(this IServiceCollection services services .AddOptions() .BindConfiguration("Discord") - .Configure(configureOptions); + .PostConfigure(configureOptions); services.AddSingleton>(services => services.GetRequiredService>()); @@ -31,7 +49,8 @@ public static IServiceCollection AddDiscordRest(this IServiceCollection services var options = services.GetRequiredService>().Value; var token = options.Token; - return token is null ? new(options.Configuration) : new(ConfigurationHelper.ParseToken(token, services), options.Configuration); + var configuration = options.CreateConfiguration(); + return token is null ? new(configuration) : new(ConfigurationHelper.ParseToken(token, services), configuration); }); return services; diff --git a/NetCord/Gateway/GatewayClient.cs b/NetCord/Gateway/GatewayClient.cs index 63b6f5dc..be12400e 100644 --- a/NetCord/Gateway/GatewayClient.cs +++ b/NetCord/Gateway/GatewayClient.cs @@ -13,7 +13,11 @@ namespace NetCord.Gateway; /// public partial class GatewayClient : WebSocketClient, IEntity { - private readonly GatewayClientConfiguration _configuration; + private readonly ConnectionPropertiesProperties _connectionProperties; + private readonly int? _largeThreshold; + private readonly PresenceProperties? _presence; + private readonly GatewayIntents _intents; + private readonly bool _cacheDMChannels; private readonly object? _DMsLock; private readonly Dictionary? _DMSemaphores; private readonly IGatewayCompression _compression; @@ -787,7 +791,7 @@ public partial class GatewayClient : WebSocketClient, IEntity /// /// The shard of the . /// - public Shard? Shard => _configuration.Shard; + public Shard? Shard { get; } /// /// The application flags of the . @@ -817,18 +821,22 @@ public partial class GatewayClient : WebSocketClient, IEntity { Token = token; - _configuration = configuration; + Shard = configuration.Shard; + _connectionProperties = configuration.ConnectionProperties ?? ConnectionPropertiesProperties.Default; + _largeThreshold = configuration.LargeThreshold; + _presence = configuration.Presence; + _intents = configuration.Intents.GetValueOrDefault(GatewayIntents.AllNonPrivileged); - var compression = _compression = configuration.Compression ?? IGatewayCompression.CreateDefault(); - Uri = new($"wss://{configuration.Hostname ?? Discord.GatewayHostname}/?v={(int)configuration.Version}&encoding=json&compress={compression.Name}", UriKind.Absolute); - Cache = configuration.Cache ?? new GatewayClientCache(); - Rest = rest; - - if (configuration.CacheDMChannels) + if (_cacheDMChannels = configuration.CacheDMChannels.GetValueOrDefault(true)) { _DMsLock = new(); _DMSemaphores = []; } + + var compression = _compression = configuration.Compression ?? IGatewayCompression.CreateDefault(); + Uri = new($"wss://{configuration.Hostname ?? Discord.GatewayHostname}/?v={(int)configuration.Version.GetValueOrDefault(ApiVersion.V10)}&encoding=json&compress={compression.Name}", UriKind.Absolute); + Cache = configuration.Cache ?? new GatewayClientCache(); + Rest = rest; } private protected override void OnConnected() @@ -840,11 +848,11 @@ private ValueTask SendIdentifyAsync(ConnectionState connectionState, PresencePro { var serializedPayload = new GatewayPayloadProperties(GatewayOpcode.Identify, new(Token.RawToken) { - ConnectionProperties = _configuration.ConnectionProperties ?? ConnectionPropertiesProperties.Default, - LargeThreshold = _configuration.LargeThreshold, - Shard = _configuration.Shard, - Presence = presence ?? _configuration.Presence, - Intents = _configuration.Intents, + ConnectionProperties = _connectionProperties, + LargeThreshold = _largeThreshold, + Shard = Shard, + Presence = presence ?? _presence, + Intents = _intents, }).Serialize(Serialization.Default.GatewayPayloadPropertiesGatewayIdentifyProperties); _latencyTimer.Start(); return SendConnectionPayloadAsync(connectionState, serializedPayload, _internalPayloadProperties, cancellationToken); @@ -1272,7 +1280,7 @@ await InvokeEventAsync( MessageCreate, () => data.ToObject(Serialization.Default.JsonMessage), json => Message.CreateFromJson(json, Cache, Rest), - json => _configuration.CacheDMChannels && !json.GuildId.HasValue && !json.Flags.GetValueOrDefault().HasFlag(MessageFlags.Ephemeral), + json => _cacheDMChannels && !json.GuildId.HasValue && !json.Flags.GetValueOrDefault().HasFlag(MessageFlags.Ephemeral), json => { var channelId = json.ChannelId; @@ -1289,7 +1297,7 @@ await InvokeEventAsync( MessageUpdate, () => data.ToObject(Serialization.Default.JsonMessage), json => Message.CreateFromJson(json, Cache, Rest), - json => _configuration.CacheDMChannels && !json.GuildId.HasValue && !json.Flags.GetValueOrDefault().HasFlag(MessageFlags.Ephemeral), + json => _cacheDMChannels && !json.GuildId.HasValue && !json.Flags.GetValueOrDefault().HasFlag(MessageFlags.Ephemeral), json => { var channelId = json.ChannelId; diff --git a/NetCord/Gateway/GatewayClientConfiguration.cs b/NetCord/Gateway/GatewayClientConfiguration.cs index b9535e00..9b1f6eb9 100644 --- a/NetCord/Gateway/GatewayClientConfiguration.cs +++ b/NetCord/Gateway/GatewayClientConfiguration.cs @@ -2,9 +2,12 @@ using NetCord.Gateway.LatencyTimers; using NetCord.Gateway.ReconnectStrategies; using NetCord.Gateway.WebSockets; +using NetCord.Rest; namespace NetCord.Gateway; +// Needs to be in sync with GatewayClientConfigurationFactory + public class GatewayClientConfiguration : IWebSocketClientConfiguration { public IWebSocketConnectionProvider? WebSocketConnectionProvider { get; init; } @@ -12,17 +15,17 @@ public class GatewayClientConfiguration : IWebSocketClientConfiguration public WebSocketPayloadProperties? DefaultPayloadProperties { get; init; } public IReconnectStrategy? ReconnectStrategy { get; init; } public ILatencyTimer? LatencyTimer { get; init; } - public ApiVersion Version { get; init; } = ApiVersion.V10; + public ApiVersion? Version { get; init; } public IGatewayClientCache? Cache { get; init; } public IGatewayCompression? Compression { get; init; } - public GatewayIntents Intents { get; init; } = GatewayIntents.AllNonPrivileged; + public GatewayIntents? Intents { get; init; } public string? Hostname { get; init; } public ConnectionPropertiesProperties? ConnectionProperties { get; init; } public int? LargeThreshold { get; init; } public PresenceProperties? Presence { get; init; } public Shard? Shard { get; init; } - public bool CacheDMChannels { get; init; } = true; - public Rest.RestClientConfiguration? RestClientConfiguration { get; init; } + public bool? CacheDMChannels { get; init; } + public RestClientConfiguration? RestClientConfiguration { get; init; } IRateLimiterProvider? IWebSocketClientConfiguration.RateLimiterProvider => RateLimiterProvider is { } rateLimiter ? rateLimiter : new GatewayRateLimiterProvider(120, 60_000); } diff --git a/NetCord/Gateway/GatewayClientConfigurationFactory.cs b/NetCord/Gateway/GatewayClientConfigurationFactory.cs new file mode 100644 index 00000000..9e14db2a --- /dev/null +++ b/NetCord/Gateway/GatewayClientConfigurationFactory.cs @@ -0,0 +1,48 @@ +using NetCord.Gateway.Compression; +using NetCord.Gateway.LatencyTimers; +using NetCord.Gateway.ReconnectStrategies; +using NetCord.Gateway.WebSockets; +using NetCord.Rest; + +namespace NetCord.Gateway; + +internal static class GatewayClientConfigurationFactory +{ + public static GatewayClientConfiguration Create(IWebSocketConnectionProvider? webSocketConnectionProvider, + IRateLimiterProvider? rateLimiterProvider, + WebSocketPayloadProperties? defaultPayloadProperties, + IReconnectStrategy? reconnectStrategy, + ILatencyTimer? latencyTimer, + ApiVersion? version, + IGatewayClientCache? cache, + IGatewayCompression? compression, + GatewayIntents? intents, + string? hostname, + ConnectionPropertiesProperties? connectionProperties, + int? largeThreshold, + PresenceProperties? presence, + Shard? shard, + bool? cacheDMChannels, + RestClientConfiguration? restClientConfiguration) + { + return new() + { + WebSocketConnectionProvider = webSocketConnectionProvider, + RateLimiterProvider = rateLimiterProvider, + DefaultPayloadProperties = defaultPayloadProperties, + ReconnectStrategy = reconnectStrategy, + LatencyTimer = latencyTimer, + Version = version, + Cache = cache, + Compression = compression, + Intents = intents, + Hostname = hostname, + ConnectionProperties = connectionProperties, + LargeThreshold = largeThreshold, + Presence = presence, + Shard = shard, + CacheDMChannels = cacheDMChannels, + RestClientConfiguration = restClientConfiguration, + }; + } +} diff --git a/NetCord/Gateway/ShardedGatewayClient.cs b/NetCord/Gateway/ShardedGatewayClient.cs index 087c3244..e507959f 100644 --- a/NetCord/Gateway/ShardedGatewayClient.cs +++ b/NetCord/Gateway/ShardedGatewayClient.cs @@ -29,41 +29,40 @@ private static ShardedGatewayClientConfiguration CreateConfiguration(ShardedGate { if (configuration is null) { - return new() - { - WebSocketConnectionProviderFactory = _ => null, - ReconnectStrategyFactory = _ => null, - LatencyTimerFactory = _ => null, - VersionFactory = _ => ApiVersion.V10, - CacheFactory = _ => null, - CompressionFactory = _ => null, - IntentsFactory = _ => GatewayIntents.AllNonPrivileged, - Hostname = null, - ConnectionPropertiesFactory = _ => null, - LargeThresholdFactory = _ => null, - PresenceFactory = _ => null, - ShardCount = null, - RestClientConfiguration = null, - }; - } - - return new() - { - WebSocketConnectionProviderFactory = configuration.WebSocketConnectionProviderFactory ?? (_ => null), - ReconnectStrategyFactory = configuration.ReconnectStrategyFactory ?? (_ => null), - LatencyTimerFactory = configuration.LatencyTimerFactory ?? (_ => null), - VersionFactory = configuration.VersionFactory ?? (_ => ApiVersion.V10), - CacheFactory = configuration.CacheFactory ?? (_ => null), - CompressionFactory = configuration.CompressionFactory ?? (_ => null), - IntentsFactory = configuration.IntentsFactory ?? (_ => GatewayIntents.AllNonPrivileged), - Hostname = configuration.Hostname, - ConnectionPropertiesFactory = configuration.ConnectionPropertiesFactory ?? (_ => null), - LargeThresholdFactory = configuration.LargeThresholdFactory ?? (_ => null), - PresenceFactory = configuration.PresenceFactory ?? (_ => null), - ShardCount = configuration.ShardCount, - CacheDMChannels = configuration.CacheDMChannels, - RestClientConfiguration = configuration.RestClientConfiguration, - }; + return ShardedGatewayClientConfigurationFactory.Create(_ => null, + _ => null, + _ => null, + _ => null, + _ => null, + _ => null, + _ => null, + _ => null, + _ => null, + null, + _ => null, + _ => null, + _ => null, + null, + null, + null); + } + + return ShardedGatewayClientConfigurationFactory.Create(configuration.WebSocketConnectionProviderFactory ?? (_ => null), + configuration.RateLimiterProviderFactory ?? (_ => null), + configuration.DefaultPayloadPropertiesFactory ?? (_ => null), + configuration.ReconnectStrategyFactory ?? (_ => null), + configuration.LatencyTimerFactory ?? (_ => null), + configuration.VersionFactory ?? (_ => ApiVersion.V10), + configuration.CacheFactory ?? (_ => null), + configuration.CompressionFactory ?? (_ => null), + configuration.IntentsFactory ?? (_ => GatewayIntents.AllNonPrivileged), + configuration.Hostname, + configuration.ConnectionPropertiesFactory ?? (_ => null), + configuration.LargeThresholdFactory ?? (_ => null), + configuration.PresenceFactory ?? (_ => null), + configuration.ShardCount, + configuration.CacheDMChannels, + configuration.RestClientConfiguration); } /// @@ -217,24 +216,22 @@ async Task ConnectShardAsync(int shardId) private GatewayClientConfiguration GetGatewayClientConfiguration(Shard shard) { var configuration = _configuration; - return new() - { - WebSocketConnectionProvider = configuration.WebSocketConnectionProviderFactory!(shard), - RateLimiterProvider = configuration.RateLimiterProviderFactory!(shard), - DefaultPayloadProperties = configuration.DefaultPayloadPropertiesFactory!(shard), - ReconnectStrategy = configuration.ReconnectStrategyFactory!(shard), - LatencyTimer = configuration.LatencyTimerFactory!(shard), - Version = configuration.VersionFactory!(shard), - Cache = configuration.CacheFactory!(shard), - Compression = configuration.CompressionFactory!(shard), - Intents = configuration.IntentsFactory!(shard), - Hostname = configuration.Hostname, - ConnectionProperties = configuration.ConnectionPropertiesFactory!(shard), - LargeThreshold = configuration.LargeThresholdFactory!(shard), - Presence = configuration.PresenceFactory!(shard), - Shard = shard, - CacheDMChannels = configuration.CacheDMChannels, - }; + return GatewayClientConfigurationFactory.Create(configuration.WebSocketConnectionProviderFactory!(shard), + configuration.RateLimiterProviderFactory!(shard), + configuration.DefaultPayloadPropertiesFactory!(shard), + configuration.ReconnectStrategyFactory!(shard), + configuration.LatencyTimerFactory!(shard), + configuration.VersionFactory!(shard), + configuration.CacheFactory!(shard), + configuration.CompressionFactory!(shard), + configuration.IntentsFactory!(shard), + configuration.Hostname, + configuration.ConnectionPropertiesFactory!(shard), + configuration.LargeThresholdFactory!(shard), + configuration.PresenceFactory!(shard), + shard, + configuration.CacheDMChannels, + null); } public async Task CloseAsync(System.Net.WebSockets.WebSocketCloseStatus status = System.Net.WebSockets.WebSocketCloseStatus.NormalClosure) diff --git a/NetCord/Gateway/ShardedGatewayClientConfiguration.cs b/NetCord/Gateway/ShardedGatewayClientConfiguration.cs index d6a70c26..bab70afa 100644 --- a/NetCord/Gateway/ShardedGatewayClientConfiguration.cs +++ b/NetCord/Gateway/ShardedGatewayClientConfiguration.cs @@ -12,15 +12,15 @@ public class ShardedGatewayClientConfiguration public Func? DefaultPayloadPropertiesFactory { get; init; } public Func? ReconnectStrategyFactory { get; init; } public Func? LatencyTimerFactory { get; init; } - public Func? VersionFactory { get; init; } + public Func? VersionFactory { get; init; } public Func? CacheFactory { get; init; } public Func? CompressionFactory { get; init; } - public Func? IntentsFactory { get; init; } + public Func? IntentsFactory { get; init; } public string? Hostname { get; init; } public Func? ConnectionPropertiesFactory { get; init; } public Func? LargeThresholdFactory { get; init; } public Func? PresenceFactory { get; init; } public int? ShardCount { get; init; } - public bool CacheDMChannels { get; init; } = true; + public bool? CacheDMChannels { get; init; } public Rest.RestClientConfiguration? RestClientConfiguration { get; init; } } diff --git a/NetCord/Gateway/ShardedGatewayClientConfigurationFactory.cs b/NetCord/Gateway/ShardedGatewayClientConfigurationFactory.cs new file mode 100644 index 00000000..029f6ca3 --- /dev/null +++ b/NetCord/Gateway/ShardedGatewayClientConfigurationFactory.cs @@ -0,0 +1,48 @@ +using NetCord.Gateway.Compression; +using NetCord.Gateway.LatencyTimers; +using NetCord.Gateway.ReconnectStrategies; +using NetCord.Gateway.WebSockets; +using NetCord.Rest; + +namespace NetCord.Gateway; + +internal static class ShardedGatewayClientConfigurationFactory +{ + public static ShardedGatewayClientConfiguration Create(Func? webSocketConnectionProviderFactory, + Func? rateLimiterProviderFactory, + Func? defaultPayloadPropertiesFactory, + Func? reconnectStrategyFactory, + Func? latencyTimerFactory, + Func? versionFactory, + Func? cacheFactory, + Func? compressionFactory, + Func? intentsFactory, + string? hostname, + Func? connectionPropertiesFactory, + Func? largeThresholdFactory, + Func? presenceFactory, + int? shardCount, + bool? cacheDMChannels, + RestClientConfiguration? restClientConfiguration) + { + return new() + { + WebSocketConnectionProviderFactory = webSocketConnectionProviderFactory, + RateLimiterProviderFactory = rateLimiterProviderFactory, + DefaultPayloadPropertiesFactory = defaultPayloadPropertiesFactory, + ReconnectStrategyFactory = reconnectStrategyFactory, + LatencyTimerFactory = latencyTimerFactory, + VersionFactory = versionFactory, + CacheFactory = cacheFactory, + CompressionFactory = compressionFactory, + IntentsFactory = intentsFactory, + Hostname = hostname, + ConnectionPropertiesFactory = connectionPropertiesFactory, + LargeThresholdFactory = largeThresholdFactory, + PresenceFactory = presenceFactory, + ShardCount = shardCount, + CacheDMChannels = cacheDMChannels, + RestClientConfiguration = restClientConfiguration, + }; + } +} diff --git a/NetCord/Gateway/Voice/VoiceClient.cs b/NetCord/Gateway/Voice/VoiceClient.cs index 1320c981..0f6a8b9b 100644 --- a/NetCord/Gateway/Voice/VoiceClient.cs +++ b/NetCord/Gateway/Voice/VoiceClient.cs @@ -43,14 +43,14 @@ public class VoiceClient : WebSocketClient { UserId = userId; SessionId = sessionId; - Uri = new($"wss://{Endpoint = endpoint}?v={(int)configuration.Version}", UriKind.Absolute); + Uri = new($"wss://{Endpoint = endpoint}?v={(int)configuration.Version.GetValueOrDefault(VoiceApiVersion.V4)}", UriKind.Absolute); GuildId = guildId; Token = token; _udpSocket = configuration.UdpSocket ?? new UdpSocket(); Cache = configuration.Cache ?? new VoiceClientCache(); _encryption = configuration.Encryption ?? new Aes256GcmRtpSizeEncryption(); - RedirectInputStreams = configuration.RedirectInputStreams; + RedirectInputStreams = configuration.RedirectInputStreams.GetValueOrDefault(false); } private ValueTask SendIdentifyAsync(ConnectionState connectionState, CancellationToken cancellationToken = default) diff --git a/NetCord/Gateway/Voice/VoiceClientConfiguration.cs b/NetCord/Gateway/Voice/VoiceClientConfiguration.cs index 67868134..2a6ed0bd 100644 --- a/NetCord/Gateway/Voice/VoiceClientConfiguration.cs +++ b/NetCord/Gateway/Voice/VoiceClientConfiguration.cs @@ -14,8 +14,8 @@ public class VoiceClientConfiguration : IWebSocketClientConfiguration public IUdpSocket? UdpSocket { get; init; } public IReconnectStrategy? ReconnectStrategy { get; init; } public ILatencyTimer? LatencyTimer { get; init; } - public VoiceApiVersion Version { get; init; } = VoiceApiVersion.V4; + public VoiceApiVersion? Version { get; init; } public IVoiceClientCache? Cache { get; init; } public IVoiceEncryption? Encryption { get; init; } - public bool RedirectInputStreams { get; init; } + public bool? RedirectInputStreams { get; init; } } diff --git a/NetCord/Rest/RestClient.cs b/NetCord/Rest/RestClient.cs index 5e25470b..d07c09dc 100644 --- a/NetCord/Rest/RestClient.cs +++ b/NetCord/Rest/RestClient.cs @@ -23,7 +23,7 @@ public RestClient(RestClientConfiguration? configuration = null) { configuration ??= new(); - _baseUrl = $"https://{configuration.Hostname ?? Discord.RestHostname}/api/v{(int)configuration.Version}"; + _baseUrl = $"https://{configuration.Hostname ?? Discord.RestHostname}/api/v{(int)configuration.Version.GetValueOrDefault(ApiVersion.V10)}"; var requestHandler = _requestHandler = configuration.RequestHandler ?? new RestRequestHandler(); diff --git a/NetCord/Rest/RestClientConfiguration.cs b/NetCord/Rest/RestClientConfiguration.cs index 736d84f4..d74bd9e3 100644 --- a/NetCord/Rest/RestClientConfiguration.cs +++ b/NetCord/Rest/RestClientConfiguration.cs @@ -5,7 +5,7 @@ namespace NetCord.Rest; public class RestClientConfiguration { public string? Hostname { get; init; } - public ApiVersion Version { get; init; } = ApiVersion.V10; + public ApiVersion? Version { get; init; } public IRestRequestHandler? RequestHandler { get; init; } public RestRequestProperties? DefaultRequestProperties { get; init; } public IRateLimitManager? RateLimitManager { get; init; } diff --git a/Tests/NetCord.Test.Hosting/Program.cs b/Tests/NetCord.Test.Hosting/Program.cs index f5e546de..e6086906 100644 --- a/Tests/NetCord.Test.Hosting/Program.cs +++ b/Tests/NetCord.Test.Hosting/Program.cs @@ -35,10 +35,12 @@ var builder = Host.CreateApplicationBuilder(args); builder.Services - .AddDiscordGateway(o => o.Configuration = new() - { - Intents = GatewayIntents.All, - }) + .ConfigureDiscordGateway(o => o.Presence = new(UserStatusType.DoNotDisturb)) + .ConfigureCommands(o => o.Prefix = "!") + .ConfigureCommands(o => o.Prefix = ">") + .ConfigureApplicationCommands(o => o.DefaultParameterDescriptionFormat = "AA") + .ConfigureApplicationCommands(o => o.DefaultParameterDescriptionFormat = "XD") + .AddDiscordGateway(o => o.Intents = GatewayIntents.All) .AddApplicationCommands(options => { options.ResultHandler = new CustomSlashCommandResultHandler(); diff --git a/Tests/NetCord.Test.Sharded.Hosting/Program.cs b/Tests/NetCord.Test.Sharded.Hosting/Program.cs index 3b63f162..3ebe2ada 100644 --- a/Tests/NetCord.Test.Sharded.Hosting/Program.cs +++ b/Tests/NetCord.Test.Sharded.Hosting/Program.cs @@ -12,19 +12,15 @@ var builder = Host.CreateApplicationBuilder(args); builder.Services - .AddDiscordShardedGateway(o => o.Configuration = new() - { - ShardCount = 2, - IntentsFactory = _ => GatewayIntents.All, - }) + .ConfigureDiscordShardedGateway(o => o.Presence = new(UserStatusType.Idle)) + .AddDiscordShardedGateway() .AddApplicationCommands() .AddCommands() .AddShardedGatewayEventHandler(nameof(GatewayClient.MessageCreate), (Message message, GatewayClient client, ILogger logger) => logger.LogInformation(new EventId(client.Shard.GetValueOrDefault().Id), "Content: {}", message.Content)); var host = builder.Build(); -host - .AddSlashCommand("ping", "Ping!", (SlashCommandContext context) => "Pong!") +host.AddSlashCommand("ping", "Ping!", (SlashCommandContext context) => "Pong!") .AddCommand(["ping"], () => "Pong!") .UseGatewayEventHandlers();