From 0a06f163d1664bfd0ff938569223294edf9902f6 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Mon, 12 Jun 2023 23:47:43 -0400 Subject: [PATCH] initial --- .dockerignore | 3 + .gitignore | 1 + Cargo.lock | 957 ++++++++++++++++++++++++++++++++++ Cargo.toml | 11 + LICENSE | 699 +++++++++++++++++++++++++ README.md | 7 + client/css/main.css | 27 + client/index.html | 8 + client/js/main.js | 25 + client/js/map.js | 243 +++++++++ client/js/sprite.js | 43 ++ client/static/cross.png | Bin 0 -> 4289 bytes client/static/dot.png | Bin 0 -> 4288 bytes client/static/empty.png | Bin 0 -> 563 bytes client/static/tee.png | Bin 0 -> 4283 bytes client/static/turn.png | Bin 0 -> 569 bytes client/static/tux.png | Bin 0 -> 101931 bytes client/static/wall.png | Bin 0 -> 571 bytes client/static/wall_end.png | Bin 0 -> 4281 bytes deployments/docker/Dockerfile | 16 + src/main.rs | 22 + src/room/handle.rs | 106 ++++ src/room/messages.rs | 69 +++ src/room/mod.rs | 128 +++++ src/room/websocket.rs | 66 +++ src/rooms.rs | 59 +++ src/routes.rs | 51 ++ 27 files changed, 2541 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 client/css/main.css create mode 100644 client/index.html create mode 100644 client/js/main.js create mode 100644 client/js/map.js create mode 100644 client/js/sprite.js create mode 100644 client/static/cross.png create mode 100644 client/static/dot.png create mode 100644 client/static/empty.png create mode 100644 client/static/tee.png create mode 100644 client/static/turn.png create mode 100644 client/static/tux.png create mode 100644 client/static/wall.png create mode 100644 client/static/wall_end.png create mode 100644 deployments/docker/Dockerfile create mode 100644 src/main.rs create mode 100644 src/room/handle.rs create mode 100644 src/room/messages.rs create mode 100644 src/room/mod.rs create mode 100644 src/room/websocket.rs create mode 100644 src/rooms.rs create mode 100644 src/routes.rs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fa3945f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +/deployments +/target +/.git diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6b0a690 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,957 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f8ccfd9221ee7d1f3d4b33e1f8319b3a81ed8f61f2ea40b37b859794b4491" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.21.0", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matchit" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rollback" +version = "0.1.0" +dependencies = [ + "axum", + "serde", + "serde_json", + "tokio", + "tower-http", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "serde" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "serde_json" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.13", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tungstenite" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..98ffd29 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rollback" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +axum = { version = "0.6.12", features = ["ws"] } +tower-http = { version = "0.4.0", features = ["fs"] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4f7b5f1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,699 @@ +MIT License + +Copyright (c) 2023 tint + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f6bf8ab --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Licenses + +| License | Author | Project | +|---------|--------|---------| +| [MIT](https://mit-license.org/) | tint | [rollback](https://git.tint.red/tint/rollback) | +| [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html) | tylerm | tuxman | + diff --git a/client/css/main.css b/client/css/main.css new file mode 100644 index 0000000..fbe272c --- /dev/null +++ b/client/css/main.css @@ -0,0 +1,27 @@ +* { + margin: 0; + padding: 0; +} + +#container img { + image-rendering: -webkit-optimize-contrast; /* webkit */ + image-rendering: -moz-crisp-edges /* Firefox */ +} + +.rotate90 { + transform: rotate(90deg); +} + +.rotate180 { + transform: rotate(180deg); +} + +.rotate270 { + transform: rotate(270deg); +} + +.sprite { + position: absolute; + transition: left .1s, top .1s; + z-index: 2; +} diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..9ba6b4c --- /dev/null +++ b/client/index.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/client/js/main.js b/client/js/main.js new file mode 100644 index 0000000..7004fb5 --- /dev/null +++ b/client/js/main.js @@ -0,0 +1,25 @@ +import { Sprite } from './sprite.js' +import { Map } from './map.js' + +let width = 13 +let height = 5 +let data = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 +] + +let map = new Map(width, height, data) +let tux = new Sprite("/static/tux.png", map) + +tux.show() +const callback = () => { + + tux.add_pos(1, 0) + + setTimeout(callback, 500) +} + +callback() diff --git a/client/js/map.js b/client/js/map.js new file mode 100644 index 0000000..e293ad2 --- /dev/null +++ b/client/js/map.js @@ -0,0 +1,243 @@ +const create_style = (map) => { + const css = ` + * { + --scale: 100; + --aspect: ${map.width/map.height}; + --scaleX: calc(var(--scale) * 1vw); + --scaleY: calc(var(--scale) * 1vh); + } + + body { + background-color: #191919; + width: 100vw; + height: 100vh; + display: flex; + } + + #container { + width: calc(var(--scaleY) * var(--aspect)); + height: var(--scaleY); + margin-top: calc((100vh - var(--scaleY))/2); + margin-left: calc(50vw - var(--scaleY)*var(--aspect)/2); + position: relative; + } + + #container img { + display: inline-block; + width: ${100/map.width}%; + height: ${100/map.height}%; + } + + @media (max-aspect-ratio: ${map.width}/${map.height}) { + #container { + width: var(--scaleX); + height: calc(var(--scaleX) / var(--aspect)); + margin-left: calc((100vw - var(--scaleX))/2); + margin-top: calc(50vh - var(--scaleX)/var(--aspect)/2); + } + }`; + + map.style.innerHTML = css +} + +const Direction = { + EMPTY: 0, + WALL_HZ: 1, + WALL_VT: 2, + TURN_Q1: 3, + TURN_Q2: 4, + TURN_Q3: 5, + TURN_Q4: 6, + TEE_NORTH: 7, + TEE_EAST: 8, + TEE_SOUTH: 9, + TEE_WEST: 10, + CROSS: 11, + DOT: 12, + WALL_END_NORTH: 13, + WALL_END_SOUTH: 14, + WALL_END_EAST: 15, + WALL_END_WEST: 16 +} + +const place_tile = (container, type) => { + + const img = document.createElement("img") + + let image_src, class_name; + switch(type) { + case Direction.EMPTY: + image_src = "/static/empty.png" + class_name = "" + break + case Direction.WALL_HZ: + image_src = "/static/wall.png" + class_name = "" + break + case Direction.WALL_VT: + image_src = "/static/wall.png" + class_name = "rotate90" + break + case Direction.TURN_Q1: + image_src = "/static/turn.png" + class_name = "" + break + case Direction.TURN_Q2: + image_src = "/static/turn.png" + class_name = "rotate270" + break + case Direction.TURN_Q3: + image_src = "/static/turn.png" + class_name = "rotate180" + break + case Direction.TURN_Q4: + image_src = "/static/turn.png" + class_name = "rotate90" + break + case Direction.TEE_NORTH: + image_src = "/static/tee.png" + class_name = "rotate180" + break + case Direction.TEE_EAST: + image_src = "/static/tee.png" + class_name = "rotate270" + break + case Direction.TEE_SOUTH: + image_src = "/static/tee.png" + class_name = "" + break + case Direction.TEE_WEST: + image_src = "/static/tee.png" + class_name = "rotate90" + break + case Direction.CROSS: + image_src = "/static/cross.png" + class_name = "" + break + case Direction.DOT: + image_src = "/static/dot.png" + class_name = "" + break + case Direction.WALL_END_NORTH: + image_src = "/static/wall_end.png" + class_name = "" + break; + case Direction.WALL_END_EAST: + image_src = "/static/wall_end.png" + class_name = "rotate90" + break; + case Direction.WALL_END_SOUTH: + image_src = "/static/wall_end.png" + class_name = "rotate180" + break; + case Direction.WALL_END_WEST: + image_src = "/static/wall_end.png" + class_name = "rotate270" + break; + } + + img.setAttribute("class", class_name) + img.setAttribute("src", image_src) + + container.appendChild(img) +} + +const get_point = (width, height, data, x, y) => { + if (x < 0 || x >= width || y < 0 || y >= height) { + return 0 + } else { + return data[y * width + x] + } +} + +const gen_walls = (width, height, data) => { + + let walls = Array(width * height) + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + + let north = get_point(width, height, data, x, y-1) + let south = get_point(width, height, data, x, y+1) + let east = get_point(width, height, data, x+1, y) + let west = get_point(width, height, data, x-1, y) + let current = get_point(width, height, data, x, y) + + let point = Direction.EMPTY + + if (!current) { + walls[y * width + x] = point + continue + } + + if (north && south && east && west) { + point = Direction.CROSS + } else if (east && west && north) { + point = Direction.TEE_NORTH + } else if (east && west && south) { + point = Direction.TEE_SOUTH + } else if (north && south && east) { + point = Direction.TEE_EAST + } else if (north && south && west) { + point = Direction.TEE_WEST + } else if (east && west) { + point = Direction.WALL_HZ + } else if (north && south) { + point = Direction.WALL_VT + } else if (west && south) { + point = Direction.TURN_Q1 + } else if (south && east) { + point = Direction.TURN_Q2 + } else if (east && north) { + point = Direction.TURN_Q3 + } else if (north && west) { + point = Direction.TURN_Q4 + } else if (north) { + point = Direction.WALL_END_NORTH + } else if (east) { + point = Direction.WALL_END_EAST + } else if (south) { + point = Direction.WALL_END_SOUTH + } else if (west) { + point = Direction.WALL_END_WEST + } else { + point = Direction.DOT + } + + walls[y * width + x] = point + + } + } + + return walls +} + +const gen_map = (map) => { + let walls = gen_walls(map.width, map.height, map.data) + for (let y = 0; y < map.height; y++) { + for (let x = 0; x < map.width; x++) { + place_tile(map.container, walls[y * map.width + x]) + } + } + +} + +export class Map { + + constructor(width, height, data) { + this.width = width + this.height = height + this.data = data + this.container = document.body.appendChild(document.createElement("div")) + this.container.id = "container" + this.style = document.body.appendChild(document.createElement("style")) + + create_style(this) + gen_map(this) + } + + destroy() { + this.container.remove() + this.style.remove() + } + +} diff --git a/client/js/sprite.js b/client/js/sprite.js new file mode 100644 index 0000000..ec6ecbd --- /dev/null +++ b/client/js/sprite.js @@ -0,0 +1,43 @@ +export class Sprite { + + constructor(image_src, map) { + this.element = document.createElement("img") + this.element.src = image_src + this.element.className = "sprite" + this.map = map + this.map.container.appendChild(this.element) + this.x = 0 + this.y = 0 + this.hide() + } + + #update_pos() { + this.element.style.left = `${100/this.map.width*this.x}%`, + this.element.style.top = `${100/this.map.height*this.y}%` + } + + set_pos(x, y) { + this.x = x + this.y = y + this.#update_pos() + } + + add_pos(x, y) { + this.x += x + this.y += y + this.#update_pos() + } + + hide() { + this.element.style.display = "none" + } + + show() { + this.element.style.display = "initial" + } + + destory() { + this.element.remove() + } + +} diff --git a/client/static/cross.png b/client/static/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..4ee9824952a6a213de09b1f445aa1341b625df64 GIT binary patch literal 4289 zcmeHKdvFv*8lMm$WR)lwK=CycJa+aql}!x0OR|uKy|9LGLXqB?-rbSion?2D zodjaI;F9w=j0OcfJSY`>6c0}xcR{RLEkP)>0+_ptMgb4+yl_y{GHF^_g`Wr)_w?il5dB zDr#`4@oMaB$SSox+*S2XVe<={=CpK%KT+^?_t+}F{OW-%yYh0jrCy$M;UV?AyWc9i zz4+3bGyfKE*>Jw))T%9;uN02n);P&9`sgbr@?vRWWxm^T#$Gs4{x{Rjc6N3*R&0N6 zQTvqRPd-i-WbzjtD&DZT$FkQ!`^Aed%s4)6`|b(8zpS2pvi0%9i&ySw`_^S! zeB$1Xt^VIOFUimMeSPBf&V3(c4(v~TbLg6>sv-BjV|9Bj9*tIDSWa4UI(;6evp;c^ z?u(7jI?CVo6{hDswvQkS>TX+h#P|Cht7b3T@#yrKY2QP8|5elbaY^{&XSTN647*0> zHBH)HVC;CCZ#Oi5aqF+QuUYr_u(X}Y>YViZVk<`C-Ich6U9#Yq*PH&l5Ww<|g#i(V?XIH!5DZTsj zUZvym!SPk=3(q9a2z-XRY6tPTz5E%7gc_%I0q_wA!9{ zb`iUOM$O-=9~n1e+TmNTqeVJTGb01Qbn2XX#DhQKA!K`bzPX>Z&K!%}%e0?u!k>lYf9 z3U-kwDK-?TJR*of1>kBl5=-)`gV1?-^sSjG0@oqRQU_7(_2EuA0ddaA8EMk3N_8wz zY`}{WVvw(N&FZ5-e-0w7C~=;mQmK?NWirZ%5XIQ-c8X>xmL(B_OxDK~ppvoVRE;9b z;etsaA;lF*j^P?72*|aHgCI~l-XC8y?)47P$C7<2AU!A*#3{x|Q_(0j*dwX9>kvs_ zKtJe_^rHz)Rl=lPn-HM84#t$JgDFH|z&~D_i0J8v0tF*5il9lJ0aGLP3c;Gszn zlA>|l3yD1hsYt;aVhxE+Ythpg90+nB;2nbQ&s_&2l-J9Rml%gO6sdy};H)w+Mr9O{?V2#;cb&D?olpu0&5EW9a zR=olBOHnvq0h*eO#b&Xvw9RT}?X2C--T+m>L=sh^#>vn|6Q{Rm!@{Fvkg!0jQ$(QK zQ7*hQ0f8bX{IVQz5Ly7Z<~h*pMbk+H3UC1hB2t<)@wA0!SU=0~oRv3oB+c>kAiOL} z!TSG))+P^LlpXSNDT(^8*G<_OH6Jd^{$+n7l0KDiT%Qy?5V9#GK^+wJI1yL2NeF{j z2%^=auUz}>(hrmZ2LKZgZ7dl?Wk7OhILQD6kfd3QV7HqYi#?DPZ-6~12bB~^z|s)X z5ov|WQ`ZWgt`F3MLt{yWp*9LgFp{>Qs^}NY+$R{-moTNR8T}a-QU9Y!kq#KN$RNM0 z4J}@1Eu;n(!#>SWyg%jDHx@r-7dSrB$*}Ytk!wV*VJR>y@JMxy$Tchlh6Ns}t{+V< z!;Rw<;TkxCNa!7Rl9T4Z6$Tcn5THW z?!14F8J9y@$AA9VZe+SsaaSu&IjZf-F@3WLMLZ=bVO-lRF8Ec!WCXg)<0|!!?GkFx o_1*RB*PF(mYt|jP1vR6v@5^rfwtmyX90bEW?zygAGi#dv3ukZut^fc4 literal 0 HcmV?d00001 diff --git a/client/static/dot.png b/client/static/dot.png new file mode 100644 index 0000000000000000000000000000000000000000..600e3738e0a2a648e2551d67759a40fb72276702 GIT binary patch literal 4288 zcmeHKdvFv*8lM;>$x1+whoVOfgVBi2V`pbKo4G6@>;|&PCd(2+1PDe9G-P!C+ zvJ+lWG(k~}qN3$-XbzM*1qv}pIJJ^0P*Aw!5KBrliKTZMA1DPDK2Yy^X7g05u2OaW zm#v!ZneN~B>+k#Z*I#wt?=PK~ZJBDpFf7|!;t8NO-FPxbqyLKBgRQ9fa!q-q763^+ zo=_w?0&%T24soc<5{Bt#w=8@=`v^Yf$I#}7K3sw|x>p49dcJ#Y)XnnD#n0!Qta4te z@}BtO@N>r|2Xfx?-+5_!7Kl;V&jcE)Iu^YA>9nbT?EYR`k(v9N{nqnp*S-55{jMwA)3D=c)vWnfJ|!-!m{W0ZU*OQQXZMH13h%P%vlpG- zeB08RkF#1QOnBx4!N2qL$ufm%+;Ft8W4?lWYML{1Iv>Qaw0ha?_Ius#zPM4e+t)wh zDmmhxSYNj6AVH3;xw`7O|1W#)nP0VMaqgUY|ExEWoBYC9 zs{QYLi)G`7(ZDQ6v=~*6pZr074W&PbVuIfPN>-x52_tTRqEH|aEyP|62XAQ-#7TwU@thHZ0 zI=*7t#E;aEvhJZuemq|N-oNwOb2j}{U<-=2i$})?o8EanG3BKLO%pnRuY(7~mlb89b5X|SAqi#;Q6A?k~7E4mlEuDaY`Uw`enskhw3YCFC;-{{=%$a41Z z%vJxYoSi-M#$)4t&S(v-p1gba2fO?ede*;quF;COT-7}F<)79^-rsu-etyhy`44q_ zvrcZ<+SL<2HDgu$`j(cj!WX8+52ueQ{A}y={J>q?S}R9&b@crCLfbz{X8$Mcd)Gg7 zIs?D`rTN`h#-=v?{sU)RU7g*oLv?GQb-9KmW?Arp zgedU=&)i-L^yMPLnil72I+;vTNgJgkLbNqMKc8k;nq^6ZAl2HK26Qr}&M+ua93H3& z2|2FGN(?tRK~SmITm*r}@jm~eai6cBKBo4nfb^hs5T~saLr0_ZU<*|%u0bTd4*jNu zT8{QJ9e}D*oe*Gg4UB0s22+SazkR$q5i!FN1sX@S{)1{I-FLUEsq;S<&CKthzZc3LgbW;cMAPUCn%wr@c5G7F>L{XNIQC5P;V6O}+5mAXY$trS)O2~I`Bqs#{nQyh*$UHBegSc)0w@kf9rAp;k&K#o=G0|Vu9 z6fV+$p{CX0bU0WhpFxey#^w!xDquoInP_lY8OoLt#8?&{1%reIMxG)9(*ni9yAu#- zN}^m*A}+#k2{$bJhka-}i9iD$pg}~+ur{7?@K&~*wep;kXY)vgzR0xVBa6l&sB)bS95INTN3wBkJv?NHtq7c#%X@%0$)C$iv z7wVRwz9hrYSOp{)$vDUX!JNH<(Y*oFM$PDpxPbnZCIu#7P?14)sXkP^P%WhUi(#*3 zM%notf4yt*JI;WpM$Gmc3-@9L_LvLB}k~>rkqh=USn*MBI4eHF$yuRX$Pe*5`F*n5d zJrUG(omO0_xs|AKD#y&jA{6nYtc7vou(;&zu~QJ}datLbJoAk2&89RA%WT8H`Onj# g$1NSRCtccEX>4Tx04R}tkv&MmP!xqvQ?(*34t5X`$xxl_q9Tr3g(6f4wL+^7CNKSiCJjl7 zi=*ILaPVib>fqw6tAnc`2>yV$x;QDiNQw6)g%&Yhc)XAE?m4`7A0RX;OtZRX0Zq5f zbTT1kbE{(L6+MU`fDwo?vy3@OO2N0j?x~aNF3z+3`~IwmnztAb5Q%4*VcNtS#M7I$ z!FiuJ%1W|Id`>)W(glehxvqHp#<}RSz%!#}COuCaB^HYvtaLCdnHupFaZJ^8$``U8 ztDLtuYn2*n-IKpCoYz;DxlU^sNi1Rs5=1Ddp^OS_#A(+_v5=KlnXct1vm?C500}_lx6vi~^xupjmgE?_eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{000X~L_t&t*JEG+0ssI700H7A1)Bf>002ovPDHLkV1nik B;4c6G literal 0 HcmV?d00001 diff --git a/client/static/tee.png b/client/static/tee.png new file mode 100644 index 0000000000000000000000000000000000000000..e3857fc42ad11e330beef747b280e8f49cacda73 GIT binary patch literal 4283 zcmeHKeQ*@z8Q%m-;3QxqCK@YUHdO<V z-Q+e27(`BL5fP-cRWyU541@TQgc`t^Fe8@qV**mgXskp*C3YHhh^@3B?Yn#VoI2CV zO#LrAvtQ5qdw%cx{NCq%=6xRvtSHMg<(Uu!$@G2K~D%>4Z7rP97=S)P=i z^|)`|rI!Z(e)3Rj{=xFLg}JYOx$U)$Re4JeWGQEtzc(~<=d-PwPMD|fy^yTh+J9=A zvcGorC+#;jW^cLUoVuYS=lb~YhP6mnE#ZtbMEuImld?tJy^QCch65&uFGv& zdi+;XPV4^m1IT-P0V_T@*G)xBI*P?`+f+ws?$E9Z+t=bt>-Nt<5z zQASJ7kvZm`6HKRR>&J6{eq_f}&+pi)ZKw!kT}qz0Mt}9(Tg~65-4K6ySX`MNDEwph z!9Atsu0_)~ytAF$^lQ(0?xn@|{6f;+>vh#veDt=qFVWw6>l)MD(>A5oZT;d=@0%q* z?(a~0uARV-`$Js>%h6Fl}naIpDG?xUu@KTy5WPAuuYuVfo?dwpdfnY?Wp8jILm9&Y?qpIT*NQVDsyPyDVtuO&xi^{cdyk!=v-iuV=59 z?rb?a>rW5uxiAoVC%-0kM`!1kp)2!a$EVFM{$kGpN5z(XUDeYsoE>=P%BgcW`P%0_ zM>jw5=M41z_GSG@#`aU%V{N^z3m^5n-e_s=8@iVEyQkybja^$-zy#GKn26Q>|0lm3_+grxGOI9T1ZqLOc_ z@LM+%7-~S&S{GLB51?*24p5ufW+rj3CN)sl zViW3&3nEkDSvpJs|6Eu|Rbvc6BoYa8!fKY|LBis2I0%v=C<=!NTxpD|tcFLGe4Qf2 z;QY$Rg<-HA9T{IF=J$`%N0ng}pdN(A#t4g zfWFs5sf6p9r~rywALoI$0YugO@e~3->L06*hmCLqo&aGGflvkZYMIbwna>{>_0S~< zN|Bi11;w6#R3&jttO;Y&Ta0kV4+Of8@=idH#BP8g%I{}9GGDI`&*yPrdjE_d^OC?A zpBA3B+N}~f z&QT(yu=5U_a|j$RSb&Wc9HL;gvEwLK#wD1QYrbSeQ-al8QNLYBrwfhKXAgJN+S zhyW)6DcS^%vQrk$pb~gysT_~6a5|+38w5lw8Z;Vo!I_eP&xKKDa?BD4v#JOkT-b6c zTCa^YR7w%BT4i-LEq2;&r%2jPlXhE?H5InOw+6%&n29>4g*01jhPys33=9Se%j$Uw z2@E@og>lCLtIF|8Sq{4}odVT8N1Od{ISH)FdRP@eQj)SVq@A%)m6V0C6)`qDPTCl9 z99|YAvGISQ^~HlaQ&V0pDX{-W!<1T4t3h4rFZCOijHQI4#-ds z@gX)E1h9Gxr|XDa`kqvvMQb789W-7j7ICxFQ4n zQZ`t;U@as@i{Y?ldfE8_ui?4)0egVdQ=Lpo-zmAKWlPJt-g1ts8N>Biy6A$ZW5!QEfxF^*iwKiwx=;Mc5J`Og#tG3V=dn)YIG12kr+ zKEF5P@{G(hg51^FlLbw;tKMqWEl2cSIbv)Ufq*6?HH7M$#kCL5$%UXCpQog9W-ni} lB>nM!!)w=lr;vFFlK6ebzp}d@xC#-7&%46&N@>m3{{S_+0s#O3 literal 0 HcmV?d00001 diff --git a/client/static/turn.png b/client/static/turn.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a93cff73fcb8c8210517f966f96e3e28c1a21a GIT binary patch literal 569 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(e(OU~JBGb`J1#c2+1T%1_J8No8Qr zm{>c}*5j~)%+dJhtxCE|Vj_hn0_MJ1q|~>S%XNi7R%@87kKW%VHD1rI?!^zH3O*!n zeD&bbn$^v#6*%e|cI>jy+~v{v-D%`g}w%Y2l57MeLg=Efn$>b{7p@TvLB7 zwe_=D`qrT2wbh@*+dkboWpq8WPpQ*Y$FYS$(sW8-W2?kkDNVIYTjqcG&~H&UF~(@; zse~sH4x(Br$NB%U@85089XvTNNQ1Ft|BY|QB?RuU&MLkA&u-h>XPg2RZ0ojc+kcB8 z&E9kU_N^}jFYM=yiP>&i$-mzacP`;l1XQozs08o~})78&qol`;+ E09Uo;MgRZ+ literal 0 HcmV?d00001 diff --git a/client/static/tux.png b/client/static/tux.png new file mode 100644 index 0000000000000000000000000000000000000000..b78a72b3e7b0c132fad1494278eac1feb803d05b GIT binary patch literal 101931 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 z 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 HN@xNAL)Yhi literal 0 HcmV?d00001 diff --git a/client/static/wall_end.png b/client/static/wall_end.png new file mode 100644 index 0000000000000000000000000000000000000000..7b28b61a8cd13a1cb082a25ae454a70b141d2abd GIT binary patch literal 4281 zcmeHLe{d7k7EYzMwPT?j3Vmt^msFi9Y<9ERB%7r%lq9qPQe#^xRi1jYd($rMW@EBV zw&_$`7*OQ#1QDx%47Kn?6yGp{mEs5^FwgSiwH6)4(NQbvD0QmfKpiXf?xsISXPnOH zf8CkQ?%wmA@1FDBbMM@n^}dp#jP#q+bvj*!r`T1Bp3~GjEd~8n=$v zVWF@T5NaVN*M}em6(OM0DIagVw{znO^2T3|Jc$>!%-H(n%41RTs~I!rbq1P}Dw^Q7 zircn%E?$f+bu<)j;SayjyC?IVPgb%E+p^AWe!lPBJUaU5rEfbjees-*aFf05)6)l+ zbgq46?snh)lg-;VEgv}Cx2U~xu=<(DTXP=S*;U$nN9ES7o0f}v-*0?5+IRi)%X=P7 z>o(UcxJ2&!Vcy)NQ}&d)jx&Q7&wl@2%RtxbJ-5uc96b>1IlfA#OIj;9oj#A#Ig&TZ zc1Po8d+~8!_S$z`RvSy}o-*ZTiubYMT`eF$4VV_I^rTt2gR^Vu^qi`K6#%{l$gGpE)qDRAeOm2bTC ztF2|${~y@#!KxPy^>;q>4@335(<@&xug;!*AUW$g{{4FkXU*ewv+#EY8F55?P%+4IQG?a@~7QP*Ig)1y8oI#OL4SGr>3oGUpTaFLHiY3 z$*oQE&)(HIEjRZ%?)Fm;UR7cbUH#v_LAO^6IKhw@h~ilmy~ny8qUV+ z9e1Y}C@dlnp$srZtPMt3#je+QS@fSViKkL=h;d}7G!9iC+; zA2BorU1>*CXI^c*u_#<1ZX$~5mZ4U6s*z=s^Dy)&tun926C*$R}16-a87v#7(uqGXV;K&?|mptYl1 zSZ5dlSqhg+QmtLDhJ>k}qh>FfPCSr-3&;?Wl9Y)hEv%6$r;MzbVa+5?(kwX+FY!X4 z{?E|rQ({Jy!ABBbiO*U=n@Sj_O$rupi4-Cr3VAI~#Fa2{)gV{} z(dsc=t|RTjACv+IAPm?T8n;oL5vMtTO2HcN<2H+lH<>Mzl{6))X_P%81>_hA!@?@0 zBhm_$r=}H_uMO0l6Jv>0Lv<98U^r>P#{@GD3q}klOsH$dNX7-k?=&gU0OJ-J#oyTlhD~)cDSfBpnv!c$3QP(-Rb5kZO-g}Dfv2kLFOw^M z>^KF3XcrVihouYqLYe5GmEvDoNhDFNvvsZa=rRD!cDS!h3u3>byu#_Hj9wQVuDM*N5q literal 0 HcmV?d00001 diff --git a/deployments/docker/Dockerfile b/deployments/docker/Dockerfile new file mode 100644 index 0000000..0565b6b --- /dev/null +++ b/deployments/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM rust:alpine AS builder + +COPY Cargo.toml Cargo.lock /app/ +COPY src /app/src +WORKDIR /app +RUN apk add musl-dev +RUN cargo build --release + +FROM alpine +RUN apk add --no-cache tini + +RUN adduser -DH block +USER block +COPY --from=builder /app/target/release/rollback /rollback +COPY client /client +ENTRYPOINT ["/sbin/tini", "--", "/rollback"] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..34783ac --- /dev/null +++ b/src/main.rs @@ -0,0 +1,22 @@ +mod routes; +mod rooms; +mod room; + +#[tokio::main] +async fn main() { + let port = std::env::var("PORT") + .unwrap_or("8080".to_owned()) + .parse::() + .unwrap_or(8080); + + axum::Server::bind(&std::net::SocketAddr::new( + std::net::IpAddr::V6(std::net::Ipv6Addr::from(0)), + port + )) + .serve( + routes::routes() + .into_make_service() + ) + .await + .expect("Error running the web server"); +} diff --git a/src/room/handle.rs b/src/room/handle.rs new file mode 100644 index 0000000..d397c70 --- /dev/null +++ b/src/room/handle.rs @@ -0,0 +1,106 @@ +use std::collections::HashSet; + +use super::messages::{ClientMessage, ServerMessage}; + +// send a ServerMessage::Connections to all sockets +pub async fn send_connections(v: &mut super::Clients, added: Option, removed: Option, frame: u64) { + // get the list of connection IDs + let connections: Vec = v.iter() + .enumerate() + .filter(|(_, n)| n.is_some()) + .map(|(id, _)| id) + .collect(); + + super::send(v, |id, _c| { + Some(ServerMessage::Connections { + connections: connections.clone(), + added, + removed, + id, + frame, + }) + }).await; +} + +// handle incoming websocket messages +pub async fn handle( + v: &mut super::Clients, + requests: &mut HashSet<(u64, Option, usize)>, // frame, connection, client id + pending: &mut Vec<(Option, Option)>, + id: usize, + msg: ClientMessage, +) { + match msg { + // broadcast inputs to every other connection + ClientMessage::Input { data, frame } => { + super::broadcast(v, ServerMessage::Input { + data, + frame, + connection: id + }, Some(id)).await; + }, + // a client needs the current game state, grab it from another client + ClientMessage::RequestState { frame, connection } => { + let count = super::conn_count(v); + + if count < 2 { // nobody to request state *from* + if let Some(Some(client)) = v.get(id) { + client.send(ServerMessage::State { + state: serde_json::Value::Null, + frame: 0, + connection: None, + }).await.ok(); + } + return; + } + + // request state from other clients + requests.insert((frame, connection, id)); + + match connection { + None => { + super::broadcast(v, ServerMessage::RequestState { frame }, Some(id)).await; + }, + Some(id) => { // it's to a specific connection + let Some(Some(client)) = v.get(id) else { + return; + }; + client.send(ServerMessage::RequestState { frame }).await.ok(); + }, + } + }, + // a client responded to a request for game state, tell all the requestees + ClientMessage::State { state, frame } => { + let mut new_requests = HashSet::new(); + for (fr, conn, cid) in requests.drain() { + if + fr != frame || // this isn't the requested frame + (conn.is_some() && Some(id) != conn) // this isn't the requested connection + { + new_requests.insert((fr, conn, cid)); + continue; + } + if let Some(Some(client)) = v.get(cid) { + client.send(ServerMessage::State { + state: state.clone(), + frame, + connection: Some(id), + }).await.ok(); + } + } + *requests = new_requests; + }, + // a client said what frame they're on, actually send the connections message + ClientMessage::Frame { frame } => { + for (added, removed) in pending.into_iter() { + send_connections(v, *added, *removed, frame).await; + } + *pending = Vec::new(); + }, + ClientMessage::Ping { frame } => { + if let Some(Some(client)) = v.get(id) { + client.send(ServerMessage::Pong { frame }).await.ok(); + } + } + } +} diff --git a/src/room/messages.rs b/src/room/messages.rs new file mode 100644 index 0000000..72958a6 --- /dev/null +++ b/src/room/messages.rs @@ -0,0 +1,69 @@ +use serde::{Serialize, Deserialize}; +use serde_json::Value; + +#[derive(Deserialize, Clone, Debug)] +#[serde(tag = "type")] +pub enum ClientMessage { + #[serde(rename = "frame")] + Frame { + frame: u64, + }, + #[serde(rename = "input")] + Input { + data: Value, + frame: u64, + }, + #[serde(rename = "requeststate")] + RequestState { + connection: Option, + frame: u64, + }, + #[serde(rename = "state")] + State { + state: Value, + frame: u64, + }, + #[serde(rename = "ping")] + Ping { + frame: u64, + }, +} + +#[derive(Serialize, Clone, Debug)] +#[serde(tag = "type")] +pub enum ServerMessage { + #[serde(rename = "framerequest")] + FrameRequest, + #[serde(rename = "connections")] + Connections { + connections: Vec, + added: Option, + removed: Option, + id: usize, + frame: u64, + }, + #[serde(rename = "input")] + Input { + data: Value, + frame: u64, + connection: usize, + }, + #[serde(rename = "requeststate")] + RequestState { + frame: u64, + }, + #[serde(rename = "state")] + State { + state: Value, + frame: u64, + connection: Option, + }, + #[serde(rename = "pong")] + Pong { + frame: u64, + }, + #[serde(rename = "error")] + Error { + error: String, + }, +} diff --git a/src/room/mod.rs b/src/room/mod.rs new file mode 100644 index 0000000..8b3d8c2 --- /dev/null +++ b/src/room/mod.rs @@ -0,0 +1,128 @@ +use std::{time::Duration, collections::HashSet}; + +use axum::extract::ws::WebSocket; +use tokio::sync::mpsc; + +mod websocket; +mod messages; +mod handle; + +use messages::{ClientMessage, ServerMessage}; + +pub enum RoomMessage { + Add(WebSocket), + Remove(usize), + WsMessage(usize, ClientMessage), +} + +pub type Client = mpsc::Sender; +pub type Clients = Vec>; + +pub type Room = mpsc::Sender; + +// spawns a task for the room that listens for incoming messages from websockets as well as connections and disconnections +pub fn start_room(room_id: String, room_service: super::rooms::RoomService) -> Room { + let (tx, rx) = mpsc::channel::(20); + + let txret = tx.clone(); + + tokio::spawn(room_task(tx, rx, room_id, room_service)); + + txret +} + +async fn room_task(tx: mpsc::Sender, mut rx: mpsc::Receiver, room_id: String, room_service: super::rooms::RoomService) { + let mut ws = Vec::new(); + let mut state_requests = HashSet::new(); + let mut pending: Vec<(Option, Option)> = Vec::new(); + + while let Some(message) = rx.recv().await { + match message { + RoomMessage::Add(w) => { // a new connection is added + // create channels for the websocket and start a task to send and receive from it + let (wstx, wsrx) = mpsc::channel(5); + let id = ws.len(); + ws.push(Some(wstx)); + tokio::spawn(websocket::start_ws(w, id, tx.clone(), wsrx)); + + if conn_count(&ws) < 2 { // the first connection is on frame 0 + handle::send_connections(&mut ws, Some(id), None, 0).await; + } else { + // connections need to be added on a specific frame + // so ask the clients for a frame to put this event on + broadcast(&mut ws, ServerMessage::FrameRequest, Some(id)).await; + pending.push((Some(id), None)); + } + }, + RoomMessage::Remove(id) => { // a connection is closed (sent by the websocket task on exiting) + // only remove it if it exists + if let Some(item) = ws.get_mut(id) { + *item = None; + }; + let count = conn_count(&ws); + if count == 0 { // remove rooms once they become empty + room_service.send(super::rooms::RoomServiceRequest::Remove(room_id.clone())).await.ok(); + break; + } + + // disconnections happen on a specific frame, ask the clients for a frame + broadcast(&mut ws, ServerMessage::FrameRequest, None).await; + pending.push((None, Some(id))); + }, + RoomMessage::WsMessage(id, msg) => { // new data from a websocket + handle::handle(&mut ws, &mut state_requests, &mut pending, id, msg).await; + } + } + } +} + +// send the websocket to the room task +pub async fn add_connection(tx: &Room, ws: WebSocket) { + tx.send_timeout(RoomMessage::Add(ws), Duration::from_secs(1)).await.ok(); +} + +pub fn conn_count(v: &Clients) -> usize { + v.iter().filter(|i| i.is_some()).count() +} + +// send a message to all or some of the clients, in parallel rather than series, +// based on a callback +pub async fn send(v: &mut Clients, create_message: impl Fn(usize, &Client) -> Option) -> usize { + let tasks = v.iter() + .enumerate() + .map(|(id, c)| { + // send to existing clients + let Some(client) = c.clone() else { + return None; + }; + + let Some(msg) = create_message(id, &client) else { + return None; + }; + + Some(tokio::spawn(async move { + client.send(msg).await.ok(); + })) + }); + + let count = tasks.len(); + // make sure all the tasks complete + for task in tasks { + if let Some(t) = task { + t.await.ok(); + } + } + + count +} + +// send a message to all the websockets in the room (optionally excluding one) +pub async fn broadcast(v: &mut Clients, msg: ServerMessage, except: Option) -> usize { + send(v, |id, _client| { + if Some(id) == except { + return None; + } + + Some(msg.clone()) + }).await +} diff --git a/src/room/websocket.rs b/src/room/websocket.rs new file mode 100644 index 0000000..50a4537 --- /dev/null +++ b/src/room/websocket.rs @@ -0,0 +1,66 @@ +use std::time::Duration; + +use axum::extract::ws::{WebSocket, Message}; +use tokio::sync::mpsc; + +use super::RoomMessage; +use super::messages::ServerMessage; + +// set up some senders and receivers so that the websocket can receive messages from the task, send messages to the task, and notify the task when it closes +pub async fn start_ws(mut ws: WebSocket, id: usize, tx: mpsc::Sender, mut rx: mpsc::Receiver) { + loop { + tokio::select! { + m = ws.recv() => { // receive from the websocket and send it to `tx` + if let Some(Ok(msg)) = m { + // get the string contents + let optionstring = match msg { + Message::Text(s) => { + Some(s) + }, + Message::Binary(bin) => { + String::from_utf8(bin).ok() + }, + Message::Close(_) => { // quit the whole loop on disconnect + break; + }, + _ => None + }; + + // ignore things that aren't strings + let Some(s) = optionstring else { + continue; + }; + + // decode and send to the room + match serde_json::from_str(&s) { + Ok(message) => { + tx.send_timeout(RoomMessage::WsMessage(id, message), Duration::from_secs(1)).await.ok(); + }, + Err(e) => { // let the client know if they sent a bad message + if let Ok(text) = serde_json::to_string(&ServerMessage::Error{ + error: format!("Failed to decode JSON message: {}: {}", e, s), + }) { + ws.send(Message::Text(text)).await.ok(); + } + } + } + } else { // websocket error + break; + } + } + s = rx.recv() => { // receive from `rx` and send it to the websocket + if let Some(msg) = s { + if let Ok(string) = serde_json::to_string(&msg) { + ws.send(Message::Text(string)).await.ok(); + } + } else { // shouldn't happen but this is if the room drops the sender, it should close the websocket anyways + break; + } + } + } + } + + // websocket disconnect due to either error or normal disconnect + // notify the room that the socket should be removed + tx.send_timeout(RoomMessage::Remove(id), Duration::from_secs(1)).await.ok(); +} diff --git a/src/rooms.rs b/src/rooms.rs new file mode 100644 index 0000000..c8199d1 --- /dev/null +++ b/src/rooms.rs @@ -0,0 +1,59 @@ +use std::collections::HashMap; + +use axum::extract::ws::WebSocket; +use tokio::sync::mpsc; +use tokio::sync::oneshot; + +use super::room; + +pub enum RoomServiceRequest { + Exists(String, oneshot::Sender), + Join(String, WebSocket), + Remove(String), +} + +pub type RoomService = mpsc::Sender; + +type RoomMap = HashMap; + +async fn handle_room_server_message(rooms: &mut RoomMap, req: RoomServiceRequest, tx: RoomService) { + match req { + // check whether a given room exists + // the sender must provide a tokio::sync::oneshot sender to receive a response + RoomServiceRequest::Exists(code, reply) => { + reply.send(rooms.get(&code).is_some()).ok(); + }, + // send a websocket into the given room, starting it if it doesn't exist + RoomServiceRequest::Join(code, ws) => { + let room = match rooms.get(&code) { + Some(rm) => rm, + None => { + let rm = room::start_room(code.clone(), tx); + rooms.insert(code.clone(), rm); + &rooms[&code] + } + }; + + room::add_connection(room, ws).await; + }, + // remove a room (called by the room task itself once there are no more connections to it) + RoomServiceRequest::Remove(code) => { + rooms.remove(&code); + } + } +} + +// a task to manage a hashmap holding the room task senders +// returns a sender to interface with the task +pub fn start_room_server() -> RoomService { + let (tx, mut rx) = mpsc::channel::(10); + let txret = tx.clone(); + + tokio::spawn(async move { + let mut rooms: RoomMap = HashMap::new(); + while let Some(req) = rx.recv().await { + handle_room_server_message(&mut rooms, req, tx.clone()).await; + } + }); + txret +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..1fa16c7 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,51 @@ +use axum::{ + extract::{ws::WebSocketUpgrade, Path}, + routing::get, + response::Response, + Router, Extension, +}; +use tokio::sync::oneshot; +use tower_http::services::ServeDir; + +use super::rooms; + +pub fn routes() -> Router { + let room_server: rooms::RoomService = rooms::start_room_server(); + + Router::new() + .route("/api/check", get(|| async {"ok"})) + .route("/api/exists/:code", get(game_exists)) + .route("/api/join/:code", get(game_join)) + .nest_service("/", ServeDir::new("client")) + .layer(Extension(room_server)) +} + +// check if a given room code exists already +async fn game_exists( + Path(code): Path, + Extension(room_server): Extension +) -> &'static str { + let (tx, rx) = oneshot::channel(); + room_server.send(rooms::RoomServiceRequest::Exists(code, tx)).await.ok(); + + if let Ok(res) = rx.await { + if res { + "true" + } else { + "false" + } + } else { + return "error"; + } +} + +// start a websocket connection and join it to the room +async fn game_join( + Path(code): Path, + ws: WebSocketUpgrade, + Extension(room_server): Extension +) -> Response { + ws.on_upgrade(|s| async move { + room_server.send(rooms::RoomServiceRequest::Join(code, s)).await.ok(); + }) +}