Skip to content

Commit

Permalink
Improve configuration in hosting
Browse files Browse the repository at this point in the history
  • Loading branch information
KubaZ2 committed Sep 14, 2024
1 parent 59d17b2 commit ca6b81f
Show file tree
Hide file tree
Showing 39 changed files with 1,027 additions and 146 deletions.
7 changes: 2 additions & 5 deletions Documentation/guides/events/FirstEventsHosting/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 1 addition & 4 deletions Documentation/guides/events/IntentsHosting/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

builder.Services
.AddSingleton<IDataProvider, DataProvider>()
.AddDiscordGateway(o => o.Configuration = new() { Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent })
.AddDiscordGateway(o => o.Intents = GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.MessageContent)
.AddCommands<CommandContext>()
.AddApplicationCommands<SlashCommandInteraction, SlashCommandContext>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@
builder.Services
.AddApplicationCommands<SlashCommandInteraction, SlashCommandContext>(options =>
{
options.Configuration = ApplicationCommandServiceConfiguration<SlashCommandContext>.Default with
{
LocalizationsProvider = new JsonLocalizationsProvider(),
};
options.LocalizationsProvider = new JsonLocalizationsProvider();
})
.AddDiscordGateway();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public ApplicationCommandInteractionHandler(IServiceProvider services,

var optionsValue = options.Value;

if (optionsValue.UseScopes)
if (optionsValue.UseScopes.GetValueOrDefault(true))
{
_scopeFactory = services.GetService<IServiceScopeFactory>() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes.");
_handleAsync = &HandleInteractionWithScopeAsync;
Expand All @@ -43,7 +43,7 @@ public ApplicationCommandInteractionHandler(IServiceProvider services,
_handleAsync = &HandleInteractionAsync;

_createContext = optionsValue.CreateContext ?? ContextHelper.CreateContextDelegate<TInteraction, GatewayClient?, TContext>();
_resultHandler = optionsValue.ResultHandler;
_resultHandler = optionsValue.ResultHandler ?? new ApplicationCommandResultHandler<TContext>();
_client = client;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,56 @@ namespace NetCord.Hosting.Services.ApplicationCommands;

public static class ApplicationCommandServiceHostBuilderExtensions
{
// Configure

public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions> configureOptions)
{
return builder.ConfigureApplicationCommands((options, _) => configureOptions(options));
}

public static IHostBuilder ConfigureApplicationCommands(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions, IServiceProvider> configureOptions)
{
return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions));
}

public static IHostBuilder ConfigureApplicationCommands<TInteraction, TContext>(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions<TInteraction, TContext>> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
{
return builder.ConfigureApplicationCommands<TInteraction, TContext>((options, _) => configureOptions(options));
}

public static IHostBuilder ConfigureApplicationCommands<TInteraction, TContext>(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions<TInteraction, TContext>, IServiceProvider> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
{
return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions));
}

public static IHostBuilder ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
where TAutocompleteContext : IAutocompleteInteractionContext
{
return builder.ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>((options, _) => configureOptions(options));
}

public static IHostBuilder ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>(this IHostBuilder builder,
Action<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>, IServiceProvider> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
where TAutocompleteContext : IAutocompleteInteractionContext
{
return builder.ConfigureServices((context, services) => services.ConfigureApplicationCommands(configureOptions));
}

// Use

public static IHostBuilder UseApplicationCommands<TInteraction, TContext>(this IHostBuilder builder)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ApplicationIntegrationType>? DefaultIntegrationTypes { get; set; }

public IEnumerable<InteractionContextType>? DefaultContexts { get; set; }

/// <summary>
/// {0} - parameter name
/// </summary>
[StringSyntax(StringSyntaxAttribute.CompositeFormat)]
public string? DefaultParameterDescriptionFormat { get; set; }

public ILocalizationsProvider? LocalizationsProvider { get; set; }

public bool? UseScopes { get; set; }
}

public class ApplicationCommandServiceOptions<TInteraction, TContext> where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext
{
public ApplicationCommandServiceConfiguration<TContext> Configuration { get; set; } = ApplicationCommandServiceConfiguration<TContext>.Default;
public Dictionary<Type, SlashCommandTypeReader<TContext>> TypeReaders { get; set; } = ApplicationCommandServiceConfiguration<TContext>.Default.TypeReaders.ToDictionary();

public SlashCommandTypeReader<TContext>? EnumTypeReader { get; set; }

public bool? DefaultDMPermission { get; set; }

public IEnumerable<ApplicationIntegrationType>? DefaultIntegrationTypes { get; set; }

public IEnumerable<InteractionContextType>? DefaultContexts { get; set; }

public bool UseScopes { get; set; } = true;
public ISlashCommandParameterNameProcessor<TContext>? ParameterNameProcessor { get; set; }

/// <summary>
/// {0} - parameter name
/// </summary>
[StringSyntax(StringSyntaxAttribute.CompositeFormat)]
public string? DefaultParameterDescriptionFormat { get; set; }

public IResultResolverProvider<TContext>? ResultResolverProvider { get; set; }

public ILocalizationsProvider? LocalizationsProvider { get; set; }

public bool? UseScopes { get; set; }

public Func<TInteraction, GatewayClient?, IServiceProvider, TContext>? CreateContext { get; set; }

public IApplicationCommandResultHandler<TContext> ResultHandler { get; set; } = new ApplicationCommandResultHandler<TContext>();
public IApplicationCommandResultHandler<TContext>? ResultHandler { get; set; }

internal void Apply(IOptions<ApplicationCommandServiceOptions> 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<TContext> CreateConfiguration()
{
var configuration = ApplicationCommandServiceConfiguration<TContext>.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<TInteraction, TContext, TAutocompleteContext> : ApplicationCommandServiceOptions<TInteraction, TContext> where TInteraction : ApplicationCommandInteraction where TContext : IApplicationCommandContext where TAutocompleteContext : IAutocompleteInteractionContext
{
public Func<AutocompleteInteraction, GatewayClient?, IServiceProvider, TAutocompleteContext>? CreateAutocompleteContext { get; set; }

public IAutocompleteInteractionResultHandler<TAutocompleteContext> AutocompleteResultHandler { get; set; } = new AutocompleteInteractionResultHandler<TAutocompleteContext>();
public IAutocompleteInteractionResultHandler<TAutocompleteContext>? AutocompleteResultHandler { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,68 @@ namespace NetCord.Hosting.Services.ApplicationCommands;

public static class ApplicationCommandServiceServiceCollectionExtensions
{
// Configure

public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services,
Action<ApplicationCommandServiceOptions> configureOptions)
{
return services.ConfigureApplicationCommands((options, _) => configureOptions(options));
}

public static IServiceCollection ConfigureApplicationCommands(this IServiceCollection services,
Action<ApplicationCommandServiceOptions, IServiceProvider> configureOptions)
{
services
.AddOptions<ApplicationCommandServiceOptions>()
.PostConfigure(configureOptions);

return services;
}

public static IServiceCollection ConfigureApplicationCommands<TInteraction, TContext>(this IServiceCollection services,
Action<ApplicationCommandServiceOptions<TInteraction, TContext>> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
{
return services.ConfigureApplicationCommands<TInteraction, TContext>((options, _) => configureOptions(options));
}

public static IServiceCollection ConfigureApplicationCommands<TInteraction, TContext>(this IServiceCollection services,
Action<ApplicationCommandServiceOptions<TInteraction, TContext>, IServiceProvider> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
{
services
.AddOptions<ApplicationCommandServiceOptions<TInteraction, TContext>>()
.PostConfigure(configureOptions);

return services;
}

public static IServiceCollection ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>(this IServiceCollection services,
Action<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
where TAutocompleteContext : IAutocompleteInteractionContext
{
return services.ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>((options, _) => configureOptions(options));
}

public static IServiceCollection ConfigureApplicationCommands<TInteraction, TContext, TAutocompleteContext>(this IServiceCollection services,
Action<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>, IServiceProvider> configureOptions)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
where TAutocompleteContext : IAutocompleteInteractionContext
{
services
.AddOptions<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>>()
.PostConfigure(configureOptions);

return services;
}

// Add

public static IServiceCollection AddApplicationCommands<TInteraction, TContext>(this IServiceCollection services)
where TInteraction : ApplicationCommandInteraction
where TContext : IApplicationCommandContext
Expand All @@ -31,12 +93,15 @@ public static IServiceCollection AddApplicationCommands<TInteraction, TContext>(
{
services
.AddOptions<ApplicationCommandServiceOptions<TInteraction, TContext>>()
.Configure(configureOptions);
.BindConfiguration("Discord")
.BindConfiguration("Discord:ApplicationCommands")
.Configure<IOptions<ApplicationCommandServiceOptions>>((options, baseOptions) => options.Apply(baseOptions))
.PostConfigure(configureOptions);

services.AddSingleton(services =>
{
var options = services.GetRequiredService<IOptions<ApplicationCommandServiceOptions<TInteraction, TContext>>>().Value;
return new ApplicationCommandService<TContext>(options.Configuration);
return new ApplicationCommandService<TContext>(options.CreateConfiguration());
});
services.AddSingleton<IApplicationCommandService>(services => services.GetRequiredService<ApplicationCommandService<TContext>>());
services.AddSingleton<IService>(services => services.GetRequiredService<ApplicationCommandService<TContext>>());
Expand Down Expand Up @@ -75,14 +140,17 @@ public static IServiceCollection AddApplicationCommands<TInteraction, TContext,
{
services
.AddOptions<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>>()
.Configure(configureOptions);
.BindConfiguration("Discord")
.BindConfiguration("Discord:ApplicationCommands")
.Configure<IOptions<ApplicationCommandServiceOptions>>((options, baseOptions) => options.Apply(baseOptions))
.PostConfigure(configureOptions);

services.AddSingleton<IOptions<ApplicationCommandServiceOptions<TInteraction, TContext>>>(services => services.GetRequiredService<IOptions<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>>>());

services.AddSingleton(services =>
{
var options = services.GetRequiredService<IOptions<ApplicationCommandServiceOptions<TInteraction, TContext, TAutocompleteContext>>>().Value;
return new ApplicationCommandService<TContext, TAutocompleteContext>(options.Configuration);
return new ApplicationCommandService<TContext, TAutocompleteContext>(options.CreateConfiguration());
});
services.AddSingleton<ApplicationCommandService<TContext>>(services => services.GetRequiredService<ApplicationCommandService<TContext, TAutocompleteContext>>());
services.AddSingleton<IApplicationCommandService>(services => services.GetRequiredService<ApplicationCommandService<TContext, TAutocompleteContext>>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public AutocompleteInteractionHandler(IServiceProvider services,

var optionsValue = options.Value;

if (optionsValue.UseScopes)
if (optionsValue.UseScopes.GetValueOrDefault(true))
{
_scopeFactory = services.GetService<IServiceScopeFactory>() ?? throw new InvalidOperationException($"'{nameof(IServiceScopeFactory)}' is not registered in the '{nameof(IServiceProvider)}', but it is required for using scopes.");
_handleAsync = &HandleInteractionWithScopeAsync;
Expand All @@ -43,7 +43,7 @@ public AutocompleteInteractionHandler(IServiceProvider services,
_handleAsync = &HandleInteractionAsync;

_createContext = optionsValue.CreateAutocompleteContext ?? ContextHelper.CreateContextDelegate<AutocompleteInteraction, GatewayClient?, TAutocompleteContext>();
_resultHandler = optionsValue.AutocompleteResultHandler;
_resultHandler = optionsValue.AutocompleteResultHandler ?? new AutocompleteInteractionResultHandler<TAutocompleteContext>();
_client = client;
}

Expand Down
Loading

0 comments on commit ca6b81f

Please sign in to comment.