Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 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
| GatewayIntents.DirectMessages
| GatewayIntents.MessageContent
| GatewayIntents.DirectMessageReactions
| GatewayIntents.GuildMessageReactions,
};
options.Intents = GatewayIntents.GuildMessages
| GatewayIntents.DirectMessages
| GatewayIntents.MessageContent
| GatewayIntents.DirectMessageReactions
| 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;
});
2 changes: 1 addition & 1 deletion Documentation/guides/events/first-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The preferred way to receive events with the generic host is by implementing @NetCord.Hosting.Gateway.IGatewayEventHandler or @NetCord.Hosting.Gateway.IGatewayEventHandler`1.

First, use @NetCord.Hosting.Gateway.GatewayEventHandlerServiceCollectionExtensions.AddGatewayEventHandlers(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Reflection.Assembly) to add all event handlers in an assembly. You also need to call @NetCord.Hosting.Gateway.GatewayEventHandlerHostExtensions.UseGatewayEventHandlers(Microsoft.Extensions.Hosting.IHost) to bind the handlers to the client.
[!code-cs[Program.cs](FirstEventsHosting/Program.cs?highlight=20,23)]
[!code-cs[Program.cs](FirstEventsHosting/Program.cs?highlight=17,20)]

> [!NOTE]
> All gateway event handlers require @NetCord.Hosting.Gateway.GatewayEventAttribute that specifies the event to bind to. The event argument must match the type of the handler, otherwise an exception will be thrown.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/guides/events/intents.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Intents in NetCord are handled by @NetCord.Gateway.GatewayIntents.
You specify them like this:

## [Generic Host](#tab/generic-host)
[!code-cs[Program.cs](IntentsHosting/Program.cs?highlight=6#L8-L15)]
[!code-cs[Program.cs](IntentsHosting/Program.cs?highlight=4#L8-L12)]

## [Bare Bones](#tab/bare-bones)
[!code-cs[Program.cs](Intents/Program.cs?highlight=3#L4-L7)]
Expand Down
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 @@ -7,7 +7,7 @@ To localize application commands, you need to use @NetCord.Services.ApplicationC
The samples below show how to specify the @NetCord.Services.ApplicationCommands.JsonLocalizationsProvider.

## [Generic Host](#tab/generic-host)
[!code-cs[Program.cs](LocalizationsHosting/Program.cs?highlight=6#L11-L18)]
[!code-cs[Program.cs](LocalizationsHosting/Program.cs?highlight=4#L11-L15)]

## [Bare Bones](#tab/bare-bones)
[!code-cs[Program.cs](Localizations/Program.cs?highlight=3#L12-L15)]
Expand Down
8 changes: 6 additions & 2 deletions Hosting/NetCord.Hosting.AspNetCore/RoutePatternHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ public static RoutePattern ParseLiteral(string pattern)
{
var trimmedPattern = TrimPrefix(pattern);

var routePattern = RoutePatternFactory.Pattern(pattern, trimmedPattern.Length == 0 ? [] : trimmedPattern.Split('/').Select(p => RoutePatternFactory.Segment(RoutePatternFactory.LiteralPart(p))));
return routePattern;
var segments = trimmedPattern.Length is 0
? []
: trimmedPattern.Split('/')
.Select(p => RoutePatternFactory.Segment(RoutePatternFactory.LiteralPart(p)));

return RoutePatternFactory.Pattern(pattern, segments);
}

private static string TrimPrefix(string routePattern)
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; }
}
Loading