mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
More PeriodicTimer's instead of System.Threading.Timers
This commit is contained in:
@@ -29,7 +29,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||
var index = 0;
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
|
@@ -22,7 +22,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
||||
private readonly IEmbedBuilderService _eb;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
private readonly Timer _clearTimer;
|
||||
private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new();
|
||||
|
||||
public LogCommandService(
|
||||
@@ -80,21 +79,25 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
||||
|
||||
_prot.OnAntiProtectionTriggered += TriggeredAntiProtection;
|
||||
|
||||
_clearTimer = new(_ =>
|
||||
{
|
||||
_ignoreMessageIds.Clear();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromHours(1),
|
||||
TimeSpan.FromHours(1));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
public Task OnReadyAsync()
|
||||
=> Task.WhenAll(PresenceUpdateTask(), IgnoreMessageIdsClearTask());
|
||||
|
||||
private async Task IgnoreMessageIdsClearTask()
|
||||
{
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromHours(1));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
_ignoreMessageIds.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PresenceUpdateTask()
|
||||
{
|
||||
#if !GLOBAL_NADEKO
|
||||
var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
try
|
||||
@@ -105,6 +108,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
||||
{
|
||||
if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (PresenceUpdates.TryRemove(key, out var msgs))
|
||||
{
|
||||
var title = GetText(key.Guild, strs.presence_updates);
|
||||
|
@@ -36,7 +36,7 @@ public class UserPunishService : INService, IReadyExecutor
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
var expiryTimer = new PeriodicTimer(TimeSpan.FromHours(12));
|
||||
using var expiryTimer = new PeriodicTimer(TimeSpan.FromHours(12));
|
||||
do
|
||||
{
|
||||
try
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Connect4;
|
||||
@@ -9,7 +10,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
public class GamblingService : INService
|
||||
public class GamblingService : INService, IReadyExecutor
|
||||
{
|
||||
public ConcurrentDictionary<(ulong, ulong), RollDuelGame> Duels { get; } = new();
|
||||
public ConcurrentDictionary<ulong, Connect4Game> Connect4Games { get; } = new();
|
||||
@@ -20,8 +21,6 @@ public class GamblingService : INService
|
||||
private readonly IDataCache _cache;
|
||||
private readonly GamblingConfigService _gss;
|
||||
|
||||
private readonly Timer _decayTimer;
|
||||
|
||||
public GamblingService(
|
||||
DbService db,
|
||||
Bot bot,
|
||||
@@ -36,32 +35,38 @@ public class GamblingService : INService
|
||||
_client = client;
|
||||
_cache = cache;
|
||||
_gss = gss;
|
||||
}
|
||||
|
||||
if (_bot.Client.ShardId == 0)
|
||||
_decayTimer = new(_ =>
|
||||
{
|
||||
var config = _gss.Data;
|
||||
var maxDecay = config.Decay.MaxDecay;
|
||||
if (config.Decay.Percent is <= 0 or > 1 || maxDecay < 0)
|
||||
return;
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
if (_bot.Client.ShardId != 0)
|
||||
return;
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
var lastCurrencyDecay = _cache.GetLastCurrencyDecay();
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
var config = _gss.Data;
|
||||
var maxDecay = config.Decay.MaxDecay;
|
||||
if (config.Decay.Percent is <= 0 or > 1 || maxDecay < 0)
|
||||
continue;
|
||||
|
||||
if (DateTime.UtcNow - lastCurrencyDecay < TimeSpan.FromHours(config.Decay.HourInterval))
|
||||
return;
|
||||
await using var uow = _db.GetDbContext();
|
||||
var lastCurrencyDecay = _cache.GetLastCurrencyDecay();
|
||||
|
||||
Log.Information(@"Decaying users' currency - decay: {ConfigDecayPercent}%
|
||||
if (DateTime.UtcNow - lastCurrencyDecay < TimeSpan.FromHours(config.Decay.HourInterval))
|
||||
continue;
|
||||
|
||||
Log.Information(@"Decaying users' currency - decay: {ConfigDecayPercent}%
|
||||
| max: {MaxDecay}
|
||||
| threshold: {DecayMinTreshold}",
|
||||
config.Decay.Percent * 100,
|
||||
maxDecay,
|
||||
config.Decay.MinThreshold);
|
||||
config.Decay.Percent * 100,
|
||||
maxDecay,
|
||||
config.Decay.MinThreshold);
|
||||
|
||||
if (maxDecay == 0)
|
||||
maxDecay = int.MaxValue;
|
||||
if (maxDecay == 0)
|
||||
maxDecay = int.MaxValue;
|
||||
|
||||
uow.Database.ExecuteSqlInterpolated($@"
|
||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"
|
||||
UPDATE DiscordUser
|
||||
SET CurrencyAmount=
|
||||
CASE WHEN
|
||||
@@ -73,12 +78,9 @@ SET CurrencyAmount=
|
||||
END
|
||||
WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentUser.Id};");
|
||||
|
||||
_cache.SetLastCurrencyDecay();
|
||||
uow.SaveChanges();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromMinutes(5),
|
||||
TimeSpan.FromMinutes(5));
|
||||
_cache.SetLastCurrencyDecay();
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<SlotResponse> SlotAsync(ulong userId, long amount)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
using NadekoBot.Modules.Games.Common.Acrophobia;
|
||||
using NadekoBot.Modules.Games.Common.Nunchi;
|
||||
@@ -8,7 +9,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Services;
|
||||
|
||||
public class GamesService : INService
|
||||
public class GamesService : INService, IReadyExecutor
|
||||
{
|
||||
private const string TYPING_ARTICLES_PATH = "data/typing_articles3.json";
|
||||
|
||||
@@ -29,7 +30,6 @@ public class GamesService : INService
|
||||
public AsyncLazy<RatingTexts> Ratings { get; }
|
||||
private readonly GamesConfigService _gamesConfig;
|
||||
|
||||
private readonly Timer _t;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IMemoryCache _8BallCache;
|
||||
private readonly Random _rng;
|
||||
@@ -46,15 +46,6 @@ public class GamesService : INService
|
||||
Ratings = new(GetRatingTexts);
|
||||
_rng = new NadekoRandom();
|
||||
|
||||
//girl ratings
|
||||
_t = new(_ =>
|
||||
{
|
||||
GirlRatings.Clear();
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromDays(1),
|
||||
TimeSpan.FromDays(1));
|
||||
|
||||
try
|
||||
{
|
||||
TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(TYPING_ARTICLES_PATH));
|
||||
@@ -66,6 +57,16 @@ public class GamesService : INService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
// reset rating once a day
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromDays(1));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
GirlRatings.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<RatingTexts> GetRatingTexts()
|
||||
{
|
||||
using var http = _httpFactory.CreateClient();
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Searches.Common;
|
||||
@@ -9,7 +10,7 @@ using StackExchange.Redis;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Services;
|
||||
|
||||
public sealed class StreamNotificationService : INService
|
||||
public sealed class StreamNotificationService : INService, IReadyExecutor
|
||||
{
|
||||
private readonly DbService _db;
|
||||
private readonly IBotStrings _strings;
|
||||
@@ -26,7 +27,6 @@ public sealed class StreamNotificationService : INService
|
||||
|
||||
private readonly IPubSub _pubSub;
|
||||
private readonly IEmbedBuilderService _eb;
|
||||
private readonly Timer _notifCleanupTimer;
|
||||
|
||||
private readonly TypedKey<List<StreamData>> _streamsOnlineKey;
|
||||
private readonly TypedKey<List<StreamData>> _streamsOfflineKey;
|
||||
@@ -114,49 +114,6 @@ public sealed class StreamNotificationService : INService
|
||||
_streamTracker.OnStreamsOffline += OnStreamsOffline;
|
||||
_streamTracker.OnStreamsOnline += OnStreamsOnline;
|
||||
_ = _streamTracker.RunAsync();
|
||||
_notifCleanupTimer = new(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorLimit = TimeSpan.FromHours(12);
|
||||
var failingStreams = _streamTracker.GetFailingStreams(errorLimit, true).ToList();
|
||||
|
||||
if (!failingStreams.Any())
|
||||
return;
|
||||
|
||||
var deleteGroups = failingStreams.GroupBy(x => x.Type)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList());
|
||||
|
||||
using var uow = _db.GetDbContext();
|
||||
foreach (var kvp in deleteGroups)
|
||||
{
|
||||
Log.Information(
|
||||
"Deleting {StreamCount} {Platform} streams because they've been erroring for more than {ErrorLimit}: {RemovedList}",
|
||||
kvp.Value.Count,
|
||||
kvp.Key,
|
||||
errorLimit,
|
||||
string.Join(", ", kvp.Value));
|
||||
|
||||
var toDelete = uow.Set<FollowedStream>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username))
|
||||
.ToList();
|
||||
|
||||
uow.RemoveRange(toDelete);
|
||||
uow.SaveChanges();
|
||||
|
||||
foreach (var loginToDelete in kvp.Value)
|
||||
_streamTracker.UntrackStreamByKey(new(kvp.Key, loginToDelete));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error cleaning up FollowedStreams");
|
||||
}
|
||||
},
|
||||
null,
|
||||
TimeSpan.FromMinutes(30),
|
||||
TimeSpan.FromMinutes(30));
|
||||
|
||||
_pubSub.Sub(_streamFollowKey, HandleFollowStream);
|
||||
_pubSub.Sub(_streamUnfollowKey, HandleUnfollowStream);
|
||||
@@ -166,6 +123,54 @@ public sealed class StreamNotificationService : INService
|
||||
client.LeftGuild += ClientOnLeftGuild;
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(30));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorLimit = TimeSpan.FromHours(12);
|
||||
var failingStreams = _streamTracker.GetFailingStreams(errorLimit, true).ToList();
|
||||
|
||||
if (!failingStreams.Any())
|
||||
continue;
|
||||
|
||||
var deleteGroups = failingStreams.GroupBy(x => x.Type)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList());
|
||||
|
||||
await using var uow = _db.GetDbContext();
|
||||
foreach (var kvp in deleteGroups)
|
||||
{
|
||||
Log.Information(
|
||||
"Deleting {StreamCount} {Platform} streams because they've been erroring for more than {ErrorLimit}: {RemovedList}",
|
||||
kvp.Value.Count,
|
||||
kvp.Key,
|
||||
errorLimit,
|
||||
string.Join(", ", kvp.Value));
|
||||
|
||||
var toDelete = uow.Set<FollowedStream>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.Type == kvp.Key && kvp.Value.Contains(x.Username))
|
||||
.ToList();
|
||||
|
||||
uow.RemoveRange(toDelete);
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
foreach (var loginToDelete in kvp.Value)
|
||||
_streamTracker.UntrackStreamByKey(new(kvp.Key, loginToDelete));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error cleaning up FollowedStreams");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles follow stream pubs to keep the counter up to date.
|
||||
/// When counter reaches 0, stream is removed from tracking because
|
||||
|
@@ -52,7 +52,7 @@ public class PatreonRewardsService : INService, IReadyExecutor
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
var t = new PeriodicTimer(Interval);
|
||||
using var t = new PeriodicTimer(Interval);
|
||||
do
|
||||
{
|
||||
try
|
||||
|
@@ -30,7 +30,7 @@ public class ConverterService : INService, IReadyExecutor
|
||||
if (_client.ShardId != 0)
|
||||
return;
|
||||
|
||||
var timer = new PeriodicTimer(_updateInterval);
|
||||
using var timer = new PeriodicTimer(_updateInterval);
|
||||
do
|
||||
{
|
||||
try
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.Configs;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using System.Collections.Immutable;
|
||||
using ExecuteResult = Discord.Commands.ExecuteResult;
|
||||
@@ -7,7 +8,7 @@ using PreconditionResult = Discord.Commands.PreconditionResult;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
|
||||
public class CommandHandler : INService
|
||||
public class CommandHandler : INService, IReadyExecutor
|
||||
{
|
||||
private const int GLOBAL_COMMANDS_COOLDOWN = 750;
|
||||
|
||||
@@ -30,7 +31,6 @@ public class CommandHandler : INService
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, string> _prefixes;
|
||||
private readonly Timer _clearUsersOnShortCooldown;
|
||||
private readonly DbService _db;
|
||||
// private readonly InteractionService _interactions;
|
||||
|
||||
@@ -53,19 +53,21 @@ public class CommandHandler : INService
|
||||
_services = services;
|
||||
// _interactions = interactions;
|
||||
|
||||
_clearUsersOnShortCooldown = new(_ =>
|
||||
{
|
||||
UsersOnShortCooldown.Clear();
|
||||
},
|
||||
null,
|
||||
GLOBAL_COMMANDS_COOLDOWN,
|
||||
GLOBAL_COMMANDS_COOLDOWN);
|
||||
|
||||
_prefixes = bot.AllGuildConfigs.Where(x => x.Prefix is not null)
|
||||
.ToDictionary(x => x.GuildId, x => x.Prefix)
|
||||
.ToConcurrent();
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
// clear users on short cooldown every GLOBAL_COMMANDS_COOLDOWN miliseconds
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(GLOBAL_COMMANDS_COOLDOWN));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
UsersOnShortCooldown.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPrefix(IGuild guild)
|
||||
=> GetPrefix(guild?.Id);
|
||||
|
||||
|
@@ -139,7 +139,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
||||
textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
|
||||
voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel));
|
||||
|
||||
var timer = new PeriodicTimer(TimeSpan.FromHours(1));
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromHours(1));
|
||||
do
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_creds.BotListToken))
|
||||
|
Reference in New Issue
Block a user