1 OTTER - ONLINE TABLE TOP ENVIRONMENT RENDERER
2 =============================================
4 Otter is an online "table simulator" intended to be suitable for board
7 It is accessed from a web browser running JavaScript. The server runs
8 on a convenationl Unix host. Currently, joining a game requires a
9 unix shell account on the server.
11 I expect it to be used with a concurrent voice chat.
13 The game server does not currently have a built-in text chat system.
14 The game organiser can use the game server to distribute (and update)
15 voice chat and info links.
17 Right now Otter is in an alpha state.
25 otter join-game unix:<user>::<game-name>
29 otter join-game unix:ijackson::test
32 See `otter --help` for further options, including setting your nick.
34 Currently when a new player joins a game (with the `otter` command),
35 all the other players must reload the page.
42 otter reset --reset-table local-users :test demo
43 /^^^^^^^^^^^ ^^^\ ^^^^'~ game spec
47 Here `local-users` refers to the file `local-users.table.spec` in the
48 Otter specs directory (`/volatile/Otter/specs` on chiark). The table
49 spec file handles access control (and some other global properties)
50 This particular file says that all local shell account users may join
53 `:test` is the game name. It starts with a colon, which means
54 implicitly `unix:<whoami>::test`. Other people have to name the game
55 with the full name, with all three colons in it.
57 `demo` refers to the file `demo.game.spec`. The "game spec" says what
58 shape table is and what pieces there are. This is a simple demo game.
59 There is also `penultima` which is a work-in-progress set of pieces
60 suitable for fairy chess etc.
62 See `otter --help` for some more options.
64 Currently, resetting a game (or otherwise adding or removing pieces)
65 will mean all the players will get errors until they reload the page.
71 If you want to use existing piece shapes that Otter already knows
72 about, you can do this by providing a `<something>.game.toml` file.
73 The format of these files is a TOML document representing a GameSpec
74 as found in `src/spec.rs` in the Otter source code.
76 todo: use rustdoc to provide this somewhere.
82 Otter uses SVGs. The sources for the SVGs are all in the otter source
83 tree, in the `library/` directory.
85 Each shape is listed in one of the `library/*.toml` files, in a
86 `files` entry. (Most of) the syntax and semantics of this file are
87 documented in the Rustdoc documentation for the module
88 `otter::shapelib_toml`. If you run `make -j8 shapelib` it will print
89 out a `file://` url for these docs.
91 You can preview the shapes, including any changes you make, without a
92 whole game server, by running `make -j8 shapelib`, and looking at
93 `templates/shapelib.html`. As above, this make rune will print the
94 `file://` url for you. (See BUILDING AND TESTING for information
95 about how to install the tools you will need.)
97 Some of these SVGs were scraped from Wikimedia. The scraper machinery
98 can perhaps be adapted to scrape SVGs from elsewhere.
100 You can also add your own SVGs in the library/edited/ directory.
101 If you do that, please make sure to include the actual source code.
102 If you copied or adapted an SVG from somewhere, provide details.
104 Contributions should be via git branch, eg a merge request on Salsa:
105 [https://salsa.debian.org/iwj/otter](https://salsa.debian.org/iwj/otter)
107 NB that shapes must come with a licence compatible with CC-BY-SA 4.0
108 or GNU AGPLv3+. See `LICENCE` for more information about copyright status.
114 You will need at least 6000 megabytes of disk space, or more, and a
115 good internet connection. Your computer will be compiling a lot of
118 These instructions have been tested on Debian buster.
126 sudo apt install build-essential cpio git curl \
127 pkg-config libssl-dev \
128 node-typescript inkscape bubblewrap \
132 2. Install Rust. This is most easily done with [rustup](https://rustup.rs)):
135 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
138 and then follow the instructions about your `PATH`. If this rune
139 alarms you, see below about Rust privsep.
141 3. Switch your Rust install to use Rust Nightly and add the WASM
145 rustup default nightly
146 rustup target add wasm32-unknown-unknown
149 Unfortunately, it is possible that the Rust nightly you find when
150 you run this is missing some pieces. The following is known to
151 work (with otter from the time of writing):
153 rustup default nightly-2021-01-26
156 4. Install the `usvg` SVG launderer, which we need for shape libraries
162 This will put it in `~/.cargo/bin`, which you presumably have on
163 your `PATH` (or the above `rustup` and `cargo` runes wouldn't work).
166 ** If you just want to edit and preview the shape libraries
167 (ie the piece shapes) you can stop here **
170 5. Install some more build tools:
173 cargo install bundle-sources
181 git clone https://salsa.debian.org/iwj/otter
183 make -j8 all bundled-sources
186 Or if you just want to edit the piece libraries:
191 And then open `./templates/shapelib.html` in your browser
200 target/debug/daemon-otter server-test.toml
203 The server does not daemonise, and the default config there makes it
204 quite verbose. So, in another shell:
208 --account server: --config server-test.toml --spec-dir=specs \
209 reset --reset-table test server::test demo
212 --account server: --config server-test.toml --spec-dir=specs \
213 join-game server::test
216 The URL printed can then be visited in a local browser.
219 Resetting/restoring things after tests, updating server, etc.
220 -------------------------------------------------------------
222 After the server is updated, you can just `^C` and restart it. Games
223 are constantly saved (although there is an up-to-1s lag on the most
224 frequently udpated game state).
226 If you want to clear out the server state, delete the files `[ag]-*`
227 and `accounts`. NB that you should do this with the server not
228 running, because the server has most of that information in memory and
229 will like to write it out again.
231 If you update Typescript (JS code) you will need to rerun `make` to
232 rebuild the JS output.
234 Apart from that, if you update JS or WASM code or Tera templates, you
235 do not need to restart the server - it will pick up changes
238 When testing, you do not need to `make bundled-sources` more than
239 once, at the beginning. So don't, because it's slow. But you
240 definitely should run it for every update if you make a deployment for
241 other people to use. Otherwise you might be running a privately
242 modified server without offering your users its source code. See
245 If you Do Something to the output from cargo, you should `rm stamp/*`,
246 since the `Makefile` won't notice, otherwise, that, the relevant cargo
247 rune(s) need to be re-run. Needlessly deleting all the stamp files
248 wastes only a handful of seconds (on my stupidly fast laptop).
251 Navigating the otter source code
252 --------------------------------
256 The main Rust source code. This is mixture of code used only or
257 mainly by the server and code used by the `otter` command line
258 utility; these aren't split up in a wholly principled way. In Rust
259 terms this is a "library crate".
263 Support executables, including in particular the command line
264 utility `otter` which is used to set up and join games.
268 The Otter server. This is a simple binary crare. Much
269 functionality belonging primarily, or only, to the server, is in
270 `src/`, simply because it was easier not to disentangle it.
271 Anything that needs Rocket (the web framework) is in `daemon/`.
275 Code shared by the host and the WebAssembly. Notably, the Z
276 coordinate handling, but also a a few other minor functions needed
277 by both client and server. To avoid duplicating them are written
278 once in Rust and compiled twice - once for the host and once for
279 WebAssembly for use in the client. This crate is kept minimal to
280 keeep the WebAssembly binary small.
284 WebAssembly/Rust bindings for the items in `zcoord/`. Produces the
285 single wasm file for use by the JavaScript, and corresponding
286 Typescript annotations etc.
288 * `templates/script.ts`
290 The main Typescript (typed Javascript) code. Otter's web
291 compatibility target is the earliest browser versions that properly
294 * `templates/session.tera`, `macros.tera`, etc.
296 Tera templates generating the main HTML screen. These templates are
297 filled in from structs in the Rust source code. The main files are
298 `session.tera` (portrait), `landscape.tera`, and `macros.tera`
299 (common), and their rendering uses an instance of
300 `SessionRenderContext` from `src/session.rs`.
304 "Non-web templataes". Tera templates for things other than web
305 pages. Currently this includes the server's outgoing emails. These
306 have to be in a separate directory because Rocket likes to load
307 everything applicable it finds in its own `templates/` directory.
308 These are used via `src/nwtemplates.rs`.
310 * `wdriver.rs`, `wdriver/`
312 WebDriver-based end-to-end tests. Each `wdt-*.rs` is one test
313 utility. `wdriver.rs` (in the top level to evade Cargo's
314 dur-brained search rules) is the library for these, and contains
315 most of the heavy lifting.
317 These are not standard Rust `#[test]` tests because they need to
318 reinvoke themselves via `bwrap` for test isolation reasons, and
319 because their dependencies are extensive and not properly capturable
320 in Cargo. They are run by `make check`.
322 * `library/`: The shape libraries.
324 The program `./media-scraper` (which is not run by the `Makefile`)
325 reads `library/*.toml` for instructions and generates `files.make`
326 fragments. These fragments arrange to run `./usvg-processor` which
327 launders SVGs through `usvg`. `usvg-processor`.
329 The shape libraries have a different, more relaxed, copyright
333 Automatic in-browser tests
334 --------------------------
336 * `apt install firefox`
338 * `https://github.com/mozilla/geckodriver/releases/tag/v0.28.0`
339 download appropriate tarball, put "geckodriver" on PATH
341 `make check` runs all the tests; `make wdt` runs only those tests. You can run
342 an individual test with a rune like this:
345 OTTER_TEST_LOG=otter_webdriver_tests=trace CARGO_MANIFEST_DIR=~ian/Rustup/Game/server time target/debug/wdt-simple --geckodriver-args=
348 (This rune has some example logging options in it, for you to change
349 if you like. You can omit the `CARGO_MANIFEST_DIR` for an in-tree
350 non-privsep build.) After a test has run, you can find screenshots,
351 etc. in `tmp/wdt-simple` or whatever. You can restart the same game
352 server setup as the test used, with the state left by the test, with a
356 target/debug/daemon-otter tmp/wdt-simple/server-config.toml
358 and then play with it at this url:
360 http://localhost:8000/?kmqAKPwK4TfReFjMor8MJhdRPBcwIBpe
364 Rust, cargo, curl|bash-ware; privsep
365 ------------------------------------
367 If you follow the above instructions you will have downloaded and
368 executed - and, therefore, trusted:
370 * Various Debian packages - safe
371 * Rustup (the Rust downloader/installer) - this is pretty safe
372 * Rust itself - again, pretty safe
373 * Otter itself - well, I wrote this; up to you.
374 * 450 transitive dependencies of otter (from crates.io)
375 * 50 transitive dependencies of bundle-sources
376 * the transitive dependencies of resvg
377 * a geckodriver binary directly from mozilla
379 You will have trusted the integrity of the following:
381 * The Debian archive (via its apt keyring) (very good)
382 * Rustup's and Rust's TLS keyholders (good, I think)
383 * The HTTP TLS cabal (sigh)
384 * github (pretty good in practice)
385 * whatever mozilla do to make binaries, in particular geckodriver
386 * crates.io (extremely poor traceability)
387 * the project management of hundreds of random crates.io libraries
389 If this makes you uncomfortable, as it should, you may wish to
390 consider running everything in a separate shell account, or a VM or
391 container of some kind.
393 (I have a not-properly-released tool called "nailing-cargo" which
394 makes it possible to do most things in my main account but run the
395 Rust stuff in a separate less-privileged account. There is support
396 for this in the Makefile. But if you want to run *everything* in the
397 lesser account, you don't need to bother with that.)
400 Dependencies - apologia
401 -----------------------
405 This is needed almost solely because Rocket needs it. Rocket is
406 the web framework I am using. The next version of Rocket (0.5.x),
407 which is in development, will not need Nightly, but it will also be
408 a serious compatibility break. The existing Rocket (0.4.x) will
409 almost certainly never be ported to Stable Rust. When Rocket 0.5.x
410 is out, porting Otter to it will go on my list - but it won't be
413 * The many dependencies of Otter
415 These are partly because Rocket is a large piece of software with
416 much functionality. But also because I favoured my own programming
417 convenience and in some cases was experimenting with different
418 approaches. In practice, it seems to me that once I'm using Rocket
419 and WASM and resvg and so on, there is not that much to be gained
420 by trying to prune the dependencies of the otter package itself.
422 * bundle-rust-sources
424 This is mine, but it needs to be properly released.
426 * geckodriver (for the automated in-browser tests)
428 This is done with a protocol called "WebDriver" which is a
429 cross-browser way to puppet a browser. There is a thing called
430 "geckodriver" which converts that to a firefox-specific protocol
431 for the same purpose, called "Marionette". (In practice all this
432 seems to have lots of bugs and misfeatures.)
434 AFAICT the usual approach for using geckodriver to have it *bind to
435 a fixed TCP port accessible to all local programs*. My wrapper
436 tooling arranges to run this in an ephemeral $HOME and a private
439 AFAICT the only practical way to get geckodriver is to download the
440 binary. I got mine here:
441 https://github.com/mozilla/geckodriver/releases/tag/v0.28.0 You
442 You just dump the binary on your PATH.
448 * For running on chiark I build with the Rust target
449 `x86_64-unknown-linux-musl` which on my system is configured to
450 produce a completely statically linked bionary. I have this in my
451 `~/.cargo/config` (in the lesser privsep account):
454 [target.x86_64-unknown-linux-musl]
455 rustflags = ["-C", "target-feature=+crt-static"]
456 # ^ from https://stackoverflow.com/questions/31770604/how-to-generate-statically-linked-executables