mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 08:34:27 -05:00 
			
		
		
		
	Using PeriodicTimer instead of threading.timer in some services
This commit is contained in:
		@@ -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
 | 
			
		||||
@@ -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<WarningPunishment> Warn(
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -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<PatreonMember>();
 | 
			
		||||
@@ -196,10 +210,6 @@ public class PatreonRewardsService : INService
 | 
			
		||||
        {
 | 
			
		||||
            Log.Warning(ex, "Error refreshing patreon pledges");
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            _getPledgesLocker.Release();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<int> ClaimReward(ulong userId, string patreonUserId, int cents)
 | 
			
		||||
 
 | 
			
		||||
@@ -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<ConvertUnit[]>();
 | 
			
		||||
 | 
			
		||||
    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<Rates> GetCurrencyRates()
 | 
			
		||||
@@ -36,37 +51,27 @@ public class ConverterService : INService
 | 
			
		||||
        return JsonConvert.DeserializeObject<Rates>(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<ConvertUnit[]>(File.ReadAllText("data/units.json"))
 | 
			
		||||
                                          ?.Where(x => x.UnitType != "currency");
 | 
			
		||||
                if (fileData is null)
 | 
			
		||||
                    return;
 | 
			
		||||
        var fileData = JsonConvert.DeserializeObject<ConvertUnit[]>(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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user