From 8e5fb6520b9869b8384abbddfe94b435a8ec8bed Mon Sep 17 00:00:00 2001 From: spiral Date: Fri, 20 Nov 2020 19:44:15 -0500 Subject: [PATCH] Add configurable autoproxy latch timeout --- PluralKit.Bot/Commands/Autoproxy.cs | 36 ++++++++++++++++++- PluralKit.Bot/Proxy/ProxyMatcher.cs | 16 +++++---- .../Database/Functions/MessageContext.cs | 1 + .../Database/Functions/functions.sql | 6 ++-- PluralKit.Core/Database/Migrations/12.sql | 2 ++ PluralKit.Core/Models/PKSystem.cs | 1 + PluralKit.Core/Models/Patch/SystemPatch.cs | 4 ++- docs/content/user-guide.md | 14 ++++++++ 8 files changed, 70 insertions(+), 10 deletions(-) diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index 475e0647..c548c82d 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -25,12 +25,17 @@ namespace PluralKit.Bot ctx.CheckSystem(); // check account first - // this is ugly, but someone may want to disable autoproxy in DMs (since this is global) + // this is ugly, but these global options should be available in DMs if (ctx.Match("account", "ac")) { await AutoproxyAccount(ctx); return; } + else if (ctx.Match("timeout", "tm")) + { + await AutoproxyTimeout(ctx); + return; + } ctx.CheckGuildContext(); @@ -138,6 +143,35 @@ namespace PluralKit.Bot return eb.Build(); } + private async Task AutoproxyTimeout(Context ctx) + { + if (!ctx.HasNext()) + { + if (ctx.System.LatchTimeout == -1) + await ctx.Reply($"You do not have a custom autoproxy timeout duration set. The default latch timeout duration is {PluralKit.Bot.ProxyMatcher.DefaultLatchExpiryTime} hour(s)."); + else if (ctx.System.LatchTimeout == 0) + await ctx.Reply("Latch timeout is currently **disabled** for your system. Latch mode autoproxy will never timeout."); + else + await ctx.Reply($"The current latch timeout duration for your system is {ctx.System.LatchTimeout} hour(s)."); + return; + } + + // todo: somehow parse a more human-friendly date format + int newTimeout; + if (ctx.Match("off", "stop", "cancel", "no", "disable", "remove")) newTimeout = 0; + else if (ctx.Match("reset", "default")) newTimeout = -1; + else if (!int.TryParse(ctx.RemainderOrNull(), out newTimeout)) throw new PKError("Duration must be an integer."); + + await _db.Execute(conn => _repo.UpdateSystem(conn, ctx.System.Id, new SystemPatch{LatchTimeout = newTimeout})); + + if (newTimeout == -1) + await ctx.Reply($"{Emojis.Success} Latch timeout reset to default ({PluralKit.Bot.ProxyMatcher.DefaultLatchExpiryTime} hours)."); + else if (newTimeout == 0) + await ctx.Reply($"{Emojis.Success} Latch timeout disabled. Latch mode autoproxy will never timeout."); + else + await ctx.Reply($"{Emojis.Success} Latch timeout set to {newTimeout} hours."); + } + private async Task AutoproxyAccount(Context ctx) { if (ctx.Match("enable", "on")) diff --git a/PluralKit.Bot/Proxy/ProxyMatcher.cs b/PluralKit.Bot/Proxy/ProxyMatcher.cs index 386b46dd..7e9aa0cf 100644 --- a/PluralKit.Bot/Proxy/ProxyMatcher.cs +++ b/PluralKit.Bot/Proxy/ProxyMatcher.cs @@ -10,7 +10,7 @@ namespace PluralKit.Bot public class ProxyMatcher { private static readonly char AutoproxyEscapeCharacter = '\\'; - private static readonly Duration LatchExpiryTime = Duration.FromHours(6); + public static readonly int DefaultLatchExpiryTime = 6; private readonly IClock _clock; private readonly ProxyTagParser _parser; @@ -56,7 +56,7 @@ namespace PluralKit.Bot AutoproxyMode.Front when ctx.LastSwitchMembers.Length > 0 => members.FirstOrDefault(m => m.Id == ctx.LastSwitchMembers[0]), - AutoproxyMode.Latch when ctx.LastMessageMember != null && !IsLatchExpired(ctx.LastMessage) => + AutoproxyMode.Latch when ctx.LastMessageMember != null && !IsLatchExpired(ctx) => members.FirstOrDefault(m => m.Id == ctx.LastMessageMember.Value), _ => null @@ -75,11 +75,15 @@ namespace PluralKit.Bot return true; } - private bool IsLatchExpired(ulong? messageId) + private bool IsLatchExpired(MessageContext ctx) { - if (messageId == null) return true; - var timestamp = DiscordUtils.SnowflakeToInstant(messageId.Value); - return _clock.GetCurrentInstant() - timestamp > LatchExpiryTime; + if (ctx.LastMessage == null) return true; + if (ctx.LatchTimeout == 0) return false; + + var timeout = Duration.FromHours(ctx.LatchTimeout == -1 ? DefaultLatchExpiryTime : ctx.LatchTimeout); + + var timestamp = DiscordUtils.SnowflakeToInstant(ctx.LastMessage.Value); + return _clock.GetCurrentInstant() - timestamp > timeout; } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Functions/MessageContext.cs b/PluralKit.Core/Database/Functions/MessageContext.cs index 428dfd1c..5d76890f 100644 --- a/PluralKit.Core/Database/Functions/MessageContext.cs +++ b/PluralKit.Core/Database/Functions/MessageContext.cs @@ -25,5 +25,6 @@ namespace PluralKit.Core public string? SystemTag { get; } public string? SystemAvatar { get; } public bool AllowAutoproxy { get; } + public int LatchTimeout { get; } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Functions/functions.sql b/PluralKit.Core/Database/Functions/functions.sql index a6f3d758..f959f447 100644 --- a/PluralKit.Core/Database/Functions/functions.sql +++ b/PluralKit.Core/Database/Functions/functions.sql @@ -15,7 +15,8 @@ last_switch_timestamp timestamp, system_tag text, system_avatar text, - allow_autoproxy bool + allow_autoproxy bool, + latch_timeout integer ) as $$ -- CTEs to query "static" (accessible only through args) data @@ -39,7 +40,8 @@ as $$ system_last_switch.timestamp as last_switch_timestamp, system.tag as system_tag, system.avatar_url as system_avatar, - system.account_autoproxy as allow_autoproxy + system.account_autoproxy as allow_autoproxy, + system.latch_timeout as latch_timeout -- We need a "from" clause, so we just use some bogus data that's always present -- This ensure we always have exactly one row going forward, so we can left join afterwards and still get data from (select 1) as _placeholder diff --git a/PluralKit.Core/Database/Migrations/12.sql b/PluralKit.Core/Database/Migrations/12.sql index 6cc63e80..c00d8e74 100644 --- a/PluralKit.Core/Database/Migrations/12.sql +++ b/PluralKit.Core/Database/Migrations/12.sql @@ -1,7 +1,9 @@ -- SCHEMA VERSION 12: -- -- Add disabling front/latch autoproxy per-member -- -- Add disabling autoproxy per-account -- +-- Add configurable latch timeout -- alter table members add column allow_autoproxy bool not null default true; alter table accounts add column allow_autoproxy bool not null default true; +alter table systems add column latch_timeout int not null default -1; update info set schema_version = 12; \ No newline at end of file diff --git a/PluralKit.Core/Models/PKSystem.cs b/PluralKit.Core/Models/PKSystem.cs index 9962e75f..462e04a4 100644 --- a/PluralKit.Core/Models/PKSystem.cs +++ b/PluralKit.Core/Models/PKSystem.cs @@ -18,6 +18,7 @@ namespace PluralKit.Core { public Instant Created { get; } public string UiTz { get; set; } public bool PingsEnabled { get; } + public int LatchTimeout { get; } public PrivacyLevel DescriptionPrivacy { get; } public PrivacyLevel MemberListPrivacy { get;} public PrivacyLevel FrontPrivacy { get; } diff --git a/PluralKit.Core/Models/Patch/SystemPatch.cs b/PluralKit.Core/Models/Patch/SystemPatch.cs index d574e8e2..76fdfbb1 100644 --- a/PluralKit.Core/Models/Patch/SystemPatch.cs +++ b/PluralKit.Core/Models/Patch/SystemPatch.cs @@ -15,6 +15,7 @@ namespace PluralKit.Core public Partial FrontPrivacy { get; set; } public Partial FrontHistoryPrivacy { get; set; } public Partial PingsEnabled { get; set; } + public Partial LatchTimeout { get; set; } public override UpdateQueryBuilder Apply(UpdateQueryBuilder b) => b .With("name", Name) @@ -28,6 +29,7 @@ namespace PluralKit.Core .With("group_list_privacy", GroupListPrivacy) .With("front_privacy", FrontPrivacy) .With("front_history_privacy", FrontHistoryPrivacy) - .With("pings_enabled", PingsEnabled); + .With("pings_enabled", PingsEnabled) + .With("latch_timeout", LatchTimeout); } } \ No newline at end of file diff --git a/docs/content/user-guide.md b/docs/content/user-guide.md index bdc0a138..f7d7240b 100644 --- a/docs/content/user-guide.md +++ b/docs/content/user-guide.md @@ -340,6 +340,20 @@ To enable latch-mode autoproxying for a given server, use the following command: pk;autoproxy latch +::: tip +By default, latch mode times out after 6 hours. It is possible to change this: + + pk;autoproxy timeout + +To reset the duration, use the following command: + + pk;autoproxy timeout reset + +To disable timeout (never timeout), use the following command: + + pk;autoproxy timeout disable +::: + #### Member mode This autoproxy mode will autoproxy for a specific selected member, irrelevant of past proxies or fronters.