feat: rewrite database schema for localized autoproxy
This commit is contained in:
@@ -18,12 +18,12 @@ public class ProxyMatcher
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
public bool TryMatch(MessageContext ctx, IReadOnlyCollection<ProxyMember> members, out ProxyMatch match,
|
||||
public bool TryMatch(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection<ProxyMember> members, out ProxyMatch match,
|
||||
string messageContent,
|
||||
bool hasAttachments, bool allowAutoproxy)
|
||||
{
|
||||
if (TryMatchTags(members, messageContent, hasAttachments, out match)) return true;
|
||||
if (allowAutoproxy && TryMatchAutoproxy(ctx, members, messageContent, out match)) return true;
|
||||
if (allowAutoproxy && TryMatchAutoproxy(ctx, settings, members, messageContent, out match)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ProxyMatcher
|
||||
return hasAttachments || match.Content.Trim().Length > 0;
|
||||
}
|
||||
|
||||
private bool TryMatchAutoproxy(MessageContext ctx, IReadOnlyCollection<ProxyMember> members,
|
||||
private bool TryMatchAutoproxy(MessageContext ctx, AutoproxySettings settings, IReadOnlyCollection<ProxyMember> members,
|
||||
string messageContent,
|
||||
out ProxyMatch match)
|
||||
{
|
||||
@@ -49,41 +49,41 @@ public class ProxyMatcher
|
||||
"This message matches none of your proxy tags, and it was not autoproxied because it starts with a backslash (`\\`).");
|
||||
|
||||
// Find the member we should autoproxy (null if none)
|
||||
var member = ctx.AutoproxyMode switch
|
||||
var member = settings.AutoproxyMode switch
|
||||
{
|
||||
AutoproxyMode.Member when ctx.AutoproxyMember != null =>
|
||||
members.FirstOrDefault(m => m.Id == ctx.AutoproxyMember),
|
||||
AutoproxyMode.Member when settings.AutoproxyMember != null =>
|
||||
members.FirstOrDefault(m => m.Id == settings.AutoproxyMember),
|
||||
|
||||
AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 =>
|
||||
members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]),
|
||||
|
||||
AutoproxyMode.Latch when ctx.LastMessageMember != null =>
|
||||
members.FirstOrDefault(m => m.Id == ctx.LastMessageMember.Value),
|
||||
AutoproxyMode.Latch when settings.AutoproxyMember != null =>
|
||||
members.FirstOrDefault(m => m.Id == settings.AutoproxyMember.Value),
|
||||
|
||||
_ => null
|
||||
};
|
||||
// Throw an error if the member is null, message varies depending on autoproxy mode
|
||||
if (member == null)
|
||||
{
|
||||
if (ctx.AutoproxyMode == AutoproxyMode.Front)
|
||||
if (settings.AutoproxyMode == AutoproxyMode.Front)
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"You are using autoproxy front, but no members are currently registered as fronting. Please use `pk;switch <member>` to log a new switch.");
|
||||
if (ctx.AutoproxyMode == AutoproxyMode.Member)
|
||||
if (settings.AutoproxyMode == AutoproxyMode.Member)
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"You are using member-specific autoproxy with an invalid member. Was this member deleted?");
|
||||
if (ctx.AutoproxyMode == AutoproxyMode.Latch)
|
||||
if (settings.AutoproxyMode == AutoproxyMode.Latch)
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"You are using autoproxy latch, but have not sent any messages yet in this server. Please send a message using proxy tags first.");
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"This message matches none of your proxy tags and autoproxy is not enabled.");
|
||||
}
|
||||
|
||||
if (ctx.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)
|
||||
if (settings.AutoproxyMode != AutoproxyMode.Member && !member.AllowAutoproxy)
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"This member has autoproxy disabled. To enable it, use `pk;m <member> autoproxy on`.");
|
||||
|
||||
// Moved the IsLatchExpired() check to here, so that an expired latch and a latch without any previous messages throw different errors
|
||||
if (ctx.AutoproxyMode == AutoproxyMode.Latch && IsLatchExpired(ctx))
|
||||
if (settings.AutoproxyMode == AutoproxyMode.Latch && IsLatchExpired(ctx, settings))
|
||||
throw new ProxyService.ProxyChecksFailedException(
|
||||
"Latch-mode autoproxy has timed out. Please send a new message using proxy tags.");
|
||||
|
||||
@@ -99,16 +99,14 @@ public class ProxyMatcher
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsLatchExpired(MessageContext ctx)
|
||||
private bool IsLatchExpired(MessageContext ctx, AutoproxySettings settings)
|
||||
{
|
||||
if (ctx.LastMessage == null) return true;
|
||||
if (ctx.LatchTimeout == 0) return false;
|
||||
|
||||
var timeout = ctx.LatchTimeout.HasValue
|
||||
? Duration.FromSeconds(ctx.LatchTimeout.Value)
|
||||
: DefaultLatchExpiryTime;
|
||||
|
||||
var timestamp = DiscordUtils.SnowflakeToInstant(ctx.LastMessage.Value);
|
||||
return _clock.GetCurrentInstant() - timestamp > timeout;
|
||||
return _clock.GetCurrentInstant() - settings.LastLatchTimestamp > timeout;
|
||||
}
|
||||
}
|
@@ -32,10 +32,11 @@ public class ProxyService
|
||||
private readonly ModelRepository _repo;
|
||||
private readonly DiscordApiClient _rest;
|
||||
private readonly WebhookExecutorService _webhookExecutor;
|
||||
private readonly NodaTime.IClock _clock;
|
||||
|
||||
public ProxyService(LogChannelService logChannel, ILogger logger, WebhookExecutorService webhookExecutor,
|
||||
DispatchService dispatch, IDatabase db, ProxyMatcher matcher, IMetrics metrics, ModelRepository repo,
|
||||
IDiscordCache cache, DiscordApiClient rest, LastMessageCacheService lastMessage)
|
||||
NodaTime.IClock clock, IDiscordCache cache, DiscordApiClient rest, LastMessageCacheService lastMessage)
|
||||
{
|
||||
_logChannel = logChannel;
|
||||
_webhookExecutor = webhookExecutor;
|
||||
@@ -47,6 +48,7 @@ public class ProxyService
|
||||
_cache = cache;
|
||||
_lastMessage = lastMessage;
|
||||
_rest = rest;
|
||||
_clock = clock;
|
||||
_logger = logger.ForContext<ProxyService>();
|
||||
}
|
||||
|
||||
@@ -56,6 +58,17 @@ public class ProxyService
|
||||
if (!ShouldProxy(channel, message, ctx))
|
||||
return false;
|
||||
|
||||
var autoproxySettings = await _repo.GetAutoproxySettings(ctx.SystemId.Value, guild.Id, null);
|
||||
|
||||
if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message))
|
||||
{
|
||||
// "unlatch"
|
||||
await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() {
|
||||
AutoproxyMember = null
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var rootChannel = await _cache.GetRootChannel(message.ChannelId);
|
||||
|
||||
List<ProxyMember> members;
|
||||
@@ -63,7 +76,7 @@ public class ProxyService
|
||||
using (_metrics.Measure.Timer.Time(BotMetrics.ProxyMembersQueryTime))
|
||||
members = (await _repo.GetProxyMembers(message.Author.Id, message.GuildId!.Value)).ToList();
|
||||
|
||||
if (!_matcher.TryMatch(ctx, members, out var match, message.Content, message.Attachments.Length > 0,
|
||||
if (!_matcher.TryMatch(ctx, autoproxySettings, members, out var match, message.Content, message.Attachments.Length > 0,
|
||||
allowAutoproxy)) return false;
|
||||
|
||||
// this is hopefully temporary, so not putting it into a separate method
|
||||
@@ -84,7 +97,7 @@ public class ProxyService
|
||||
var allowEmbeds = senderPermissions.HasFlag(PermissionSet.EmbedLinks);
|
||||
|
||||
// Everything's in order, we can execute the proxy!
|
||||
await ExecuteProxy(message, ctx, match, allowEveryone, allowEmbeds);
|
||||
await ExecuteProxy(message, ctx, autoproxySettings, match, allowEveryone, allowEmbeds);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -129,7 +142,7 @@ public class ProxyService
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task ExecuteProxy(Message trigger, MessageContext ctx,
|
||||
private async Task ExecuteProxy(Message trigger, MessageContext ctx, AutoproxySettings autoproxySettings,
|
||||
ProxyMatch match, bool allowEveryone, bool allowEmbeds)
|
||||
{
|
||||
// Create reply embed
|
||||
@@ -171,7 +184,7 @@ public class ProxyService
|
||||
Stickers = trigger.StickerItems,
|
||||
AllowEveryone = allowEveryone
|
||||
});
|
||||
await HandleProxyExecutedActions(ctx, trigger, proxyMessage, match);
|
||||
await HandleProxyExecutedActions(ctx, autoproxySettings, trigger, proxyMessage, match);
|
||||
}
|
||||
|
||||
private async Task<(string?, string?)> FetchReferencedMessageAuthorInfo(Message trigger, Message referenced)
|
||||
@@ -290,7 +303,11 @@ public class ProxyService
|
||||
private string FixSameNameInner(string name)
|
||||
=> $"{name}\u17b5";
|
||||
|
||||
private async Task HandleProxyExecutedActions(MessageContext ctx, Message triggerMessage, Message proxyMessage, ProxyMatch match)
|
||||
public static bool IsUnlatch(Message message)
|
||||
=> message.Content.StartsWith(@"\\") || message.Content.StartsWith("\\\u200b\\");
|
||||
|
||||
private async Task HandleProxyExecutedActions(MessageContext ctx, AutoproxySettings autoproxySettings,
|
||||
Message triggerMessage, Message proxyMessage, ProxyMatch match)
|
||||
{
|
||||
var sentMessage = new PKMessage
|
||||
{
|
||||
@@ -308,6 +325,14 @@ public class ProxyService
|
||||
Task LogMessageToChannel() =>
|
||||
_logChannel.LogMessage(ctx, sentMessage, triggerMessage, proxyMessage).AsTask();
|
||||
|
||||
Task SaveLatchAutoproxy() => autoproxySettings.AutoproxyMode == AutoproxyMode.Latch
|
||||
? _repo.UpdateAutoproxy(ctx.SystemId.Value, triggerMessage.GuildId, null, new()
|
||||
{
|
||||
AutoproxyMember = match.Member.Id,
|
||||
LastLatchTimestamp = _clock.GetCurrentInstant(),
|
||||
})
|
||||
: Task.CompletedTask;
|
||||
|
||||
Task DispatchWebhook() => _dispatch.Dispatch(ctx.SystemId.Value, sentMessage);
|
||||
|
||||
async Task DeleteProxyTriggerMessage()
|
||||
@@ -333,6 +358,7 @@ public class ProxyService
|
||||
DeleteProxyTriggerMessage(),
|
||||
SaveMessageInDatabase(),
|
||||
LogMessageToChannel(),
|
||||
SaveLatchAutoproxy(),
|
||||
DispatchWebhook()
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user