Add command prefix configuration

This commit is contained in:
Ske 2020-08-25 19:32:19 +02:00
parent 87619a728e
commit 2206185d55
3 changed files with 38 additions and 17 deletions

View File

@ -2,7 +2,14 @@ namespace PluralKit.Bot
{ {
public class BotConfig public class BotConfig
{ {
public static readonly string[] DefaultPrefixes = {"pk;", "pk!"};
public string Token { get; set; } public string Token { get; set; }
public ulong? ClientId { get; set; } public ulong? ClientId { get; set; }
// ASP.NET configuration merges arrays with defaults, so we leave this field nullable
// and fall back to the separate default array at the use site :)
// This does bind [] as null (therefore default) instead of an empty array, but I can live w/ that.
public string[] Prefixes { get; set; }
} }
} }

View File

@ -23,11 +23,11 @@ namespace PluralKit.Bot
private readonly ProxyService _proxy; private readonly ProxyService _proxy;
private readonly ILifetimeScope _services; private readonly ILifetimeScope _services;
private readonly IDatabase _db; private readonly IDatabase _db;
private readonly IDataStore _data; private readonly BotConfig _config;
public MessageCreated(LastMessageCacheService lastMessageCache, LoggerCleanService loggerClean, public MessageCreated(LastMessageCacheService lastMessageCache, LoggerCleanService loggerClean,
IMetrics metrics, ProxyService proxy, DiscordShardedClient client, IMetrics metrics, ProxyService proxy, DiscordShardedClient client,
CommandTree tree, ILifetimeScope services, IDatabase db, IDataStore data) CommandTree tree, ILifetimeScope services, IDatabase db, BotConfig config)
{ {
_lastMessageCache = lastMessageCache; _lastMessageCache = lastMessageCache;
_loggerClean = loggerClean; _loggerClean = loggerClean;
@ -37,7 +37,7 @@ namespace PluralKit.Bot
_tree = tree; _tree = tree;
_services = services; _services = services;
_db = db; _db = db;
_data = data; _config = config;
} }
public DiscordChannel ErrorChannelFor(MessageCreateEventArgs evt) => evt.Channel; public DiscordChannel ErrorChannelFor(MessageCreateEventArgs evt) => evt.Channel;
@ -87,26 +87,19 @@ namespace PluralKit.Bot
var content = evt.Message.Content; var content = evt.Message.Content;
if (content == null) return false; if (content == null) return false;
var argPos = -1; // Check for command prefix
// Check if message starts with the command prefix if (!HasCommandPrefix(content, out var cmdStart))
if (content.StartsWith("pk;", StringComparison.InvariantCultureIgnoreCase)) argPos = 3; return false;
else if (content.StartsWith("pk!", StringComparison.InvariantCultureIgnoreCase)) argPos = 3;
else if (DiscordUtils.HasMentionPrefix(content, ref argPos, out var id)) // Set argPos to the proper value
if (id != _client.CurrentUser.Id) // But undo it if it's someone else's ping
argPos = -1;
// If we didn't find a prefix, give up handling commands // Trim leading whitespace from command without actually modifying the string
if (argPos == -1) return false;
// Trim leading whitespace from command without actually modifying the wring
// This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string // This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string
var trimStartLengthDiff = content.Substring(argPos).Length - content.Substring(argPos).TrimStart().Length; var trimStartLengthDiff = content.Substring(cmdStart).Length - content.Substring(cmdStart).TrimStart().Length;
argPos += trimStartLengthDiff; cmdStart += trimStartLengthDiff;
try try
{ {
var system = ctx.SystemId != null ? await _db.Execute(c => c.QuerySystem(ctx.SystemId.Value)) : null; var system = ctx.SystemId != null ? await _db.Execute(c => c.QuerySystem(ctx.SystemId.Value)) : null;
await _tree.ExecuteCommand(new Context(_services, evt.Client, evt.Message, argPos, system, ctx)); await _tree.ExecuteCommand(new Context(_services, evt.Client, evt.Message, cmdStart, system, ctx));
} }
catch (PKError) catch (PKError)
{ {
@ -117,6 +110,26 @@ namespace PluralKit.Bot
return true; return true;
} }
private bool HasCommandPrefix(string message, out int argPos)
{
// First, try prefixes defined in the config
var prefixes = _config.Prefixes ?? BotConfig.DefaultPrefixes;
foreach (var prefix in prefixes)
{
if (!message.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase)) continue;
argPos = prefix.Length;
return true;
}
// Then, check mention prefix (must be the bot user, ofc)
argPos = -1;
if (DiscordUtils.HasMentionPrefix(message, ref argPos, out var id))
return id == _client.CurrentUser.Id;
return false;
}
private async ValueTask<bool> TryHandleProxy(MessageCreateEventArgs evt, MessageContext ctx) private async ValueTask<bool> TryHandleProxy(MessageCreateEventArgs evt, MessageContext ctx)
{ {
try try

View File

@ -17,6 +17,7 @@ The configuration file needs to be placed in the bot's working directory (usuall
The configuration file is in JSON format (albeit with a `.conf` extension). The following keys are available (using `.` to indicate a nested object level), bolded key names are required: The configuration file is in JSON format (albeit with a `.conf` extension). The following keys are available (using `.` to indicate a nested object level), bolded key names are required:
* **`PluralKit.Bot.Token`**: the Discord bot token to connect with * **`PluralKit.Bot.Token`**: the Discord bot token to connect with
* **`PluralKit.Database`**: the URI of the database to connect to (in [ADO.NET Npgsql format](https://www.connectionstrings.com/npgsql/)) * **`PluralKit.Database`**: the URI of the database to connect to (in [ADO.NET Npgsql format](https://www.connectionstrings.com/npgsql/))
* `PluralKit.Bot.Prefixes`: an array of command prefixes to use (default `["pk;", "pk!"]`).
* `PluralKit.Bot.ClientId` *(optional)*: the ID of the bot's user account, used when generating invite links through `pk;invite`. It's automatically determined if not present, but overriding it may be useful for private instances that still want a public invite link. * `PluralKit.Bot.ClientId` *(optional)*: the ID of the bot's user account, used when generating invite links through `pk;invite`. It's automatically determined if not present, but overriding it may be useful for private instances that still want a public invite link.
* `PluralKit.SentryUrl` *(optional)*: the [Sentry](https://sentry.io/welcome/) client key/DSN to report runtime errors to. If absent, disables Sentry integration. * `PluralKit.SentryUrl` *(optional)*: the [Sentry](https://sentry.io/welcome/) client key/DSN to report runtime errors to. If absent, disables Sentry integration.
* `PluralKit.InfluxUrl` *(optional)*: the URL to an [InfluxDB](https://www.influxdata.com/products/influxdb-overview/) server to report aggregate statistics to. An example of these stats can be seen on [the public stats page](https://stats.pluralkit.me). * `PluralKit.InfluxUrl` *(optional)*: the URL to an [InfluxDB](https://www.influxdata.com/products/influxdb-overview/) server to report aggregate statistics to. An example of these stats can be seen on [the public stats page](https://stats.pluralkit.me).