chiark / gitweb /
ensure_eq, fix
[otter.git] / README.md
1 OTTER - ONLINE TABLE TOP ENVIRONMENT RENDERER
2 =============================================
3
4 Otter is an online "table simulator" intended to be suitable for board
5 games and similar.
6
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.
10
11 I expect it to be used with a concurrent voice chat.
12
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.
16
17 Right now Otter is in an alpha state.
18
19
20 JOINING A GAME
21 ==============
22
23 In the simplest case:
24 ```
25   otter join-game unix:<user>::<game-name>
26 ```
27 e.g.
28 ```
29   otter join-game unix:ijackson::test
30 ```
31
32 See `otter --help` for further options, including setting your nick.
33
34 Currently when a new player joins a game (with the `otter` command),
35 all the other players must reload the page.
36
37
38 CREATING A GAME
39 ===============
40
41 ```
42 otter reset --reset-table local-users :test demo
43                          /^^^^^^^^^^^  ^^^\ ^^^^'~ game spec
44                          `table spec       game name
45 ```
46
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
51 the game.
52
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.
56
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.
61
62 See `otter --help` for some more options.
63
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.
66
67
68 MAKING YOUR OWN GAME
69 ====================
70
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.
75
76 todo: use rustdoc to provide this somewhere.
77
78
79 ADDING SHAPES
80 =============
81
82 Otter uses SVGs.  The sources for the SVGs are all in the otter source
83 tree, in the `library/` directory.
84
85 Unfortunately the mechanisms here are not yet particularly well
86 documented.
87
88 Some of these SVGs were scraped from Wikimedia.  The scraper machinery
89 can perhaps be adapted to scrape SVGs from elsewhere.
90
91 You can also add your own SVGs in the library/edited/ directory.
92 If you do that, please make sure to include the actual source code.
93 If you copied or adapted an SVG from somewhere, provide details.
94
95 Contributions should be via git branch, eg a merge request on Salsa:
96 [https://salsa.debian.org/iwj/otter](https://salsa.debian.org/iwj/otter)
97
98 NB that shapes must come with a licence compatible with CC-BY-SA 4.0.
99 See `LICENCE` for more information about copyright status.
100
101
102 BUILDING AND TESTING
103 ====================
104
105 You will need about 5500 megabytes of disk space, and a good internet
106 connection.  Your computer will be compiling a lot of code.
107
108 These instructions have been tested on Debian buster.
109
110 Setup
111 -----
112
113 1. 
114 ```
115      sudo apt install build-essential cpio git curl     \
116                       pkg-config libssl-dev             \
117                       node-typescript
118 ```
119
120 2. Install Rust.  This is most easily done with rustup:
121
122 ```
123      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
124 ```
125
126    and then follow the instructions about your `PATH`.  If this rune
127    alarms you, see below about Rust privsep.
128
129 3. Switch your Rust install to use Rust Nightly and add the WASM
130    target:
131
132 ```
133      rustup default nightly
134      rustup target add wasm32-unknown-unknown
135 ```
136
137    Unfortunately, it is possible that the Rust nightly you find when
138    you run this is missing some pieces.  The following is known to
139    work (with otter from the time of writing):
140 ```
141      rustup default nightly-2020-11-09
142 ```
143
144 4. Install some build tools:
145
146 ```
147      cargo install usvg
148      cargo install bundle-sources
149 ```
150
151    This will put them in `~/.cargo/bin`, which you presumably have on
152    your PATH (or the above `rustup` and `cargo` runes wouldn't work).
153
154 5. Install the version of wasm-pack with the option I need (upstream
155    haven't reviewed my merge request):
156
157 ```
158      git clone https://github.com/ijackson/wasm-pack.git -b cargo-opts
159      cd wasm-pack
160      cargo install
161 ```
162
163   NB that wasm-pack will itself download and install more stuff when
164   it is run by the Otter Makefile.
165
166
167 Build
168 -----
169
170 ```
171      git clone https://salsa.debian.org/iwj/otter
172      cd otter
173      make -j8 all bundled-sources
174 ```
175
176
177 Ad-hoc tests
178 ------------
179
180 In one shell:
181
182 ```
183      target/debug/daemon-otter server-test.toml
184 ```
185
186 The server does not daemonise, and the default config there makes it
187 quite verbose.  So, in another shell:
188
189 ```
190     target/debug/otter                                               \
191         --account server: --config server-test.toml --spec-dir=specs \
192         reset --reset-table test server::test demo
193
194     target/debug/otter                                               \
195         --account server: --config server-test.toml --spec-dir=specs \
196         join-game server::test
197 ```
198
199 The URL printed can then be visited in a local browser.
200
201
202 Resetting/restoring things after tests, updating server, etc.
203 -------------------------------------------------------------
204
205 After the server is updated, you can just `^C` and restart it.  Games
206 are constantly saved (although there is an up-to-1s lag on the most
207 frequently udpated game state).
208
209 If you want to clear out the server state, delete the files `[ag]-*`
210 and `accounts`.  NB that you should do this with the server not
211 running, because the server has most of that information in memory and
212 will like to write it out again.
213
214 If you update Typescript (JS code) you will need to rerun `make` to
215 rebuild the JS output.
216
217 Apart from that, if you update JS or WASM code or Tera templates, you
218 do not need to restart the server - it will pick up changes
219 automatically.
220
221 When testing, you do not need to `make bundled-sources` more than
222 once, at the beginning.  So don't, because it's slow.  But you
223 definitely should run it for every update if you make a deployment for
224 other people to use.  Otherwise you might be running a privately
225 modified server without offering your users its source code.  See
226 LICENCE.
227
228 If you Do Something to the output from cargo, you should `rm stamp/*`,
229 since the `Makefile` won't notice, otherwise, that, the relevant cargo
230 rune(s) need to be re-run.  Needlessly deleting all the stamp files
231 wastes only a handful of seconds (on my stupidly fast laptop).
232
233
234 Navigating the otter source code
235 --------------------------------
236
237 * `src/`
238
239   The main Rust source code.  This is mixture of code used only or
240   mainly by the server and code used by the `otter` command line
241   utility; these aren't split up in a wholly principled way.  In Rust
242   terms this is a "library crate".
243
244 * `src/bin/*.rs`
245
246   Support executables, including in particular the command line
247   utility `otter` which is used to set up and join games.
248
249 * `daemon/`
250
251   The Otter server.  This is a simple binary crare.  Much
252   functionality belonging primarily, or only, to the server, is in
253   `src/`, simply because it was easier not to disentangle it.
254   Anything that needs Rocket (the web framework) is in `daemon/`.
255
256 * `zcoord/`
257
258   Code shared by the host and the WebAssembly.  Notably, the Z
259   coordinate handling, but also a a few other minor functions needed
260   by both client and server.  To avoid duplicating them are written
261   once in Rust and compiled twice - once for the host and once for
262   WebAssembly for use in the client.  This crate is kept minimal to
263   keeep the WebAssembly binary small.
264
265 * `wasm/`
266
267   WebAssembly/Rust bindings for the items in `zcoord/`.  Produces the
268   single wasm file for use by the JavaScript, and corresponding
269   Typescript annotations etc.
270
271 * `templates/script.ts`
272
273   The main Typescript (typed Javascript) code.  Otter's web
274   compatibility target is the earliest browser versions that properly
275   support WebAssembly.
276
277 * `templates/session.tera`, `macros.tera`, etc.
278
279   Tera templates generating the main HTML screen.  These templates are
280   filled in from structs in the Rust source code.  The main files are
281   `session.tera` (portrait), `landscape.tera`, and `macros.tera`
282   (common), and their rendering uses an instance of
283   `SessionRenderContext` from `src/session.rs`.
284
285 * `nwtemplates/`
286
287   "Non-web templataes".  Tera templates for things other than web
288   pages.  Currently this includes the server's outgoing emails.  These
289   have to be in a separate directory because Rocket likes to load
290   everything applicable it finds in its own `templates/` directory.
291   These are used via `src/nwtemplates.rs`.
292
293 * `wdriver.rs`, `wdriver/`
294
295   WebDriver-based end-to-end tests.  Each `wdt-*.rs` is one test
296   utility.  `wdriver.rs` (in the top level to evade Cargo's
297   dur-brained search rules) is the library for these, and contains
298   most of the heavy lifting.
299
300   These are not standard Rust `#[test]` tests because they need to
301   reinvoke themselves via `bwrap` for test isolation reasons, and
302   because their dependencies are extensive and not properly capturable
303   in Cargo.  They are run by `make check`.
304
305 * `library/`: The shape libraries.
306
307   The program `./media-scraper` (which is not run by the `Makefile`)
308   reads `library/*.toml` for instructions and generates `files.make`
309   fragments.  These fragments arrange to run `./usvg-processor` which
310   launders SVGs through `usvg`.  `usvg-processor`.
311
312   The shape libraries have a different, more relaxed, copyright
313   licence.
314
315
316 Automatic in-browser tests
317 --------------------------
318
319   apt install firefox
320
321   https://github.com/mozilla/geckodriver/releases/tag/v0.28.0
322   download appropriate tarball, put "geckodriver" on PATH
323
324 "make check" runs them; "make wdt" runs only those tests.  You can run
325 an individual test with a rune like this:
326
327   OTTER_WDT_LOG=otter_webdriver_tests=trace CARGO_MANIFEST_DIR=~ian/Rustup/Game/server time target/debug/wdt-simple --geckodriver-args=
328
329 (You can omit the CARGO_MANIFEST_DIR for an in-tree non-privsep build.)
330 After a test has run, you can find screenshots, etc. in tmp/wdt-simple.
331
332 You can restart the same game server as the test used with
333   target/debug/daemon-otter tmp/wdt-simple/server-config.toml
334 and then see it at this url:
335   http://localhost:8000/?kmqAKPwK4TfReFjMor8MJhdRPBcwIBpe
336
337
338 Rust, cargo, curl|bash-ware; privsep
339 ------------------------------------
340
341 If you follow the above instructions you will have downloaded and
342 executed - and, therefore, trusted:
343
344  * Various Debian packages - safe
345  * Rustup (the Rust downloader/installer) - this is pretty safe
346  * Rust itself - again, pretty safe
347  * Otter itself - well, I wrote this; up to you.
348  * My branch of wasm-pack - I haven't audited what I started with.
349  * 300 transitive dependencies of otter (from crates.io)
350  * 50 transitive dependencies of bundle-sources
351  * the transitive dependencies of resvg
352  * god knows how many transitive dependencies of wasm-pack
353  * a geckodriver binary directly from mozilla
354  * whatever wasm-pack downloads at runtime (mostly(?) via cargo)
355
356 You will have trusted the integrity of the following:
357
358  * The Debian archive (via its apt keyring) (very good)
359  * Rustup's and Rust's TLS keyholders (good, I think)
360  * The HTTP TLS cabal (sigh)
361  * github (pretty good in practice)
362  * whatever mozilla do to make binaries, in particular geckodriver
363  * crates.io (extremely poor traceability)
364  * the project management of hundreds of random crates.io libraries
365
366 If this makes you uncomfortable, as it should, you may wish to
367 consider running everything in a separate shell account, or a VM or
368 container of some kind.
369
370 (I have a not-properly-released tool called "nailing-cargo" which
371 makes it possible to do most things in my main account but run the
372 Rust stuff in a separate less-privileged account.  There is support
373 for this in the Makefile.  But if you want to run *everything* in the
374 lesser account, you don't need to bother with that.)
375
376
377 Dependencies - apologia
378 -----------------------
379
380  * Rust Nightly
381
382    This is needed almost solely because Rocket needs it.  Rocket is
383    the web framework I am using.  The next version of Rocket (0.5.x),
384    which is in development, will not need Nightly, but it will also be
385    a serious compatibility break.  The existing Rocket (0.4.x) will
386    almost certainly never be ported to Stable Rust.  When Rocket 0.5.x
387    is out, porting Otter to it will go on my list - but it won't be
388    trivial.  Sorry.
389
390  * The many dependencies of Otter
391
392    These are partly because Rocket is a large piece of software with
393    much functionality.  But also because I favoured my own programming
394    convenience and in some cases was experimenting with different
395    approaches.  In practice, it seems to me that once I'm using Rocket
396    and WASM utilities and resvg and so on, there is not that much to
397    be gained by trying to prune the dependencies of the otter package
398    itself.
399
400  * wasm-pack
401
402    This is a wrapper program for various utilities for manipulating
403    WebAssembly files, and their Typescript and Javascript glue, etc.
404    It likes to run cargo and do god knows what.  I'm not sure it's
405    buying me much over whatever things it runs, so ideally it would be
406    best to replace this with calls to the underlying utilities and
407    libraries.  But there are some wrinkles, for example, some version
408    coupling requirements that wasm-pack takes care of.  And to be
409    honest, I'm not sure precisely what it does and understanding that
410    would be a necessary first step to reproducing it in the Makefile.
411
412  * bundle-rust-sources
413
414    This is mine, but it needs to be properly released.
415
416  * geckodriver (for the automated in-browser tests)
417
418    This is done with a protocol called "WebDriver" which is a
419    cross-browser way to puppet a browser.  There is a thing called
420    "geckodriver" which converts that to a firefox-specific protocol
421    for the same purpose, called "Marionette".  (In practice all this
422    seems to have lots of bugs and misfeatures.)
423
424    AFAICT the usual approach for using geckodriver to have it *bind to
425    a fixed TCP port accessible to all local programs*.  My wrapper
426    tooling arranges to run this in an ephemeral $HOME and a private
427    network namespace.
428
429    AFAICT the only practical way to get geckodriver is to download the
430    binary.  I got mine here:
431      https://github.com/mozilla/geckodriver/releases/tag/v0.28.0 You
432    You just dump the binary on your PATH.
433
434
435 Final weirdness
436 ---------------
437
438  * For running on chiark I build with the Rust target
439    `x86_64-unknown-linux-musl` which on my system is configured to
440    produce a completely statically linked bionary.  I have this in my
441    `~/.cargo/config` (in the lesser privsep account):
442
443 ```
444 [target.x86_64-unknown-linux-musl]
445 rustflags = ["-C", "target-feature=+crt-static"]
446 # ^ from https://stackoverflow.com/questions/31770604/how-to-generate-statically-linked-executables
447 ```