summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2025-04-25 12:18:00 +0200
committerTor Andersson <tor@ccxvii.net>2025-04-25 17:56:43 +0200
commitfc3501382c2aa3ef5b692f4f55c2616f9cade3f5 (patch)
treea047bb94f8f1854c621fa0fba5ed62c8e0d0be14
parented2361980b455d1825d811670f329cbcf5624927 (diff)
downloadserver-fc3501382c2aa3ef5b692f4f55c2616f9cade3f5.tar.gz
Move toolbox scripts to a "bin" directory.
Add a super "rtt" command to run the scripts.
-rwxr-xr-xbin/rtt31
-rwxr-xr-x[-rw-r--r--]bin/rtt-archive-backup (renamed from tools/archive.sql)9
-rwxr-xr-x[-rw-r--r--]bin/rtt-archive-prune (renamed from tools/purge.sql)5
-rwxr-xr-x[-rw-r--r--]bin/rtt-archive-restore (renamed from tools/unarchive.sh)2
-rwxr-xr-xbin/rtt-backup4
-rwxr-xr-x[-rw-r--r--]bin/rtt-export (renamed from tools/export-game.sh)3
-rwxr-xr-xbin/rtt-foreach17
-rwxr-xr-xbin/rtt-fuzz (renamed from tools/fuzz.sh)4
-rwxr-xr-xbin/rtt-help34
-rwxr-xr-xbin/rtt-import (renamed from tools/import-game.js)2
-rwxr-xr-xbin/rtt-init13
-rwxr-xr-xbin/rtt-patch (renamed from tools/patchgame.js)6
-rwxr-xr-x[-rw-r--r--]bin/rtt-run (renamed from tools/run.sh)4
-rwxr-xr-xbin/rtt-show-chat7
-rwxr-xr-x[-rw-r--r--]bin/rtt-show-game (renamed from tools/showgame.sh)2
-rwxr-xr-xbin/rtt-show-replay7
-rwxr-xr-x[-rw-r--r--]bin/rtt-tm-unban-tick (renamed from tools/lift-bans.sh)2
-rwxr-xr-x[-rw-r--r--]bin/rtt-undo (renamed from tools/undo.sh)4
-rwxr-xr-x[-rw-r--r--]bin/rtt-update-covers (renamed from tools/gencovers.sh)12
-rwxr-xr-x[-rw-r--r--]bin/rtt-update-elo (renamed from tools/elo.js)2
-rw-r--r--docs/index.md3
-rw-r--r--docs/server/install.md1
-rw-r--r--docs/server/production.md4
-rw-r--r--docs/server/toolbox.md52
-rw-r--r--package.json1
-rw-r--r--[-rwxr-xr-x]tools/fuzz.js (renamed from tools/rtt-fuzz.js)0
-rwxr-xr-x[-rw-r--r--]tools/new-layout.js2
-rw-r--r--tools/readgame.sh10
-rw-r--r--tools/showreplay.sh2
-rw-r--r--tools/writegame.sh7
30 files changed, 213 insertions, 39 deletions
diff --git a/bin/rtt b/bin/rtt
new file mode 100755
index 0000000..c6b9edc
--- /dev/null
+++ b/bin/rtt
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+cmd=$1
+shift
+
+bindir=$(dirname $(readlink -f $0))
+
+if [ ! -n "$cmd" ]
+then
+ cmd=help
+fi
+
+if [ ! -f ./server.js ]
+then
+ echo "rtt: command must run in the top-level server directory!"
+ exit 1
+fi
+
+if [ ! -f $bindir/rtt-$cmd ]
+then
+ echo "rtt: '$cmd' is not an rtt command"
+ exit 1
+fi
+
+if [ ! -f ./db -a "$cmd" != init -a "$cmd" != "help" ]
+then
+ echo "rtt: the database does not exist!"
+ exit 1
+fi
+
+exec $bindir/rtt-$cmd "$@"
diff --git a/tools/archive.sql b/bin/rtt-archive-backup
index e8b5458..f1b63e5 100644..100755
--- a/tools/archive.sql
+++ b/bin/rtt-archive-backup
@@ -1,10 +1,13 @@
--- Make a copy of finished games in a separate archive database.
+#!/bin/bash
+sqlite3 <<EOF
-pragma busy_timeout=10000;
+-- Make a copy of finished games in a separate archive database.
attach database 'db' as live;
attach database 'archive.db' as archive;
+pragma live.busy_timeout=10000;
+
-- List finished (and rated) games in live that are not in archive.
create temporary view candidates as
select
@@ -99,3 +102,5 @@ insert into archive.games (game_id, title_id, scenario, options, player_count, c
from candidates join live.games using(game_id);
commit;
+
+EOF
diff --git a/tools/purge.sql b/bin/rtt-archive-prune
index 2a95f01..fff7f23 100644..100755
--- a/tools/purge.sql
+++ b/bin/rtt-archive-prune
@@ -1,3 +1,6 @@
+#!/bin/bash
+sqlite3 <<EOF
+
-- Prune game snapshot and game state data to save database space.
attach database 'db' as live;
@@ -33,3 +36,5 @@ delete from live.game_snap where game_id in (select game_id from prune_snap_list
select 'PURGE ALL FROM ' || count(1) from prune_all_list;
update live.games set status = 3 where game_id in (select game_id from prune_all_list);
+
+EOF
diff --git a/tools/unarchive.sh b/bin/rtt-archive-restore
index 6adb300..dc4d59e 100644..100755
--- a/tools/unarchive.sh
+++ b/bin/rtt-archive-restore
@@ -3,7 +3,7 @@
if [ -z "$1" ]
then
- echo 'usage: bash tools/unarchive.sh <gameid>'
+ echo "usage: rtt-archive-restore GAME"
exit 1
fi
diff --git a/bin/rtt-backup b/bin/rtt-backup
new file mode 100755
index 0000000..40a0efc
--- /dev/null
+++ b/bin/rtt-backup
@@ -0,0 +1,4 @@
+#!/bin/bash
+FILE=$(date +backup-%Y%m%d-%H%M.db)
+echo $FILE
+sqlite3 db "vacuum into '$FILE'"
diff --git a/tools/export-game.sh b/bin/rtt-export
index 19cd4e7..b82950c 100644..100755
--- a/tools/export-game.sh
+++ b/bin/rtt-export
@@ -3,6 +3,5 @@ if [ -n "$1" ]
then
sqlite3 db "select export from game_export_view where game_id=$1"
else
- echo "usage: bash tools/export-game.sh GAME > game.json"
+ echo "usage: rtt-export GAME > game.json"
fi
-
diff --git a/bin/rtt-foreach b/bin/rtt-foreach
new file mode 100755
index 0000000..22feb77
--- /dev/null
+++ b/bin/rtt-foreach
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+if [ -z "$1" ]
+then
+ echo "usage: rtt-foreach <command>"
+ exit 1
+fi
+
+for M in $(sqlite3 db "select title_id from titles")
+do
+ echo "Entering 'public/$M'"
+ if pushd public/$M >/dev/null
+ then
+ "$@"
+ popd >/dev/null
+ fi
+done
diff --git a/tools/fuzz.sh b/bin/rtt-fuzz
index fd2391b..d7f2aef 100755
--- a/tools/fuzz.sh
+++ b/bin/rtt-fuzz
@@ -5,12 +5,12 @@ shift
if [ ! -f ./public/$TITLE/rules.js ]
then
- echo usage: bash tools/fuzz.sh title_id
+ echo usage: rtt-fuzz TITLE
exit 1
fi
mkdir -p fuzzer/corpus-$TITLE
RULES=../public/$TITLE/rules.js \
- npx jazzer tools/rtt-fuzz.js --sync fuzzer/corpus-$TITLE "$@" -- -exact_artifact_path=/dev/null | \
+ npx jazzer tools/fuzz.js --sync fuzzer/corpus-$TITLE "$@" -- -exact_artifact_path=/dev/null | \
tee fuzzer/log-$TITLE.txt
diff --git a/bin/rtt-help b/bin/rtt-help
new file mode 100755
index 0000000..5f6815c
--- /dev/null
+++ b/bin/rtt-help
@@ -0,0 +1,34 @@
+#!/bin/bash
+cat <<EOF
+usage: rtt <subcommand> [ arguments... ]
+
+database management
+ init -- create database
+ run -- run server
+ backup -- backup database
+
+game management
+ export -- export game
+ import -- import game
+ patch -- patch game state (using replay)
+ undo -- rewind game state (using replay)
+
+module development
+ foreach -- run a command for each module
+ fuzz -- fuzz test a module
+
+game debugging
+ show-chat -- show game chat (for moderation)
+ show-game -- show game state object
+ show-replay -- show game replay log
+
+miscellaneous tools
+ update-covers -- generate cover thumbnails
+ update-elo -- recalculate Elo ratings
+
+archive database
+ archive-backup -- backup replay data into archive
+ archive-prune -- prune replay data from live database
+ archive-restore -- restore replay data from archive
+
+EOF
diff --git a/tools/import-game.js b/bin/rtt-import
index 4380252..2e4295b 100755
--- a/tools/import-game.js
+++ b/bin/rtt-import
@@ -17,7 +17,7 @@ for (let i = 2; i < process.argv.length; ++i) {
}
if (input.length < 1) {
- console.error("usage: node tools/import-game.js [title_id=value] [notice=value] game.json")
+ console.error("usage: rtt-import [title_id=value] [notice=value] game-dump.json")
process.exit(1)
}
diff --git a/bin/rtt-init b/bin/rtt-init
new file mode 100755
index 0000000..02b9e9b
--- /dev/null
+++ b/bin/rtt-init
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+echo installing node packages
+npm install -s
+
+echo creating database
+sqlite3 db < schema.sql
+
+for M in public/*/title.sql
+do
+ echo registering module $(basename $(dirname $M))
+ sqlite3 db < $M
+done
diff --git a/tools/patchgame.js b/bin/rtt-patch
index de8721e..19e9874 100755
--- a/tools/patchgame.js
+++ b/bin/rtt-patch
@@ -272,9 +272,9 @@ function patch_title(title_id, options) {
}
if (process.argv.length < 3) {
- process.stderr.write("usage: ./tools/patchgame.js <game_id> '{options}'\n")
- process.stderr.write(" or: ./tools/patchgame.js <title_id> '{options}'\n")
- process.stderr.write(" or: ./tools/patchgame.js all '{options}'\n")
+ process.stderr.write("usage: rtt-patch <game_id> '{options}'\n")
+ process.stderr.write(" or: rtt-patch <title_id> '{options}'\n")
+ process.stderr.write(" or: rtt-patch all '{options}'\n")
process.stderr.write('options: { "validate_actions":true, "delete_invalid":false, "save_snaps":true, "delete_undo":false }\n')
process.exit(1)
}
diff --git a/tools/run.sh b/bin/rtt-run
index efadfe7..6873e2f 100644..100755
--- a/tools/run.sh
+++ b/bin/rtt-run
@@ -2,6 +2,8 @@
while true
do
nodemon --exitcrash server.js
- echo Restarting soon...
+ echo
+ echo "Restarting soon!"
+ echo "Hit Ctl-C to exit."
sleep 3
done
diff --git a/bin/rtt-show-chat b/bin/rtt-show-chat
new file mode 100755
index 0000000..7d71718
--- /dev/null
+++ b/bin/rtt-show-chat
@@ -0,0 +1,7 @@
+#!/bin/bash
+if [ -n "$1" ]
+then
+ sqlite3 db ".mode column --wrap 40 -ww" "select time,name,message from game_chat_view where game_id=$1" | less -FX
+else
+ echo "usage: rtt-show-chat GAME"
+fi
diff --git a/tools/showgame.sh b/bin/rtt-show-game
index f45be78..ece9e49 100644..100755
--- a/tools/showgame.sh
+++ b/bin/rtt-show-game
@@ -3,5 +3,5 @@ if [ -n "$1" ]
then
sqlite3 db "select json_remove(json_remove(state, '$.undo'), '$.log') from game_state where game_id = $1"
else
- echo "usage: bash tools/showgame.sh GAME"
+ echo "usage: rtt-show-state GAME"
fi
diff --git a/bin/rtt-show-replay b/bin/rtt-show-replay
new file mode 100755
index 0000000..4bbbdce
--- /dev/null
+++ b/bin/rtt-show-replay
@@ -0,0 +1,7 @@
+#!/bin/bash
+if [ -n "$1" ]
+then
+ sqlite3 db "select replay_id, role, action, arguments from game_replay where game_id=$1"
+else
+ echo "usage: rtt-show-replay GAME"
+fi
diff --git a/tools/lift-bans.sh b/bin/rtt-tm-unban-tick
index e76f621..7294e81 100644..100755
--- a/tools/lift-bans.sh
+++ b/bin/rtt-tm-unban-tick
@@ -1,5 +1,7 @@
#!/bin/bash
+# Run this script in a cron job to lift tournament bans periodically.
+
sqlite3 db <<EOF
begin immediate;
diff --git a/tools/undo.sh b/bin/rtt-undo
index b75182f..2f69eed 100644..100755
--- a/tools/undo.sh
+++ b/bin/rtt-undo
@@ -9,7 +9,7 @@ then
echo Game has $COUNT actions.
fi
sqlite3 db "delete from game_replay where game_id=$1 and replay_id>=$COUNT"
- node tools/patchgame.js $1 '{"validate_actions":false}'
+ ./bin/rtt-patch $1 '{"validate_actions":false}'
else
- echo "usage: bash tools/undo.sh GAME"
+ echo "usage: rtt-undo GAME"
fi
diff --git a/tools/gencovers.sh b/bin/rtt-update-covers
index 454d69b..0eae8e7 100644..100755
--- a/tools/gencovers.sh
+++ b/bin/rtt-update-covers
@@ -1,6 +1,16 @@
+#!/bin/bash
+
+if command -v convert && command -v pngtopnm && command -v cjpeg
+then
+ echo "Generating cover images and thumbnails!"
+else
+ echo error: cannot find imagemagick, netpbm, and/or cjpeg
+ exit 1
+fi
+
for F in public/*/cover.jpg public/*/cover.png
do
- echo Processing: $F
+ echo processing $F
B=$(echo $F | sed s/.jpg// | sed s/.png//)
D=$(dirname $F)
diff --git a/tools/elo.js b/bin/rtt-update-elo
index f6064f1..538964a 100644..100755
--- a/tools/elo.js
+++ b/bin/rtt-update-elo
@@ -1,5 +1,7 @@
#!/usr/bin/env -S node
+// Recompute Elo ratings from scratch!
+
const sqlite3 = require("better-sqlite3")
const db = new sqlite3("db")
diff --git a/docs/index.md b/docs/index.md
index 96c9a7b..254cc74 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -13,6 +13,7 @@ server instance and how to create new modules.
* [Installing the server](/docs/server/install)
* [Running a public server](/docs/server/production)
+* [Toolbox](/docs/server/toolbox)
## System overview
@@ -22,7 +23,7 @@ server instance and how to create new modules.
## Module implementation
-* [Step by step guide](/docs/module/guide)
+* [General tips and where to start](/docs/module/guide)
* [Rules framework](/docs/module/rules)
* [Script syntax](/docs/module/script)
* [Utility library](/docs/module/library)
diff --git a/docs/server/install.md b/docs/server/install.md
index 86359bc..4e48440 100644
--- a/docs/server/install.md
+++ b/docs/server/install.md
@@ -43,4 +43,3 @@ Register it in the database:
Open the browser to http://localhost:8080/ and create an account.
The first account created will have administrator privileges.
-
diff --git a/docs/server/production.md b/docs/server/production.md
index 9882a5a..4344630 100644
--- a/docs/server/production.md
+++ b/docs/server/production.md
@@ -91,11 +91,11 @@ Run the archive and purge scripts as part of the backup cron job.
Copy game state data of finished games into archive database.
- sqlite3 tools/archive.sql
+ sqlite3 < tools/archive.sql
Delete game state data of finished games over a certain age.
- sqlite3 tools/purge.sql
+ sqlite3 < tools/purge.sql
Restore archived game state.
diff --git a/docs/server/toolbox.md b/docs/server/toolbox.md
new file mode 100644
index 0000000..ebbabaf
--- /dev/null
+++ b/docs/server/toolbox.md
@@ -0,0 +1,52 @@
+# Toolbox
+
+There are a few programs that help maintain the database and are useful to
+develop and debug modules.
+
+## Setup
+
+These programs can be invoked from the command line by running the "rtt"
+command that is found in the "bin" directory.
+I suggest creating a symlink to the "rtt" command somewhere in your PATH.
+
+ ln -s ~/server/bin/rtt ~/.local/bin
+
+Alternatively, you can edit your .profile to add the server bin directory to your PATH.
+
+ PATH=$PATH:$HOME/server/bin
+
+## Commands
+
+database management
+
+ init -- create database
+ run -- run server
+ backup -- backup database
+
+game management
+
+ export -- export game
+ import -- import game
+ patch -- patch game state (using replay)
+ undo -- rewind game state (using replay)
+
+module development
+
+ foreach -- run a command for each module
+ fuzz -- fuzz test a module
+
+game debugging
+
+ show-chat -- show game chat (for moderation)
+ show-game -- show game state object
+ show-replay -- show game replay log
+
+miscellaneous tools
+
+ update-covers -- generate cover thumbnails
+ update-elo -- recalculate Elo ratings
+
+## Miscellaneous
+
+The "tools" directory holds various useful bits and bobs.
+
diff --git a/package.json b/package.json
index 98e6b06..2ac0ce2 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"express": "^4.18.2",
"marked": "^15.0.10",
"nodemailer": "^6.9.9",
+ "nodemon": "^3.1.10",
"pug": "^3.0.2",
"utf-8-validate": "^6.0.3",
"ws": "^8.16.0"
diff --git a/tools/rtt-fuzz.js b/tools/fuzz.js
index 0690697..0690697 100755..100644
--- a/tools/rtt-fuzz.js
+++ b/tools/fuzz.js
diff --git a/tools/new-layout.js b/tools/new-layout.js
index ce0bb6e..238a257 100644..100755
--- a/tools/new-layout.js
+++ b/tools/new-layout.js
@@ -1,3 +1,5 @@
+#!/usr/bin/env -S node
+
const print = console.log
if (process.argv.length < 4) {
diff --git a/tools/readgame.sh b/tools/readgame.sh
deleted file mode 100644
index 4a8fdbd..0000000
--- a/tools/readgame.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-if [ -n "$1" -a -n "$2" ]
-then
- sqlite3 db "select writefile('$2',state) from game_state where game_id = $1"
-elif [ -n "$1" ]
-then
- sqlite3 db "select state from game_state where game_id = $1"
-else
- echo "usage: bash tools/readgame.sh GAME [ state.json ]"
-fi
diff --git a/tools/showreplay.sh b/tools/showreplay.sh
deleted file mode 100644
index 413e12f..0000000
--- a/tools/showreplay.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-sqlite3 db "select * from game_replay where game_id=$1"
diff --git a/tools/writegame.sh b/tools/writegame.sh
deleted file mode 100644
index ea0f599..0000000
--- a/tools/writegame.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-if [ -n "$1" -a -f "$2" ]
-then
- sqlite3 db "update game_state set state=readfile('$2') where game_id = $1"
-else
- echo "usage: bash tools/writegame.sh GAME state.json"
-fi