public async void Start() { Task.Run(async() => { while (true) { try { var previousGuildCount = _currentGuilds.Count; var newSettings = _discordSettingsProvider.Provide(); try { var newGuilds = new HashSet <ulong>(_client?.Guilds.Keys.ToArray() ?? Array.Empty <ulong>()); if (newGuilds.Any()) { _currentGuilds.UnionWith(newGuilds); } } catch (System.Exception) { } if (!_currentSettings.Equals(newSettings) || Language.Current != _previousLanguage || _currentGuilds.Count != previousGuildCount) { var previousSettings = _currentSettings; _logger.LogWarning("Bot configuration changed: restarting bot"); _currentSettings = newSettings; _previousLanguage = Language.Current; await RestartBot(previousSettings, newSettings, _currentGuilds); _logger.LogWarning("Bot has been restarted."); SlashCommandBuilder.CleanUp(); } } catch (Exception ex) { _logger.LogError(ex, "Error while restarting the bot: " + ex.Message); } await Task.Delay(5000); } }); }
private async Task RestartBot(DiscordSettings previousSettings, DiscordSettings newSettings, HashSet <ulong> currentGuilds) { if (!string.IsNullOrEmpty(newSettings.BotToken)) { if (!string.Equals(previousSettings.BotToken, newSettings.BotToken, StringComparison.OrdinalIgnoreCase)) { if (_client != null) { await _client.DisconnectAsync(); _client.Ready -= Connected; _client.ComponentInteractionCreated -= DiscordComponentInteractionCreatedHandler; _client.Dispose(); } if (_slashCommands != null) { _slashCommands.SlashCommandErrored -= SlashCommandErrorHandler; } var config = new DiscordConfiguration() { Token = newSettings.BotToken, TokenType = TokenType.Bot, AutoReconnect = true, MinimumLogLevel = LogLevel.Warning, Intents = DiscordIntents.All, ReconnectIndefinitely = true }; _client = new DiscordClient(config); _slashCommands = _client.UseSlashCommands(new SlashCommandsConfiguration { Services = new ServiceCollection() .AddSingleton <DiscordClient>(_client) .AddSingleton <ILogger>(_logger) .AddSingleton <DiscordSettingsProvider>(_discordSettingsProvider) .AddSingleton <MovieWorkflowFactory>(_movieWorkflowFactory) .AddSingleton <TvShowWorkflowFactory>(_tvShowWorkflowFactory) .BuildServiceProvider() }); _slashCommands.SlashCommandErrored += SlashCommandErrorHandler; _client.Ready += Connected; _client.ComponentInteractionCreated += DiscordComponentInteractionCreatedHandler; _currentGuilds = new HashSet <ulong>(); await _client.ConnectAsync(); } if (_client != null) { if (_client.Guilds.Any()) { await ApplyBotConfigurationAsync(newSettings); var prop = _slashCommands.GetType().GetProperty("_updateList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); prop.SetValue(_slashCommands, new List <KeyValuePair <ulong?, Type> >()); var slashCommandType = SlashCommandBuilder.Build(_logger, newSettings, _serviceProvider.Get <RadarrSettingsProvider>(), _serviceProvider.Get <SonarrSettingsProvider>(), _serviceProvider.Get <OverseerrSettingsProvider>()); if (newSettings.EnableRequestsThroughDirectMessages) { try { _slashCommands.RegisterCommands(slashCommandType); } catch (System.Exception ex) { _logger.LogError(ex, "Error while registering global slash commands: " + ex.Message); } foreach (var guildId in _client.Guilds.Keys) { try { _slashCommands.RegisterCommands <EmptySlashCommands>(guildId); } catch (System.Exception ex) { _logger.LogError(ex, $"Error while emptying guild-specific slash commands for guid {guildId}: " + ex.Message); } } } else { try { _slashCommands.RegisterCommands <EmptySlashCommands>(); } catch (System.Exception ex) { _logger.LogError(ex, "Error while emptying global slash commands: " + ex.Message); } foreach (var guildId in _client.Guilds.Keys) { try { _slashCommands.RegisterCommands(slashCommandType, guildId); } catch (System.Exception ex) { _logger.LogError(ex, $"Error while registering guild-specific slash commands for guid {guildId}: " + ex.Message); } } } await _slashCommands.RefreshCommands(); await Task.Delay(TimeSpan.FromMinutes(1)); } } else { _logger.LogWarning("No Bot Token for Discord has been configured."); } } }