From 4f8ad48820fda3f91316ff3c7dac93ae92cae4d5 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 20 Mar 2022 11:57:42 +0000 Subject: [PATCH] Implement shared "info" command Displays ping, uptime, prefix, and version information --- BrackeysBot.API/IBot.cs | 2 +- BrackeysBot.API/Plugins/IPlugin.cs | 9 +++ BrackeysBot.API/Plugins/MonoPlugin.cs | 29 +++++---- BrackeysBot/BrackeysBotApp.cs | 9 +-- BrackeysBot/Commands/InfoCommand.cs | 73 ++++++++++++++++++++++ BrackeysBot/Plugins/SimplePluginManager.cs | 10 ++- 6 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 BrackeysBot/Commands/InfoCommand.cs diff --git a/BrackeysBot.API/IBot.cs b/BrackeysBot.API/IBot.cs index 71668ae..ef21ec3 100644 --- a/BrackeysBot.API/IBot.cs +++ b/BrackeysBot.API/IBot.cs @@ -24,5 +24,5 @@ public interface IBot /// Gets the bot version. /// /// The bot version. - string Version { get; } + static string Version { get; } = string.Empty; } diff --git a/BrackeysBot.API/Plugins/IPlugin.cs b/BrackeysBot.API/Plugins/IPlugin.cs index 85eeee3..4733541 100644 --- a/BrackeysBot.API/Plugins/IPlugin.cs +++ b/BrackeysBot.API/Plugins/IPlugin.cs @@ -16,6 +16,15 @@ public interface IPlugin : IDisposable, IConfigurationHolder /// The data directory. DirectoryInfo DataDirectory { get; } + /// + /// Gets the date and time at which this plugin was last enabled. + /// + /// + /// A representing the date and time at which this plugin was enabled, or + /// if this plugin is not currently enabled. + /// + DateTimeOffset? EnableTime { get; } + /// /// Gets the logger for this plugin. /// diff --git a/BrackeysBot.API/Plugins/MonoPlugin.cs b/BrackeysBot.API/Plugins/MonoPlugin.cs index c93622a..633e1ae 100644 --- a/BrackeysBot.API/Plugins/MonoPlugin.cs +++ b/BrackeysBot.API/Plugins/MonoPlugin.cs @@ -14,11 +14,13 @@ namespace BrackeysBot.API.Plugins; /// public abstract class MonoPlugin : IPlugin { - /// - ~MonoPlugin() - { - Dispose(); - } + internal AssemblyLoadContext LoadContext { get; set; } = null!; + + /// + /// Gets the underlying instance. + /// + /// The underlying . + protected internal DiscordClient? DiscordClient { get; internal set; } /// public IConfiguration Configuration { get; internal set; } = null!; @@ -26,6 +28,9 @@ public abstract class MonoPlugin : IPlugin /// public DirectoryInfo DataDirectory { get; internal set; } = null!; + /// + public DateTimeOffset? EnableTime { get; internal set; } = null!; + /// public ILogger Logger { get; internal set; } = null!; @@ -38,19 +43,17 @@ public abstract class MonoPlugin : IPlugin /// public IServiceProvider ServiceProvider { get; internal set; } = null!; - internal AssemblyLoadContext LoadContext { get; set; } = null!; - - /// - /// Gets the underlying instance. - /// - /// The underlying . - protected internal DiscordClient? DiscordClient { get; internal set; } - /// public virtual void Dispose() { } + /// + ~MonoPlugin() + { + Dispose(); + } + /// /// Allows configuration of the plugin's . /// diff --git a/BrackeysBot/BrackeysBotApp.cs b/BrackeysBot/BrackeysBotApp.cs index b74c6b7..fdd0638 100644 --- a/BrackeysBot/BrackeysBotApp.cs +++ b/BrackeysBot/BrackeysBotApp.cs @@ -19,10 +19,7 @@ internal sealed class BrackeysBotApp : BackgroundService, IBot { private readonly List _libraries = new(); - /// - /// Initializes a new instance of the class. - /// - public BrackeysBotApp() + static BrackeysBotApp() { var apiAssembly = Assembly.GetAssembly(typeof(IBot))!; var assembly = Assembly.GetAssembly(typeof(BrackeysBotApp))!; @@ -35,7 +32,7 @@ public BrackeysBotApp() /// Gets the version of the API in use. /// /// The API version. - public string ApiVersion { get; } + public static string ApiVersion { get; } /// /// Gets the libraries directory for this bot. @@ -50,7 +47,7 @@ public BrackeysBotApp() public IPluginManager PluginManager { get; } = new SimplePluginManager(); /// - public string Version { get; } + public static string Version { get; } /// /// Disables all currently-loaded and currently-enabled plugins. diff --git a/BrackeysBot/Commands/InfoCommand.cs b/BrackeysBot/Commands/InfoCommand.cs new file mode 100644 index 0000000..dc45c03 --- /dev/null +++ b/BrackeysBot/Commands/InfoCommand.cs @@ -0,0 +1,73 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using BrackeysBot.API.Attributes; +using BrackeysBot.API.Extensions; +using BrackeysBot.API.Plugins; +using DisCatSharp; +using DisCatSharp.CommandsNext; +using DisCatSharp.CommandsNext.Attributes; +using DisCatSharp.Entities; + +namespace BrackeysBot.Commands; + +/// +/// Represents a class which implements the info command. The info command requires the mention prefix to +/// discern which bot details are being requested. +/// +internal sealed class InfoCommand : BaseCommandModule +{ + private readonly IPlugin _plugin; + + /// + /// Initializes a new instance of the class. + /// + /// The owning plugin. + public InfoCommand(IPlugin plugin) + { + _plugin = plugin; + } + + [Command("info")] + [Description("Displays information about the bot.")] + [RequireGuild] + [RequireMentionPrefix] + public async Task InfoCommandAsync(CommandContext context) + { + await context.AcknowledgeAsync(); + + DiscordColor color = 0; + DiscordGuild guild = context.Guild; + DiscordUser currentUser = context.Client.CurrentUser; + + if (guild.Members.TryGetValue(currentUser.Id, out DiscordMember? member)) + color = member.Color; + + if (color.Value == 0) + color = 0x3F51B5; + + var embed = new DiscordEmbedBuilder(); + embed.WithFooter(guild.Name, guild.IconUrl); + embed.WithThumbnail(currentUser.GetAvatarUrl(ImageFormat.Png)); + embed.WithColor(color); + + string prefix = _plugin.Configuration.Get("discord.prefix") ?? "[]"; + + embed.AddField(Formatter.Underline("Ping"), context.Client.Ping, true); + embed.AddField(Formatter.Underline("Prefix"), prefix, true); + embed.AddFieldIf(_plugin.EnableTime.HasValue, Formatter.Underline("Enabled"), + () => Formatter.Timestamp(_plugin.EnableTime!.Value), true); + + var builder = new StringBuilder(); + builder.AppendLine($"BrackeysBot: {BrackeysBotApp.Version}"); + builder.AppendLine($"BrackeysBot.API: {BrackeysBotApp.ApiVersion}"); + builder.AppendLine($"{_plugin.PluginInfo.Name}: {_plugin.PluginInfo.Version}"); + builder.AppendLine($"DisCatSharp: {context.Client.VersionString}"); + builder.AppendLine($"CLR: {Environment.Version}"); + builder.AppendLine($"Host: {Environment.OSVersion}"); + + embed.AddField(Formatter.Underline("Version"), Formatter.BlockCode(builder.ToString().Trim())); + + await context.RespondAsync(embed); + } +} diff --git a/BrackeysBot/Plugins/SimplePluginManager.cs b/BrackeysBot/Plugins/SimplePluginManager.cs index 725e751..6b785c7 100644 --- a/BrackeysBot/Plugins/SimplePluginManager.cs +++ b/BrackeysBot/Plugins/SimplePluginManager.cs @@ -11,6 +11,7 @@ using BrackeysBot.API.Exceptions; using BrackeysBot.API.Plugins; using BrackeysBot.ArgumentConverters; +using BrackeysBot.Commands; using BrackeysBot.Configuration; using BrackeysBot.Resources; using DisCatSharp; @@ -83,6 +84,7 @@ public void DisablePlugin(IPlugin plugin) _loadedPlugins[plugin] = false; + monoPlugin.EnableTime = null; monoPlugin.DiscordClient?.DisconnectAsync(); Logger.Info(string.Format(LoggerMessages.DisabledPlugin, plugin.PluginInfo.Name, plugin.PluginInfo.Version)); } @@ -95,6 +97,8 @@ public void EnablePlugin(IPlugin plugin) if (_loadedPlugins[plugin]) return; if (plugin is not MonoPlugin monoPlugin) return; + monoPlugin.EnableTime = DateTimeOffset.UtcNow; + foreach (IHostedService hostedService in plugin.ServiceProvider.GetServices()) { try @@ -408,11 +412,14 @@ private IEnumerable EnumeratePluginDependencies(Type pluginType) client.MessageCreated += (sender, e) => ClientOnMessageCreated(plugin, sender, e); - return client.UseCommandsNext(new CommandsNextConfiguration + CommandsNextExtension? commandsNext = client.UseCommandsNext(new CommandsNextConfiguration { ServiceProvider = plugin.ServiceProvider, UseDefaultCommandHandler = false }); + + commandsNext.RegisterCommands(); + return commandsNext; } private void SetupPluginDataDirectory(PluginInfo pluginInfo, MonoPlugin instance) @@ -471,6 +478,7 @@ private void SetupPluginServices(MonoPlugin instance, PluginInfo pluginInfo, Typ }); serviceCollection.AddSingleton(this); + serviceCollection.AddSingleton(instance); serviceCollection.AddSingleton(instance.GetType(), instance); serviceCollection.AddSingleton(instance.Configuration);