diff --git a/src/NadekoBot/.editorconfig b/src/NadekoBot/.editorconfig index ead66194d..2525eb173 100644 --- a/src/NadekoBot/.editorconfig +++ b/src/NadekoBot/.editorconfig @@ -349,3 +349,4 @@ resharper_csharp_wrap_before_extends_colon = true resharper_csharp_place_constructor_initializer_on_same_line = false resharper_force_attribute_style = separate resharper_braces_for_ifelse = required_for_multiline +resharper_arrange_redundant_parentheses_highlighting = hint \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/UserPunish/UserPunishService.cs b/src/NadekoBot/Modules/Administration/UserPunish/UserPunishService.cs index 624948b20..87e1f4fb4 100644 --- a/src/NadekoBot/Modules/Administration/UserPunish/UserPunishService.cs +++ b/src/NadekoBot/Modules/Administration/UserPunish/UserPunishService.cs @@ -1,5 +1,6 @@ #nullable disable using Microsoft.EntityFrameworkCore; +using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Common.TypeReaders.Models; using NadekoBot.Db; using NadekoBot.Modules.Permissions.Services; @@ -8,32 +9,45 @@ using Newtonsoft.Json; namespace NadekoBot.Modules.Administration.Services; -public class UserPunishService : INService +public class UserPunishService : INService, IReadyExecutor { private readonly MuteService _mute; private readonly DbService _db; private readonly BlacklistService _blacklistService; private readonly BotConfigService _bcs; - private readonly Timer _warnExpiryTimer; + private readonly DiscordSocketClient _client; public UserPunishService( MuteService mute, DbService db, BlacklistService blacklistService, - BotConfigService bcs) + BotConfigService bcs, + DiscordSocketClient client) { _mute = mute; _db = db; _blacklistService = blacklistService; _bcs = bcs; - - _warnExpiryTimer = new(async _ => + _client = client; + } + + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + var expiryTimer = new PeriodicTimer(TimeSpan.FromHours(12)); + do + { + try { await CheckAllWarnExpiresAsync(); - }, - null, - TimeSpan.FromSeconds(0), - TimeSpan.FromHours(12)); + } + catch (Exception ex) + { + Log.Error(ex, "Unexpected error while checking for warn expiries: {ErrorMessage}", ex.Message); + } + } while (await expiryTimer.WaitForNextTickAsync()); } public async Task Warn( diff --git a/src/NadekoBot/Modules/Music/_Common/Impl/MusicPlayer.cs b/src/NadekoBot/Modules/Music/_Common/Impl/MusicPlayer.cs index b04a06ec0..d939bb1d3 100644 --- a/src/NadekoBot/Modules/Music/_Common/Impl/MusicPlayer.cs +++ b/src/NadekoBot/Modules/Music/_Common/Impl/MusicPlayer.cs @@ -1,4 +1,5 @@ using Ayu.Discord.Voice; +using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Services.Database.Models; using System.ComponentModel; using System.Diagnostics; @@ -54,7 +55,7 @@ public sealed class MusicPlayer : IMusicPlayer _songBuffer = new PoopyBufferImmortalized(_vc.InputLength); - _thread = new(async () => + _thread = new(async() => { await PlayLoop(); }); diff --git a/src/NadekoBot/Modules/Utility/Patreon/PatreonRewardsService.cs b/src/NadekoBot/Modules/Utility/Patreon/PatreonRewardsService.cs index 769244efa..ebf944560 100644 --- a/src/NadekoBot/Modules/Utility/Patreon/PatreonRewardsService.cs +++ b/src/NadekoBot/Modules/Utility/Patreon/PatreonRewardsService.cs @@ -1,5 +1,6 @@ #nullable disable using LinqToDB.EntityFrameworkCore; +using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Modules.Gambling.Services; using NadekoBot.Modules.Utility.Common.Patreon; using NadekoBot.Services.Database.Models; @@ -10,14 +11,12 @@ using System.Text.Json; namespace NadekoBot.Modules.Utility; -public class PatreonRewardsService : INService +public class PatreonRewardsService : INService, IReadyExecutor { public TimeSpan Interval { get; } = TimeSpan.FromMinutes(3); public DateTime LastUpdate { get; private set; } = DateTime.UtcNow; - private readonly SemaphoreSlim _getPledgesLocker = new(1, 1); - private readonly Timer _updater; private readonly SemaphoreSlim _claimLockJustInCase = new(1, 1); private readonly DbService _db; private readonly ICurrencyService _currency; @@ -46,9 +45,25 @@ public class PatreonRewardsService : INService _httpFactory = factory; _eb = eb; _client = client; + } - if (client.ShardId == 0) - _updater = new(async _ => await RefreshPledges(_credsProvider.GetCreds()), null, TimeSpan.Zero, Interval); + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + var t = new PeriodicTimer(Interval); + do + { + try + { + await RefreshPledges(_credsProvider.GetCreds()); + } + catch (Exception ex) + { + Log.Error(ex, "Unexpected error refreshing patreon pledges: {ErrorMessage}", ex.Message); + } + } while (await t.WaitForNextTickAsync()); } private DateTime LastAccessTokenUpdate(IBotCredentials creds) @@ -118,7 +133,7 @@ public class PatreonRewardsService : INService var lastUpdate = LastAccessTokenUpdate(creds); var now = DateTime.UtcNow; - + if (lastUpdate.Year != now.Year || lastUpdate.Month != now.Month || string.IsNullOrWhiteSpace(creds.Patreon.AccessToken)) @@ -135,7 +150,6 @@ public class PatreonRewardsService : INService } LastUpdate = DateTime.UtcNow; - await _getPledgesLocker.WaitAsync(); try { var members = new List(); @@ -196,10 +210,6 @@ public class PatreonRewardsService : INService { Log.Warning(ex, "Error refreshing patreon pledges"); } - finally - { - _getPledgesLocker.Release(); - } } public async Task ClaimReward(ulong userId, string patreonUserId, int cents) diff --git a/src/NadekoBot/Modules/Utility/UnitConversion/ConverterService.cs b/src/NadekoBot/Modules/Utility/UnitConversion/ConverterService.cs index 634b24e0c..8470a8cdb 100644 --- a/src/NadekoBot/Modules/Utility/UnitConversion/ConverterService.cs +++ b/src/NadekoBot/Modules/Utility/UnitConversion/ConverterService.cs @@ -1,16 +1,17 @@ #nullable disable +using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Modules.Utility.Common; using Newtonsoft.Json; namespace NadekoBot.Modules.Utility.Services; -public class ConverterService : INService +public class ConverterService : INService, IReadyExecutor { public ConvertUnit[] Units => _cache.Redis.GetDatabase().StringGet("converter_units").ToString().MapJson(); - private readonly Timer _currencyUpdater; private readonly TimeSpan _updateInterval = new(12, 0, 0); + private readonly DiscordSocketClient _client; private readonly IDataCache _cache; private readonly IHttpClientFactory _httpFactory; @@ -19,14 +20,28 @@ public class ConverterService : INService IDataCache cache, IHttpClientFactory factory) { + _client = client; _cache = cache; _httpFactory = factory; + } - if (client.ShardId == 0) - _currencyUpdater = new(async shouldLoad => await UpdateCurrency((bool)shouldLoad!), - client.ShardId == 0, - TimeSpan.Zero, - _updateInterval); + public async Task OnReadyAsync() + { + if (_client.ShardId != 0) + return; + + var timer = new PeriodicTimer(_updateInterval); + do + { + try + { + await UpdateCurrency(); + } + catch + { + // ignored + } + } while (await timer.WaitForNextTickAsync()); } private async Task GetCurrencyRates() @@ -36,37 +51,27 @@ public class ConverterService : INService return JsonConvert.DeserializeObject(res); } - private async Task UpdateCurrency(bool shouldLoad) + private async Task UpdateCurrency() { - try + var unitTypeString = "currency"; + var currencyRates = await GetCurrencyRates(); + var baseType = new ConvertUnit { - var unitTypeString = "currency"; - if (shouldLoad) - { - var currencyRates = await GetCurrencyRates(); - var baseType = new ConvertUnit - { - Triggers = new[] { currencyRates.Base }, Modifier = decimal.One, UnitType = unitTypeString - }; - var range = currencyRates.ConversionRates.Select(u => new ConvertUnit - { - Triggers = new[] { u.Key }, Modifier = u.Value, UnitType = unitTypeString - }) - .ToArray(); + Triggers = new[] { currencyRates.Base }, Modifier = decimal.One, UnitType = unitTypeString + }; + var range = currencyRates.ConversionRates.Select(u => new ConvertUnit + { + Triggers = new[] { u.Key }, Modifier = u.Value, UnitType = unitTypeString + }) + .ToArray(); - var fileData = JsonConvert.DeserializeObject(File.ReadAllText("data/units.json")) - ?.Where(x => x.UnitType != "currency"); - if (fileData is null) - return; + var fileData = JsonConvert.DeserializeObject(File.ReadAllText("data/units.json")) + ?.Where(x => x.UnitType != "currency"); + if (fileData is null) + return; - var data = JsonConvert.SerializeObject(range.Append(baseType).Concat(fileData).ToList()); - _cache.Redis.GetDatabase().StringSet("converter_units", data); - } - } - catch - { - // ignored - } + var data = JsonConvert.SerializeObject(range.Append(baseType).Concat(fileData).ToList()); + _cache.Redis.GetDatabase().StringSet("converter_units", data); } }