Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor client/bot registration to support HostApplicationBuilder #122

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
52 changes: 0 additions & 52 deletions src/Disqord.Bot/DiscordBotServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Threading;
using Disqord.Bot.Commands;
using Disqord.Bot.Commands.Application;
using Disqord.Bot.Commands.Application.Default;
Expand All @@ -13,57 +12,6 @@ namespace Disqord.Bot;

public static class DiscordBotServiceCollectionExtensions
{
public static IServiceCollection AddDiscordBot(this IServiceCollection services, Action<DiscordBotConfiguration>? configure = null)
{
services.AddDiscordBot<DiscordBot>();

var options = services.AddOptions<DiscordBotConfiguration>();
if (configure != null)
options.Configure(configure);

return services;
}

public static IServiceCollection AddDiscordBot<TDiscordBot>(this IServiceCollection services)
where TDiscordBot : DiscordBot
{
services.AddDiscordClient();

if (services.TryAddSingleton<TDiscordBot>())
{
var callCount = 0;

TDiscordBot GetBotService(IServiceProvider services)
{
if (Interlocked.Increment(ref callCount) > 1)
throw new InvalidOperationException($"Disqord detected a circular dependency for the bot client of type '{typeof(TDiscordBot)}'. "
+ "This means that most likely your prefix provider or another service depends on the bot client and vice versa.");

var service = services.GetRequiredService<TDiscordBot>();
Interlocked.Decrement(ref callCount);
return service;
}

if (typeof(TDiscordBot) != typeof(DiscordBot))
services.TryAddSingleton<DiscordBot>(GetBotService);

services.TryAddSingleton<DiscordBotBase>(GetBotService);
services.Replace(ServiceDescriptor.Singleton<DiscordClientBase>(GetBotService));
}

services.AddDiscordBotDependencies();
return services;
}

internal static void AddDiscordBotDependencies(this IServiceCollection services)
{
services.AddPrefixProvider();
services.AddCommands();
services.AddCommandContextAccessor();
services.AddApplicationCommandLocalizer();
services.AddApplicationCommandCacheProvider();
}

public static IServiceCollection AddPrefixProvider<TPrefixProvider>(this IServiceCollection services)
where TPrefixProvider : class, IPrefixProvider
{
Expand Down
70 changes: 64 additions & 6 deletions src/Disqord.Bot/Hosting/DiscordBotHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using Disqord.Bot.Commands.Text;
using Disqord.DependencyInjection.Extensions;
using Disqord.Hosting;
Expand Down Expand Up @@ -33,16 +33,34 @@ public static IHostBuilder ConfigureDiscordBot<TDiscordBot, TDiscordBotConfigura
var discordContext = new DiscordBotHostingContext();
configure?.Invoke(context, discordContext);

services.AddDiscordBot<TDiscordBot>();
services.ConfigureDiscordBot<TDiscordBotConfiguration>(context, discordContext);
services.ConfigureDiscordClient(context, discordContext);
services.AddDiscordBot<TDiscordBot, TDiscordBotConfiguration>(discordContext);
});

return builder;
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static void ConfigureDiscordBot<TBotConfiguration>(this IServiceCollection services, HostBuilderContext context, DiscordBotHostingContext discordContext)
public static IServiceCollection AddDiscordBot(this IServiceCollection services, DiscordBotHostingContext context)
{
return services.AddDiscordBot<DiscordBot>(context);
}

public static IServiceCollection AddDiscordBot<TDiscordBot>(this IServiceCollection services, DiscordBotHostingContext context)
where TDiscordBot : DiscordBot
{
return services.AddDiscordBot<TDiscordBot, DiscordBotConfiguration>(context);
}

public static IServiceCollection AddDiscordBot<TDiscordBot, TDiscordBotConfiguration>(this IServiceCollection services, DiscordBotHostingContext context)
where TDiscordBot : DiscordBot
where TDiscordBotConfiguration : DiscordBotBaseConfiguration, new()
{
services.AddDiscordBot<TDiscordBot>();
services.ConfigureDiscordBot<TDiscordBotConfiguration>(context);
services.ConfigureDiscordClient(context);
return services;
}

internal static void ConfigureDiscordBot<TBotConfiguration>(this IServiceCollection services, DiscordBotHostingContext discordContext)
where TBotConfiguration : DiscordBotBaseConfiguration, new()
{
if (discordContext.OwnerIds != null || discordContext.ApplicationId != null)
Expand Down Expand Up @@ -75,4 +93,44 @@ public static void ConfigureDiscordBot<TBotConfiguration>(this IServiceCollectio

services.TryAddSingleton<DiscordBotMasterService>();
}

internal static IServiceCollection AddDiscordBot<TDiscordBot>(this IServiceCollection services)
where TDiscordBot : DiscordBot
{
services.AddDiscordClient();

if (services.TryAddSingleton<TDiscordBot>())
{
var callCount = 0;

TDiscordBot GetBotService(IServiceProvider services)
{
if (Interlocked.Increment(ref callCount) > 1)
throw new InvalidOperationException($"Disqord detected a circular dependency for the bot client of type '{typeof(TDiscordBot)}'. "
+ "This means that most likely your prefix provider or another service depends on the bot client and vice versa.");

var service = services.GetRequiredService<TDiscordBot>();
Interlocked.Decrement(ref callCount);
return service;
}

if (typeof(TDiscordBot) != typeof(DiscordBot))
services.TryAddSingleton<DiscordBot>(GetBotService);

services.TryAddSingleton<DiscordBotBase>(GetBotService);
services.Replace(ServiceDescriptor.Singleton<DiscordClientBase>(GetBotService));
}

services.AddDiscordBotDependencies();
return services;
}

internal static void AddDiscordBotDependencies(this IServiceCollection services)
{
services.AddPrefixProvider();
services.AddCommands();
services.AddCommandContextAccessor();
services.AddApplicationCommandLocalizer();
services.AddApplicationCommandCacheProvider();
}
}
21 changes: 0 additions & 21 deletions src/Disqord/DiscordClientServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
using System.ComponentModel;
using Disqord.Api;
using Disqord.DependencyInjection.Extensions;
using Disqord.Extensions.Interactivity;
using Disqord.Gateway;
using Disqord.Gateway.Api;
using Disqord.Rest;
using Disqord.Webhook;
using Microsoft.Extensions.DependencyInjection;

namespace Disqord;

[EditorBrowsable(EditorBrowsableState.Advanced)]
public static class DiscordClientServiceCollectionExtensions
{
public static IServiceCollection AddDiscordClient(this IServiceCollection services)
{
if (services.TryAddSingleton<DiscordClient>())
{
services.TryAddSingleton<DiscordClientBase>(services => services.GetRequiredService<DiscordClient>());
services.AddShardCoordinator<LocalDiscordShardCoordinator>();
}

services.AddInteractivityExtension();
services.AddGatewayClient();
services.AddRestClient();
services.AddWebhookClientFactory();

return services;
}

public static IServiceCollection AddShardCoordinator<TShardCoordinator>(this IServiceCollection services)
where TShardCoordinator : class, IShardCoordinator
{
Expand Down
37 changes: 31 additions & 6 deletions src/Disqord/Hosting/DiscordClientHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using System.ComponentModel;
using System.Linq;
using Disqord.Api;
using Disqord.DependencyInjection.Extensions;
using Disqord.Extensions.Interactivity;
using Disqord.Gateway;
using Disqord.Gateway.Api.Default;
using Disqord.Gateway.Api.Models;
using Disqord.Gateway.Default;
using Disqord.Http.Default;
using Disqord.Rest;
using Disqord.Webhook;
using Disqord.WebSocket.Default;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand All @@ -21,16 +25,37 @@ public static IHostBuilder ConfigureDiscordClient(this IHostBuilder builder, Act
var discordContext = new DiscordClientHostingContext();
configure?.Invoke(context, discordContext);

services.AddDiscordClient();
services.AddHostedService<DiscordClientSetupService>();
services.ConfigureDiscordClient(context, discordContext);
services.AddDiscordClient(discordContext);
});

return builder;
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static void ConfigureDiscordClient(this IServiceCollection services, HostBuilderContext context, DiscordClientHostingContext discordContext)
public static IServiceCollection AddDiscordClient(this IServiceCollection services, DiscordClientHostingContext context)
{
services.AddDiscordClient();
services.AddHostedService<DiscordClientSetupService>();
services.ConfigureDiscordClient(context);
return services;
}

internal static IServiceCollection AddDiscordClient(this IServiceCollection services)
{
if (services.TryAddSingleton<DiscordClient>())
{
services.TryAddSingleton<DiscordClientBase>(services => services.GetRequiredService<DiscordClient>());
services.AddShardCoordinator<LocalDiscordShardCoordinator>();
}

services.AddInteractivityExtension();
services.AddGatewayClient();
services.AddRestClient();
services.AddWebhookClientFactory();

return services;
}

internal static void ConfigureDiscordClient(this IServiceCollection services, DiscordClientHostingContext discordContext)
{
services.Replace(ServiceDescriptor.Singleton<Token>(Token.Bot(discordContext.Token!)));

Expand Down
Loading