chore: move app-commands script to rust

This commit is contained in:
alyssa 2025-10-15 21:15:54 +00:00
parent c0a5bc81a0
commit 83dd880374
13 changed files with 71 additions and 139 deletions

15
Cargo.lock generated
View file

@ -104,6 +104,20 @@ dependencies = [
"twilight-http", "twilight-http",
] ]
[[package]]
name = "app-commands"
version = "0.1.0"
dependencies = [
"anyhow",
"futures",
"libpk",
"tokio",
"tracing",
"twilight-http",
"twilight-model",
"twilight-util",
]
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.1" version = "1.7.1"
@ -4560,6 +4574,7 @@ version = "0.16.0"
source = "git+https://github.com/pluralkit/twilight?branch=pluralkit-7f08d95#054a2aa5d29fb46220af1cd5df568b73511cdb26" source = "git+https://github.com/pluralkit/twilight?branch=pluralkit-7f08d95#054a2aa5d29fb46220af1cd5df568b73511cdb26"
dependencies = [ dependencies = [
"twilight-model", "twilight-model",
"twilight-validate",
] ]
[[package]] [[package]]

View file

@ -27,7 +27,7 @@ axum = { git = "https://github.com/pluralkit/axum", branch = "v0.8.4-pluralkit"
twilight-gateway = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95" } twilight-gateway = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95" }
twilight-cache-inmemory = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", features = ["permission-calculator"] } twilight-cache-inmemory = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", features = ["permission-calculator"] }
twilight-util = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", features = ["permission-calculator"] } twilight-util = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", features = ["permission-calculator", "builder"] }
twilight-model = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95" } twilight-model = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95" }
twilight-http = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", default-features = false, features = ["rustls-aws_lc_rs", "rustls-native-roots"] } twilight-http = { git = "https://github.com/pluralkit/twilight", branch = "pluralkit-7f08d95", default-features = false, features = ["rustls-aws_lc_rs", "rustls-native-roots"] }

View file

@ -0,0 +1,14 @@
[package]
name = "app-commands"
version = "0.1.0"
edition = "2024"
[dependencies]
libpk = { path = "../libpk" }
anyhow = { workspace = true }
futures = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
twilight-http = { workspace = true }
twilight-model = { workspace = true }
twilight-util = { workspace = true }

View file

@ -0,0 +1,41 @@
use twilight_model::{
application::command::{Command, CommandType},
guild::IntegrationApplication,
};
use twilight_util::builder::command::CommandBuilder;
#[libpk::main]
async fn main() -> anyhow::Result<()> {
let discord = twilight_http::Client::builder()
.token(
libpk::config
.discord
.as_ref()
.expect("missing discord config")
.bot_token
.clone(),
)
.build();
let interaction = discord.interaction(twilight_model::id::Id::new(
libpk::config
.discord
.as_ref()
.expect("missing discord config")
.client_id
.clone()
.get(),
));
let commands = vec![
// message commands
// description must be empty string
CommandBuilder::new("\u{2753} Message info", "", CommandType::Message).build(),
CommandBuilder::new("\u{274c} Delete message", "", CommandType::Message).build(),
CommandBuilder::new("\u{1f514} Ping author", "", CommandType::Message).build(),
];
interaction.set_global_commands(&commands).await?;
Ok(())
}

View file

@ -1,4 +0,0 @@
/commands.json
*.pyc
__pycache__/

View file

@ -1,23 +0,0 @@
# PluralKit "application command" helpers
## Adding new commands
Edit the `COMMAND_LIST` global in `commands.py`, making sure that any
command names that are specified in that file match up with the
command names used in the bot code (which will generally be in the list
in `PluralKit.Bot/ApplicationCommandMeta/ApplicationCommandList.cs`).
TODO: add helpers for slash commands to this
## Dumping application command JSON
Run `python3 commands.py` to get a JSON dump of the available application
commands - this is in a format that can be sent to Discord as a `PUT` to
`/applications/{clientId}/commands`.
## Updating Discord's list of application commands
From the root of the repository (where your `pluralkit.conf` resides),
run `python3 ./scripts/app-commands/update.py`. This will **REPLACE**
any existing application commands that Discord knows about, with the
updated list.

View file

@ -1,10 +0,0 @@
from common import *
COMMAND_LIST = [
MessageCommand("\U00002753 Message info"),
MessageCommand("\U0000274c Delete message"),
MessageCommand("\U0001f514 Ping author"),
]
if __name__ == "__main__":
print(__import__('json').dumps(COMMAND_LIST))

View file

@ -1 +0,0 @@
from .types import MessageCommand

View file

@ -1,7 +0,0 @@
class MessageCommand(dict):
COMMAND_TYPE = 3
def __init__(self, name):
super().__init__()
self["type"] = self.__class__.COMMAND_TYPE
self["name"] = name

View file

@ -1,70 +0,0 @@
from common import *
from commands import COMMAND_LIST
import io
import os
import sys
import json
from pathlib import Path
from urllib import request
from urllib.error import URLError
DISCORD_API_BASE = "https://discord.com/api/v10"
def get_config():
data = {}
# prefer token from environment if present
envbase = ["PluralKit", "Bot"]
for var in ["Token", "ClientId"]:
for sep in [':', '__']:
envvar = sep.join(envbase + [var])
if envvar in os.environ:
data[var] = os.environ[envvar]
if "Token" in data and "ClientId" in data:
return data
# else fall back to config
cfg_path = Path(os.getcwd()) / "pluralkit.conf"
if cfg_path.exists():
cfg = {}
with open(str(cfg_path), 'r') as fh:
cfg = json.load(fh)
if 'PluralKit' in cfg and 'Bot' in cfg['PluralKit']:
return cfg['PluralKit']['Bot']
return None
def main():
config = get_config()
if config is None:
raise ArgumentError("config was not loaded")
if 'Token' not in config or 'ClientId' not in config:
raise ArgumentError("config is missing 'Token' or 'ClientId'")
data = json.dumps(COMMAND_LIST)
url = DISCORD_API_BASE + f"/applications/{config['ClientId']}/commands"
req = request.Request(url, method='PUT', data=data.encode('utf-8'))
req.add_header("Content-Type", "application/json")
req.add_header("Authorization", f"Bot {config['Token']}")
req.add_header("User-Agent", "PluralKit (app-commands updater; https://pluralkit.me)")
try:
with request.urlopen(req) as resp:
if resp.status == 200:
print("Update successful!")
return 0
except URLError as resp:
print(f"[!!!] Update not successful: status {resp.status}", file=sys.stderr)
print(f"[!!!] Response body below:\n", file=sys.stderr)
print(resp.read(), file=sys.stderr)
sys.stderr.flush()
return 1
if __name__ == "__main__":
sys.exit(main())

View file

@ -1,3 +0,0 @@
#!/bin/sh
docker-compose -f "$(dirname $0)/../docker-compose.yml" exec -T -u postgres db pg_dump postgres

View file

@ -1,15 +0,0 @@
#!/bin/sh
# Usage: rclone-db.sh <remote>:<path>
# eg. rclone-db.sh b2:pluralkit
FILENAME=pluralkit-$(date -u +"%Y-%m-%dT%H:%M:%S").sql.gz
echo Dumping database to /tmp/$FILENAME...
$(dirname $0)/dump-db.sh | gzip > /tmp/$FILENAME
echo Transferring to remote $1...
rclone -P copy /tmp/$FILENAME $1
echo Cleaning up...
rm /tmp/$FILENAME

View file

@ -1,5 +0,0 @@
#!/bin/sh
# Runs a local database in the background listening on port 5432, deleting itself once stopped
# Requires Docker. May need sudo if your user isn't in the `docker` group.
docker run --rm --detach --publish 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres:alpine