using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Octobot.Commands; using Octobot.Commands.Events; using Octobot.Services; using Octobot.Services.Update; using Remora.Commands.Extensions; using Remora.Discord.API.Abstractions.Gateway.Commands; using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Objects; using Remora.Discord.Caching.Extensions; using Remora.Discord.Caching.Services; using Remora.Discord.Commands.Extensions; using Remora.Discord.Commands.Services; using Remora.Discord.Gateway; using Remora.Discord.Gateway.Extensions; using Remora.Discord.Hosting.Extensions; using Remora.Rest.Core; using Serilog.Extensions.Logging; namespace Octobot; public sealed class Octobot { public static readonly AllowedMentions NoMentions = new( Array.Empty(), Array.Empty(), Array.Empty()); public const string RepositoryUrl = "https://github.com/LabsDevelopment/Octobot"; public const string IssuesUrl = $"{RepositoryUrl}/issues"; public static async Task Main(string[] args) { var host = CreateHostBuilder(args).UseConsoleLifetime().Build(); var services = host.Services; var slashService = services.GetRequiredService(); // Providing a guild ID to this call will result in command duplicates! // To get rid of them, provide the ID of the guild containing duplicates, // comment out calls to WithCommandGroup in CreateHostBuilder // then launch the bot again and remove the guild ID await slashService.UpdateSlashCommandsAsync(); await host.RunAsync(); } private static IHostBuilder CreateHostBuilder(string[] args) { return Host.CreateDefaultBuilder(args) .AddDiscordService( services => { var configuration = services.GetRequiredService(); return configuration.GetValue("BOT_TOKEN") ?? throw new InvalidOperationException( "No bot token has been provided. Set the " + "BOT_TOKEN environment variable to a valid token."); } ).ConfigureServices( (_, services) => { services.Configure( options => { options.Intents |= GatewayIntents.MessageContents | GatewayIntents.GuildMembers | GatewayIntents.GuildPresences | GatewayIntents.GuildScheduledEvents; }); services.Configure( cSettings => { cSettings.SetDefaultAbsoluteExpiration(TimeSpan.FromHours(1)); cSettings.SetDefaultSlidingExpiration(TimeSpan.FromMinutes(30)); cSettings.SetAbsoluteExpiration(TimeSpan.FromDays(7)); cSettings.SetSlidingExpiration(TimeSpan.FromDays(7)); }); services.AddTransient() // Init .AddDiscordCaching() .AddDiscordCommands(true, false) // Slash command event handlers .AddPreparationErrorEvent() .AddPostExecutionEvent() // Services .AddSingleton() .AddSingleton() .AddHostedService() .AddHostedService() .AddHostedService() .AddHostedService() // Slash commands .AddCommandTree() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup() .WithCommandGroup(); var responderTypes = typeof(Octobot).Assembly .GetExportedTypes() .Where(t => t.IsResponder()); foreach (var responderType in responderTypes) { services.AddResponder(responderType); } } ).ConfigureLogging( c => c.AddConsole() .AddFile("Logs/Octobot-{Date}.log", outputTemplate: "{Timestamp:o} [{Level:u4}] {Message} {NewLine}{Exception}") .AddFilter("System.Net.Http.HttpClient.*.LogicalHandler", LogLevel.Warning) .AddFilter("System.Net.Http.HttpClient.*.ClientHandler", LogLevel.Warning) .AddFilter("System.Net.Http.HttpClient.*.LogicalHandler", LogLevel.Warning) .AddFilter("System.Net.Http.HttpClient.*.ClientHandler", LogLevel.Warning) ); } }