mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 17:58:26 -04:00
add: notify, minesweeper, migrations
dev: renames, refactors change: remind optimized wait
This commit is contained in:
@@ -9,6 +9,7 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
private readonly MessageSenderService _mss;
|
||||
|
||||
private static readonly TimeSpan _maxAfkDuration = 8.Hours();
|
||||
|
||||
public AfkService(IBotCache cache, DiscordSocketClient client, MessageSenderService mss)
|
||||
{
|
||||
_cache = cache;
|
||||
@@ -19,6 +20,9 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
private static TypedKey<string> GetKey(ulong userId)
|
||||
=> new($"afk:msg:{userId}");
|
||||
|
||||
private static TypedKey<bool> GetRecentlySentKey(ulong userId, ulong channelId)
|
||||
=> new($"afk:recent:{userId}:{channelId}");
|
||||
|
||||
public async Task<bool> SetAfkAsync(ulong userId, string text)
|
||||
{
|
||||
var added = await _cache.AddAsync(GetKey(userId), text, _maxAfkDuration, overwrite: true);
|
||||
@@ -43,9 +47,7 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
msg.DeleteAfter(5);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -61,7 +63,7 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
await Task.Delay(_maxAfkDuration);
|
||||
_client.MessageReceived -= StopAfk;
|
||||
});
|
||||
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
@@ -72,36 +74,29 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task TryTriggerAfkMessage(SocketMessage arg)
|
||||
private Task TryTriggerAfkMessage(SocketMessage sm)
|
||||
{
|
||||
if (arg.Author.IsBot || arg.Author.IsWebhook)
|
||||
if (sm.Author.IsBot || sm.Author.IsWebhook)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (arg is not IUserMessage uMsg || uMsg.Channel is not ITextChannel tc)
|
||||
if (sm is not IUserMessage uMsg || uMsg.Channel is not ITextChannel tc)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if ((arg.MentionedUsers.Count is 0 or > 3) && uMsg.ReferencedMessage is null)
|
||||
|
||||
if ((sm.MentionedUsers.Count is 0 or > 3) && uMsg.ReferencedMessage is null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var botUser = await tc.Guild.GetCurrentUserAsync();
|
||||
|
||||
var perms = botUser.GetPermissions(tc);
|
||||
|
||||
if (!perms.SendMessages)
|
||||
return;
|
||||
|
||||
ulong mentionedUserId = 0;
|
||||
|
||||
if (arg.MentionedUsers.Count <= 3)
|
||||
if (sm.MentionedUsers.Count <= 3)
|
||||
{
|
||||
foreach (var uid in uMsg.MentionedUserIds)
|
||||
{
|
||||
if (uid == arg.Author.Id)
|
||||
if (uid == sm.Author.Id)
|
||||
continue;
|
||||
|
||||
if (arg.Content.StartsWith($"<@{uid}>") || arg.Content.StartsWith($"<@!{uid}>"))
|
||||
if (sm.Content.StartsWith($"<@{uid}>") || sm.Content.StartsWith($"<@!{uid}>"))
|
||||
{
|
||||
mentionedUserId = uid;
|
||||
break;
|
||||
@@ -115,26 +110,46 @@ public sealed class AfkService : INService, IReadyExecutor
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mentionedUserId = repliedUserId;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _cache.GetAsync(GetKey(mentionedUserId));
|
||||
if (result.TryPickT0(out var msg, out _))
|
||||
{
|
||||
var st = SmartText.CreateFrom(msg);
|
||||
|
||||
|
||||
st = $"The user you've pinged (<#{mentionedUserId}>) is AFK: " + st;
|
||||
|
||||
var toDelete = await _mss.Response(arg.Channel)
|
||||
.User(arg.Author)
|
||||
|
||||
var toDelete = await _mss.Response(sm.Channel)
|
||||
.User(sm.Author)
|
||||
.Message(uMsg)
|
||||
.Text(st)
|
||||
.SendAsync();
|
||||
|
||||
toDelete.DeleteAfter(30);
|
||||
|
||||
var botUser = await tc.Guild.GetCurrentUserAsync();
|
||||
var perms = botUser.GetPermissions(tc);
|
||||
if (!perms.SendMessages)
|
||||
return;
|
||||
|
||||
var key = GetRecentlySentKey(mentionedUserId, sm.Channel.Id);
|
||||
var recent = await _cache.GetAsync(key);
|
||||
|
||||
if (!recent.TryPickT0(out _, out _))
|
||||
{
|
||||
var chMsg = await _mss.Response(sm.Channel)
|
||||
.Message(uMsg)
|
||||
.Pending(strs.user_afk($"<@{mentionedUserId}>"))
|
||||
.SendAsync();
|
||||
|
||||
chMsg.DeleteAfter(5);
|
||||
await _cache.AddAsync(key, true, expiry: TimeSpan.FromMinutes(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpException ex)
|
||||
|
@@ -98,10 +98,10 @@ public partial class Utility
|
||||
return;
|
||||
|
||||
var embed = CreateEmbed()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(guildId is not null
|
||||
? strs.reminder_server_list
|
||||
: strs.reminder_list));
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(guildId is not null
|
||||
? strs.reminder_server_list
|
||||
: strs.reminder_list));
|
||||
|
||||
List<Reminder> rems;
|
||||
if (guildId is { } gid)
|
||||
@@ -193,23 +193,14 @@ public partial class Utility
|
||||
message = message.SanitizeAllMentions();
|
||||
}
|
||||
|
||||
var rem = new Reminder
|
||||
{
|
||||
ChannelId = targetId,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
UserId = ctx.User.Id,
|
||||
ServerId = ctx.Guild?.Id ?? 0
|
||||
};
|
||||
await _service.AddReminderAsync(ctx.User.Id,
|
||||
targetId,
|
||||
ctx.Guild?.Id,
|
||||
isPrivate,
|
||||
time,
|
||||
message,
|
||||
ReminderType.User);
|
||||
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
uow.Set<Reminder>().Add(rem);
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
|
||||
await Response()
|
||||
.Confirm($"\u23f0 {GetText(strs.remind2(
|
||||
Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
|
||||
|
@@ -21,6 +21,8 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
private readonly IMessageSenderService _sender;
|
||||
private readonly CultureInfo _culture;
|
||||
|
||||
private TaskCompletionSource<bool> _tcs;
|
||||
|
||||
public RemindService(
|
||||
DiscordSocketClient client,
|
||||
DbService db,
|
||||
@@ -44,8 +46,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
while (true)
|
||||
{
|
||||
await OnReminderLoopTickInternalAsync();
|
||||
}
|
||||
@@ -55,8 +56,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
{
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var reminders = await GetRemindersBeforeAsync(now);
|
||||
var reminders = await GetRemindersBeforeAsync();
|
||||
if (reminders.Count == 0)
|
||||
return;
|
||||
|
||||
@@ -67,7 +67,6 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
{
|
||||
var executedReminders = group.ToList();
|
||||
await executedReminders.Select(ReminderTimerAction).WhenAll();
|
||||
await RemoveReminders(executedReminders.Select(x => x.Id));
|
||||
await Task.Delay(1500);
|
||||
}
|
||||
}
|
||||
@@ -80,21 +79,51 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
private async Task RemoveReminders(IEnumerable<int> reminders)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
await uow.GetTable<Reminder>()
|
||||
.DeleteAsync(x => reminders.Contains(x.Id));
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task<List<Reminder>> GetRemindersBeforeAsync(DateTime now)
|
||||
private async Task<IReadOnlyList<Reminder>> GetRemindersBeforeAsync()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
return await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId, _creds.TotalShards, _client.ShardId)
|
||||
&& x.When < now)
|
||||
.ToListAsyncLinqToDB();
|
||||
while (true)
|
||||
{
|
||||
_tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
await using var uow = _db.GetDbContext();
|
||||
var earliest = await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId,
|
||||
_creds.TotalShards,
|
||||
_client.ShardId))
|
||||
.OrderBy(x => x.When)
|
||||
.FirstOrDefaultAsyncLinqToDB();
|
||||
|
||||
if (earliest == default)
|
||||
{
|
||||
await _tcs.Task;
|
||||
continue;
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
if (earliest.When > now)
|
||||
{
|
||||
var diff = earliest.When - now;
|
||||
// Log.Information("Waiting for {Diff}", diff);
|
||||
await Task.WhenAny(Task.Delay(diff), _tcs.Task);
|
||||
continue;
|
||||
}
|
||||
|
||||
var reminders = await uow.Set<Reminder>()
|
||||
.ToLinqToDBTable()
|
||||
.Where(x => Linq2DbExpressions.GuildOnShard(x.ServerId,
|
||||
_creds.TotalShards,
|
||||
_client.ShardId))
|
||||
.Where(x => x.When <= now)
|
||||
.DeleteWithOutputAsync();
|
||||
|
||||
return reminders;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryParseRemindMessage(string input, out RemindObject obj)
|
||||
@@ -243,21 +272,24 @@ public class RemindService : INService, IReadyExecutor, IRemindService
|
||||
string message,
|
||||
ReminderType reminderType)
|
||||
{
|
||||
var rem = new Reminder
|
||||
await using (var ctx = _db.GetDbContext())
|
||||
{
|
||||
UserId = userId,
|
||||
ChannelId = targetId,
|
||||
ServerId = guildId ?? 0,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
Type = reminderType
|
||||
};
|
||||
await ctx.GetTable<Reminder>()
|
||||
.InsertAsync(() => new Reminder
|
||||
{
|
||||
UserId = userId,
|
||||
ChannelId = targetId,
|
||||
ServerId = guildId ?? 0,
|
||||
IsPrivate = isPrivate,
|
||||
When = time,
|
||||
Message = message,
|
||||
Type = reminderType,
|
||||
DateAdded = DateTime.UtcNow
|
||||
});
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.Set<Reminder>()
|
||||
.AddAsync(rem);
|
||||
await ctx.SaveChangesAsync();
|
||||
_tcs.SetResult(true);
|
||||
}
|
||||
|
||||
public async Task<List<Reminder>> GetServerReminders(int page, ulong guildId)
|
||||
|
@@ -110,14 +110,14 @@ public partial class Utility
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Repeat(StoopidTime interval, [Leftover] string message)
|
||||
public Task Repeat(ParsedTimespan interval, [Leftover] string message)
|
||||
=> Repeat(ctx.Channel, null, interval, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(0)]
|
||||
public Task Repeat(ITextChannel channel, StoopidTime interval, [Leftover] string message)
|
||||
public Task Repeat(ITextChannel channel, ParsedTimespan interval, [Leftover] string message)
|
||||
=> Repeat(channel, null, interval, message);
|
||||
|
||||
[Cmd]
|
||||
@@ -138,14 +138,14 @@ public partial class Utility
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(2)]
|
||||
public Task Repeat(GuildDateTime? timeOfDay, StoopidTime? interval, [Leftover] string message)
|
||||
public Task Repeat(GuildDateTime? timeOfDay, ParsedTimespan? interval, [Leftover] string message)
|
||||
=> Repeat(ctx.Channel, timeOfDay, interval, message);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[Priority(3)]
|
||||
public async Task Repeat(IMessageChannel channel, GuildDateTime? timeOfDay, StoopidTime? interval,
|
||||
public async Task Repeat(IMessageChannel channel, GuildDateTime? timeOfDay, ParsedTimespan? interval,
|
||||
[Leftover] string message)
|
||||
{
|
||||
if (channel is not ITextChannel txtCh || txtCh.GuildId != ctx.Guild.Id)
|
||||
|
Reference in New Issue
Block a user