From e6e35bedad818d8b54baa1d06a1a50bbbe884429 Mon Sep 17 00:00:00 2001 From: Terkwood <38859656+Terkwood@users.noreply.github.com> Date: Thu, 26 Mar 2020 07:07:39 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=B0=EF=B8=8F=20Add=20botlink=20service?= =?UTF-8?q?=20=F0=9F=9B=B0=EF=B8=8F=20(#196)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- botlink/.gitignore | 1 + botlink/Cargo.lock | 1194 +++++++++++++++++++++++++ botlink/Cargo.toml | 23 + botlink/Dockerfile | 13 + botlink/README.md | 19 + botlink/src/env.rs | 16 + botlink/src/lib.rs | 18 + botlink/src/main.rs | 20 + botlink/src/registry.rs | 48 + botlink/src/repo/attached_bots.rs | 51 ++ botlink/src/repo/entry_ids.rs | 83 ++ botlink/src/repo/mod.rs | 16 + botlink/src/repo/redis_keys.rs | 24 + botlink/src/stream/mod.rs | 299 +++++++ botlink/src/stream/topics.rs | 3 + botlink/src/stream/write_moves.rs | 15 + botlink/src/stream/xadd.rs | 77 ++ botlink/src/stream/xread.rs | 119 +++ botlink/src/websocket.rs | 84 ++ build-all-dc.sh | 22 - build-giant-dc.sh | 7 + build-tiny-dc.sh | 8 + dc-tiny.yml | 25 +- docker-compose.yml | 25 +- reverse-proxy/Caddyfile.example.dev | 4 + reverse-proxy/Caddyfile.example.prod | 4 + tinybrain/README.md | 7 + tinybrain/{ => dockerfail}/Dockerfile | 5 + tinybrain/{ => dockerfail}/build.sh | 0 tinybrain/{ => dockerfail}/run.sh | 0 30 files changed, 2192 insertions(+), 38 deletions(-) create mode 100644 botlink/.gitignore create mode 100644 botlink/Cargo.lock create mode 100644 botlink/Cargo.toml create mode 100644 botlink/Dockerfile create mode 100644 botlink/README.md create mode 100644 botlink/src/env.rs create mode 100644 botlink/src/lib.rs create mode 100644 botlink/src/main.rs create mode 100644 botlink/src/registry.rs create mode 100644 botlink/src/repo/attached_bots.rs create mode 100644 botlink/src/repo/entry_ids.rs create mode 100644 botlink/src/repo/mod.rs create mode 100644 botlink/src/repo/redis_keys.rs create mode 100644 botlink/src/stream/mod.rs create mode 100644 botlink/src/stream/topics.rs create mode 100644 botlink/src/stream/write_moves.rs create mode 100644 botlink/src/stream/xadd.rs create mode 100644 botlink/src/stream/xread.rs create mode 100644 botlink/src/websocket.rs delete mode 100755 build-all-dc.sh rename tinybrain/{ => dockerfail}/Dockerfile (85%) rename tinybrain/{ => dockerfail}/build.sh (100%) rename tinybrain/{ => dockerfail}/run.sh (100%) diff --git a/botlink/.gitignore b/botlink/.gitignore new file mode 100644 index 000000000..4c49bd78f --- /dev/null +++ b/botlink/.gitignore @@ -0,0 +1 @@ +.env diff --git a/botlink/Cargo.lock b/botlink/Cargo.lock new file mode 100644 index 000000000..17ca5a8a7 --- /dev/null +++ b/botlink/Cargo.lock @@ -0,0 +1,1194 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "base64" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3" + +[[package]] +name = "bincode" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "botlink" +version = "0.0.1" +dependencies = [ + "base64 0.12.0", + "bincode", + "crossbeam", + "crossbeam-channel", + "dotenv", + "env_logger", + "lazy_static", + "log", + "micro_model_bot", + "micro_model_moves", + "redis_conn_pool", + "redis_streams", + "tungstenite", + "uuid", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "bytes" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" + +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "crossbeam" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dtoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "input_buffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +dependencies = [ + "bytes", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" + +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memoffset" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +dependencies = [ + "autocfg", +] + +[[package]] +name = "micro_model_bot" +version = "0.1.0" +source = "git+https://github.com/Terkwood/BUGOUT?branch=unstable#bfccfb51f28db507d91ef4579c228a5e3afeaa1a" +dependencies = [ + "bincode", + "micro_model_moves", + "serde", + "serde_derive", +] + +[[package]] +name = "micro_model_moves" +version = "0.1.2" +source = "git+https://github.com/Terkwood/BUGOUT?branch=unstable#bfccfb51f28db507d91ef4579c228a5e3afeaa1a" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "uuid", +] + +[[package]] +name = "mio" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" +dependencies = [ + "iovec", + "libc", + "mio", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "openssl" +version = "0.10.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae" + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "proc-macro2" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r2d2" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1497e40855348e4a8a40767d8e55174bce1e445a3ac9254ad44ad468ee0485af" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_redis" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c77b6d801d785941187996568567838772e31dded6f6e1c844abe2fcc1e940c" +dependencies = [ + "r2d2", + "redis", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redis" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeb1fe3fc011cde97315f370bc88e4db3c23b08709a04915921e02b1d363b20" +dependencies = [ + "bytes", + "combine", + "dtoa", + "futures-executor", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "sha1", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redis_conn_pool" +version = "0.1.0" +source = "git+https://github.com/Terkwood/BUGOUT?branch=unstable#bfccfb51f28db507d91ef4579c228a5e3afeaa1a" +dependencies = [ + "r2d2_redis", + "redis", +] + +[[package]] +name = "redis_streams" +version = "0.1.0" +source = "git+https://github.com/Terkwood/BUGOUT?branch=unstable#bfccfb51f28db507d91ef4579c228a5e3afeaa1a" +dependencies = [ + "uuid", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "regex" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "schannel" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295" +dependencies = [ + "lazy_static", + "winapi 0.3.8", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5de7bc31f28f8e6c28df5e1bf3d10610f5fdc14cc95f272853512c70a2bd779" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97bbedbe81904398b6ebb054b3e912f99d55807125790f3198ac990d98def5b0" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06fd2f23e31ef68dd2328cc383bd493142e46107a3a0e24f7d734e3f3b80fe4c" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" + +[[package]] +name = "syn" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.8", +] + +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tokio" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa5e81d6bc4e67fe889d5783bd2a128ab2e0cfa487e0be16b6a8d177b101616" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "iovec", + "lazy_static", + "libc", + "memchr", + "mio", + "mio-uds", + "pin-project-lite", +] + +[[package]] +name = "tokio-util" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tungstenite" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" +dependencies = [ + "base64 0.11.0", + "byteorder", + "bytes", + "http", + "httparse", + "input_buffer", + "log", + "native-tls", + "rand", + "sha-1", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +dependencies = [ + "smallvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "url" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +dependencies = [ + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + +[[package]] +name = "uuid" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +dependencies = [ + "rand", + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[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-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" +dependencies = [ + "winapi 0.3.8", +] + +[[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 = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/botlink/Cargo.toml b/botlink/Cargo.toml new file mode 100644 index 000000000..dbe308b2c --- /dev/null +++ b/botlink/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "botlink" +version = "0.0.1" +authors = ["terkwood <38859656+Terkwood@users.noreply.github.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tungstenite = "0.10.1" +micro_model_bot = { git = "https://github.com/Terkwood/BUGOUT", branch = "unstable" } +micro_model_moves = { git = "https://github.com/Terkwood/BUGOUT", branch = "unstable" } +bincode = "1.2.1" +redis_streams = { git = "https://github.com/Terkwood/BUGOUT", branch = "unstable" } +redis_conn_pool = { git = "https://github.com/Terkwood/BUGOUT", branch = "unstable" } +crossbeam = "0.7.3" +crossbeam-channel = "0.4.2" +env_logger = "0.7.1" +log = "0.4.8" +lazy_static = "1.4.0" +dotenv = "0.15.0" +uuid = { version = "0.8.1", features = ["v4", "serde"] } +base64 = "0.12.0" diff --git a/botlink/Dockerfile b/botlink/Dockerfile new file mode 100644 index 000000000..bbe880b76 --- /dev/null +++ b/botlink/Dockerfile @@ -0,0 +1,13 @@ +FROM rust + +WORKDIR /var/BUGOUT/botlink + +RUN rustup default stable + +COPY . /var/BUGOUT/botlink/. + +RUN cargo install --path . + +ENV RUST_LOG info + +CMD ["botlink"] diff --git a/botlink/README.md b/botlink/README.md new file mode 100644 index 000000000..f7ddfad51 --- /dev/null +++ b/botlink/README.md @@ -0,0 +1,19 @@ +# botlink service + +This websocket endpoint brokers communication between an +NVIDIA Jetson Nano dev board running katago, and the cloud +deployment for BUGOUT. + +## How it works + +It listens to `bugout-attach-bot-ev` redis stream for `game_id + player` +combinations and will subsequently respond to game state changelog events +which concern the player. + +Each time the game state changelog emits an event such that it is +the given player's turn, a `ComputeMove` request will be sent to the +NVIDIA Jetson Nano board (tinybrain) over websocket. + +Eventually the tinybrain will respond with a `MoveComputed`, which is +subsequently written to the `bugout-make-move-command` stream, and +processed as a normal by `micro-judge`. diff --git a/botlink/src/env.rs b/botlink/src/env.rs new file mode 100644 index 000000000..c5f9c50ac --- /dev/null +++ b/botlink/src/env.rs @@ -0,0 +1,16 @@ +use std::env; + +const ENV_AUTHORIZATION: &str = "AUTHORIZATION"; // username:password +const ENV_ADDRESS: &str = "ADDRESS"; + +const DEFAULT_ADDRESS: &str = "127.0.0.1:3012"; +lazy_static! { + pub static ref AUTHORIZATION: Option = env::var(ENV_AUTHORIZATION).ok(); + pub static ref ADDRESS: String = env::var(ENV_ADDRESS) + .unwrap_or(DEFAULT_ADDRESS.to_string()) + .to_string(); +} + +pub fn init() { + dotenv::dotenv().ok(); +} diff --git a/botlink/src/lib.rs b/botlink/src/lib.rs new file mode 100644 index 000000000..5d80bacde --- /dev/null +++ b/botlink/src/lib.rs @@ -0,0 +1,18 @@ +#[macro_use] +extern crate lazy_static; +extern crate base64; +extern crate bincode; +extern crate crossbeam; +extern crate crossbeam_channel; +extern crate dotenv; +extern crate env_logger; +extern crate log; +extern crate micro_model_bot; +extern crate micro_model_moves; +extern crate uuid; + +pub mod env; +pub mod registry; +pub mod repo; +pub mod stream; +pub mod websocket; diff --git a/botlink/src/main.rs b/botlink/src/main.rs new file mode 100644 index 000000000..8813e75d1 --- /dev/null +++ b/botlink/src/main.rs @@ -0,0 +1,20 @@ +extern crate botlink; + +use botlink::{stream, websocket}; +use log::info; +use std::thread; +const VERSION: &str = env!("CARGO_PKG_VERSION"); + +use botlink::registry::Components; +fn main() { + env_logger::init(); + botlink::env::init(); + info!("🔢 {}", VERSION); + let components = Components::default(); + let ws_opts = websocket::WSOpts::from(&components); + thread::spawn(move || websocket::listen(ws_opts)); + let mco = components.move_computed_out.clone(); + let xmm = components.xadder_mm.clone(); + thread::spawn(move || stream::write_moves(mco, xmm)); + stream::process(&mut stream::StreamOpts::from(components)); +} diff --git a/botlink/src/registry.rs b/botlink/src/registry.rs new file mode 100644 index 000000000..8f610bd4d --- /dev/null +++ b/botlink/src/registry.rs @@ -0,0 +1,48 @@ +use crate::repo::{AttachedBotsRepo, EntryIdRepo, RedisAttachedBotsRepo, RedisEntryIdRepo}; +use crate::stream::xadd::*; +use crate::stream::xread::{RedisXReader, XReader}; +use crossbeam_channel::{unbounded, Receiver, Sender}; +use micro_model_bot::{ComputeMove, MoveComputed}; +use redis_conn_pool; +use redis_conn_pool::RedisHostUrl; +use std::sync::Arc; + +pub struct Components { + pub game_repo: Box, + pub entry_id_repo: Box, + pub xreader: Box, + pub xadder_gs: Box, + pub xadder_mm: Arc, + pub compute_move_in: Sender, + pub compute_move_out: Receiver, + pub move_computed_in: Sender, + pub move_computed_out: Receiver, +} +impl Default for Components { + fn default() -> Self { + let (compute_move_in, compute_move_out): (Sender, Receiver) = + unbounded(); + + let (move_computed_in, move_computed_out): (Sender, Receiver) = + unbounded(); + + let pool = redis_conn_pool::create(RedisHostUrl::default()); + Components { + game_repo: Box::new(RedisAttachedBotsRepo { + pool: pool.clone(), + key_provider: crate::repo::redis_keys::KeyProvider::default(), + }), + entry_id_repo: Box::new(RedisEntryIdRepo { + pool: pool.clone(), + key_provider: crate::repo::redis_keys::KeyProvider::default(), + }), + xreader: Box::new(RedisXReader { pool: pool.clone() }), + xadder_gs: Box::new(RedisXAdderGS { pool: pool.clone() }), + xadder_mm: Arc::new(RedisXAdderMM { pool }), + compute_move_in, + compute_move_out, + move_computed_in, + move_computed_out, + } + } +} diff --git a/botlink/src/repo/attached_bots.rs b/botlink/src/repo/attached_bots.rs new file mode 100644 index 000000000..4c21a626c --- /dev/null +++ b/botlink/src/repo/attached_bots.rs @@ -0,0 +1,51 @@ +use super::redis_keys::KeyProvider; +use super::RepoErr; +use micro_model_moves::{GameId, Player}; +use redis::Commands; +use redis_conn_pool::{r2d2, r2d2_redis, redis, Pool}; + +pub trait AttachedBotsRepo { + fn is_attached(&self, game_id: &GameId, player: Player) -> Result; + + fn attach(&mut self, game_id: &GameId, player: Player) -> Result<(), RepoErr>; +} + +const TTL_SECS: usize = 86400; + +pub struct RedisAttachedBotsRepo { + pub pool: Pool, + pub key_provider: KeyProvider, +} + +impl AttachedBotsRepo for RedisAttachedBotsRepo { + fn is_attached(&self, game_id: &GameId, player: Player) -> Result { + let mut conn = self.pool.get().expect("pool"); + let result = conn.sismember( + self.key_provider.attached_bots(), + member_value(game_id, player), + )?; + self.expire(&mut conn)?; + Ok(result) + } + + fn attach(&mut self, game_id: &GameId, player: Player) -> Result<(), RepoErr> { + let mut conn = self.pool.get().expect("pool"); + let result = conn.sadd( + self.key_provider.attached_bots(), + member_value(game_id, player), + )?; + self.expire(&mut conn)?; + Ok(result) + } +} +impl RedisAttachedBotsRepo { + fn expire( + &self, + conn: &mut r2d2::PooledConnection, + ) -> Result<(), RepoErr> { + Ok(conn.expire(self.key_provider.attached_bots(), TTL_SECS)?) + } +} +fn member_value(game_id: &GameId, player: Player) -> String { + format!("{}_{}", game_id.0, player.to_string()) +} diff --git a/botlink/src/repo/entry_ids.rs b/botlink/src/repo/entry_ids.rs new file mode 100644 index 000000000..178f3e5f1 --- /dev/null +++ b/botlink/src/repo/entry_ids.rs @@ -0,0 +1,83 @@ +use redis_conn_pool::redis::Commands; +use redis_conn_pool::{redis, Pool}; +use redis_streams::XReadEntryId; +use std::collections::HashMap; +pub trait EntryIdRepo { + fn fetch_all(&self) -> Result; + + fn update( + &self, + entry_id_type: EntryIdType, + entry_id: XReadEntryId, + ) -> Result<(), redis::RedisError>; +} + +pub struct RedisEntryIdRepo { + pub pool: Pool, + pub key_provider: super::redis_keys::KeyProvider, +} +const EMPTY_EID: &str = "0-0"; +impl EntryIdRepo for RedisEntryIdRepo { + fn fetch_all(&self) -> Result { + let mut conn = self.pool.get().expect("pool"); + let found: Result, _> = conn.hgetall(self.key_provider.entry_ids()); + if let Ok(f) = found { + let attach_bot_eid = XReadEntryId::from_str( + &f.get(ATTACH_BOT_EID) + .unwrap_or(&EMPTY_EID.to_string()) + .to_string(), + ) + .unwrap_or(XReadEntryId::default()); + let game_states_eid = XReadEntryId::from_str( + &f.get(GAME_STATES_EID) + .unwrap_or(&EMPTY_EID.to_string()) + .to_string(), + ) + .unwrap_or(XReadEntryId::default()); + Ok(AllEntryIds { + game_states_eid, + attach_bot_eid, + }) + } else { + Ok(AllEntryIds::default()) + } + } + fn update(&self, eid_type: EntryIdType, eid: XReadEntryId) -> Result<(), redis::RedisError> { + let mut conn = self.pool.get().expect("redis pool"); + conn.hset( + self.key_provider.entry_ids(), + eid_type.hash_field(), + eid.to_string(), + ) + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum EntryIdType { + AttachBotEvent, + GameStateChangelog, +} +const GAME_STATES_EID: &str = "game_states_eid"; +const ATTACH_BOT_EID: &str = "attach_bot_eid"; +impl EntryIdType { + pub fn hash_field(&self) -> String { + match self { + EntryIdType::GameStateChangelog => GAME_STATES_EID.to_string(), + EntryIdType::AttachBotEvent => ATTACH_BOT_EID.to_string(), + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct AllEntryIds { + pub attach_bot_eid: XReadEntryId, + pub game_states_eid: XReadEntryId, +} +impl Default for AllEntryIds { + fn default() -> Self { + AllEntryIds { + attach_bot_eid: XReadEntryId::default(), + game_states_eid: XReadEntryId::default(), + } + } +} diff --git a/botlink/src/repo/mod.rs b/botlink/src/repo/mod.rs new file mode 100644 index 000000000..5a52ffc4b --- /dev/null +++ b/botlink/src/repo/mod.rs @@ -0,0 +1,16 @@ +pub mod attached_bots; +pub mod entry_ids; +pub mod redis_keys; + +pub use attached_bots::*; +pub use entry_ids::*; +use redis_conn_pool::redis; +#[derive(Debug)] +pub enum RepoErr { + Redis(redis::RedisError), +} +impl From for RepoErr { + fn from(r: redis::RedisError) -> Self { + RepoErr::Redis(r) + } +} diff --git a/botlink/src/repo/redis_keys.rs b/botlink/src/repo/redis_keys.rs new file mode 100644 index 000000000..13cf94925 --- /dev/null +++ b/botlink/src/repo/redis_keys.rs @@ -0,0 +1,24 @@ +const DEFAULT_NAMESPACE: &str = "BUGOUT"; +#[derive(Clone, Debug)] +pub struct RedisKeyNamespace(pub String); +impl Default for RedisKeyNamespace { + fn default() -> Self { + RedisKeyNamespace(DEFAULT_NAMESPACE.to_string()) + } +} + +#[derive(Debug, Clone)] +pub struct KeyProvider(pub RedisKeyNamespace); +impl Default for KeyProvider { + fn default() -> Self { + KeyProvider(RedisKeyNamespace::default()) + } +} +impl KeyProvider { + pub fn entry_ids(&self) -> String { + format!("/{}/botlink/entry_ids", (self.0).0) + } + pub fn attached_bots(&self) -> String { + format!("/{}/botlink/attached_bots", (self.0).0) + } +} diff --git a/botlink/src/stream/mod.rs b/botlink/src/stream/mod.rs new file mode 100644 index 000000000..565d63a90 --- /dev/null +++ b/botlink/src/stream/mod.rs @@ -0,0 +1,299 @@ +pub mod topics; +mod write_moves; +pub mod xadd; +pub mod xread; + +use crate::registry::Components; +use crate::repo::{AttachedBotsRepo, EntryIdRepo, EntryIdType}; +use crossbeam_channel::Sender; +use log::{error, info}; +use micro_model_bot::gateway::AttachBot; +use micro_model_bot::ComputeMove; +use micro_model_moves::GameState; +pub use write_moves::write_moves; +use xread::StreamData; + +pub fn process(opts: &mut StreamOpts) { + loop { + match opts.entry_id_repo.fetch_all() { + Ok(entry_ids) => match opts.xreader.xread_sorted(entry_ids) { + Ok(xrr) => { + for time_ordered_event in xrr { + match time_ordered_event { + (entry_id, StreamData::AB(AttachBot { game_id, player })) => { + if let Err(e) = opts.attached_bots_repo.attach(&game_id, player) { + error!("Error attaching bot {:?}", e) + } else { + if let Err(e) = opts + .entry_id_repo + .update(EntryIdType::AttachBotEvent, entry_id) + { + error!("Error saving entry ID for attach bot {:?}", e) + } else { + if let Err(e) = opts + .xadder + .xadd_game_state(game_id, GameState::default()) + { + error!("Error writing redis stream for game state changelog : {:?}",e) + } + } + } + } + (entry_id, StreamData::GS(game_id, game_state)) => { + match opts + .attached_bots_repo + .is_attached(&game_id, game_state.player_up) + { + Ok(bot_game) => { + if bot_game { + if let Err(e) = opts.compute_move_in.send(ComputeMove { + game_id, + game_state, + }) { + error!("WS SEND ERROR {:?}", e) + } + } else { + info!( + "Ignoring {:?} {:?}", + game_id, game_state.player_up + ) + }; + if let Err(e) = opts + .entry_id_repo + .update(EntryIdType::GameStateChangelog, entry_id) + { + error!("Failed to save entry ID for game state {:?}", e) + } + } + Err(e) => error!("Game Repo error is_attached {:?}", e), + } + } + } + } + } + Err(e) => error!("Stream error {:?}", e), + }, + Err(e) => error!("Redis err in xread: {:#?}", e), + } + } +} + +pub struct StreamOpts { + pub attached_bots_repo: Box, + pub entry_id_repo: Box, + pub xreader: Box, + pub xadder: Box, + pub compute_move_in: Sender, +} + +impl StreamOpts { + pub fn from(components: Components) -> Self { + StreamOpts { + attached_bots_repo: components.game_repo, + entry_id_repo: components.entry_id_repo, + xreader: components.xreader, + xadder: components.xadder_gs, + compute_move_in: components.compute_move_in, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::repo::*; + use crossbeam_channel::{after, never, select, unbounded, Receiver}; + use micro_model_moves::*; + use redis_streams::XReadEntryId; + use std::sync::atomic::{AtomicU64, Ordering}; + use std::sync::{Arc, Mutex}; + use std::thread; + use std::time::Duration; + use uuid::Uuid; + + #[derive(Clone)] + struct FakeEntryIdRepo { + eid_update_in: Sender<(EntryIdType, XReadEntryId)>, + } + static FAKE_AB_MILLIS: AtomicU64 = AtomicU64::new(0); + static FAKE_AB_SEQNO: AtomicU64 = AtomicU64::new(0); + static FAKE_GS_MILLIS: AtomicU64 = AtomicU64::new(0); + static FAKE_GS_SEQNO: AtomicU64 = AtomicU64::new(0); + impl EntryIdRepo for FakeEntryIdRepo { + fn fetch_all(&self) -> Result { + Ok(AllEntryIds { + attach_bot_eid: XReadEntryId { + millis_time: FAKE_AB_MILLIS.load(Ordering::SeqCst), + seq_no: FAKE_AB_SEQNO.load(Ordering::SeqCst), + }, + game_states_eid: XReadEntryId { + millis_time: FAKE_GS_MILLIS.load(Ordering::SeqCst), + seq_no: FAKE_GS_MILLIS.load(Ordering::SeqCst), + }, + }) + } + fn update( + &self, + entry_id_type: EntryIdType, + entry_id: redis_streams::XReadEntryId, + ) -> Result<(), redis_conn_pool::redis::RedisError> { + self.eid_update_in + .send((entry_id_type.clone(), entry_id)) + .expect("eid update send"); + Ok(match entry_id_type { + EntryIdType::AttachBotEvent => { + FAKE_AB_MILLIS.store(entry_id.millis_time, Ordering::SeqCst); + FAKE_AB_SEQNO.store(entry_id.seq_no, Ordering::SeqCst) + } + EntryIdType::GameStateChangelog => { + FAKE_GS_MILLIS.store(entry_id.millis_time, Ordering::SeqCst); + FAKE_GS_SEQNO.store(entry_id.seq_no, Ordering::SeqCst) + } + }) + } + } + + #[derive(Clone)] + struct FakeAttachedBotsRepo { + pub members: Arc>>, + } + impl AttachedBotsRepo for FakeAttachedBotsRepo { + fn is_attached(&self, game_id: &GameId, player: Player) -> Result { + Ok(self + .members + .lock() + .expect("lock") + .contains(&(game_id.clone(), player))) + } + fn attach(&mut self, game_id: &GameId, player: Player) -> Result<(), RepoErr> { + Ok(self + .members + .lock() + .expect("lock") + .push((game_id.clone(), player))) + } + } + + struct FakeXAdder { + added_in: Sender<(GameId, GameState)>, + } + impl xadd::XAdderGS for FakeXAdder { + fn xadd_game_state( + &self, + game_id: GameId, + game_state: GameState, + ) -> Result<(), crate::stream::xadd::XAddError> { + Ok(self.added_in.send((game_id, game_state)).expect("send add")) + } + } + + struct FakeXReader { + game_id: GameId, + player: Player, + incoming_game_state: Arc>>, + } + impl xread::XReader for FakeXReader { + fn xread_sorted( + &self, + entry_ids: AllEntryIds, + ) -> Result< + Vec<(redis_streams::XReadEntryId, StreamData)>, + redis_conn_pool::redis::RedisError, + > { + let game_id = self.game_id.clone(); + let player = self.player; + let mut v: Vec<(XReadEntryId, StreamData)> = vec![( + XReadEntryId { + millis_time: 10, + seq_no: 0, + }, + StreamData::AB(AttachBot { game_id, player }), + )]; + if let Some((inc_eid, inc_game_state)) = + self.incoming_game_state.lock().expect("xrl").clone() + { + v.push((inc_eid, inc_game_state)); + } + + Ok(v.iter() + .filter(|(eid, data)| { + eid > match data { + StreamData::AB(_) => &entry_ids.attach_bot_eid, + StreamData::GS(_, _) => &entry_ids.game_states_eid, + } + }) + .cloned() + .collect()) + } + } + + #[test] + fn process_test() { + let (compute_move_in, _): (Sender, _) = unbounded(); + let (eid_update_in, eid_update_out) = unbounded(); + let (added_in, added_out): (Sender<(GameId, GameState)>, Receiver<(GameId, GameState)>) = + unbounded(); + + let entry_id_repo = Box::new(FakeEntryIdRepo { eid_update_in }); + + let bots_attached = Arc::new(Mutex::new(vec![])); + let attached_bots_repo = Box::new(FakeAttachedBotsRepo { + members: bots_attached.clone(), + }); + let abr = attached_bots_repo.clone(); + + const GAME_ID: GameId = GameId(Uuid::nil()); + let player = Player::WHITE; + let incoming_game_state = Arc::new(Mutex::new(None)); + let xreader = Box::new(FakeXReader { + game_id: GAME_ID.clone(), + player, + incoming_game_state: incoming_game_state.clone(), + }); + let xadder = Box::new(FakeXAdder { added_in }); + + thread::spawn(move || { + let mut opts = StreamOpts { + compute_move_in, + entry_id_repo, + attached_bots_repo, + xreader, + xadder, + }; + + process(&mut opts) + }); + + // process xadd of game state correctly + thread::spawn(move || loop { + select! { + recv(added_out) -> msg => if let Ok(a) = msg { + let mut data = incoming_game_state.lock().expect("locked gs"); + *data = Some((XReadEntryId{millis_time: 1, seq_no: 0}, StreamData::GS(a.0, a.1))); } + } + }); + + thread::sleep(Duration::from_millis(1)); + assert!(abr.is_attached(&GAME_ID, player).expect("ab repo")); + + let timeoutdur = Some(Duration::from_millis(30)); + + // Create a channel that times out after the specified duration. + let timeout = timeoutdur.map(|d| after(d)).unwrap_or(never()); + let mut eid_updates_observed = vec![]; + select! { + recv(eid_update_out) -> msg => eid_updates_observed.push(msg.expect("msg")), + recv(timeout) -> _ => panic!("unexpected timeout") + } + select! { + recv(eid_update_out) -> msg => eid_updates_observed.push(msg.expect("msg")), + recv(timeout) -> _ => panic!("unexpected timeout 2") + } + + assert!(eid_updates_observed.len() == 2); + assert_eq!(eid_updates_observed[0].0, EntryIdType::AttachBotEvent); + assert!(eid_updates_observed[0].1 > XReadEntryId::default()); + assert_eq!(eid_updates_observed[1].0, EntryIdType::GameStateChangelog); + assert!(eid_updates_observed[1].1 > XReadEntryId::default()); + } +} diff --git a/botlink/src/stream/topics.rs b/botlink/src/stream/topics.rs new file mode 100644 index 000000000..63cd8ec46 --- /dev/null +++ b/botlink/src/stream/topics.rs @@ -0,0 +1,3 @@ +pub const ATTACH_BOT_EV: &str = "bugout-attach-bot-ev"; +pub const GAME_STATES_CHANGELOG: &str = "bugout-game-states"; +pub const MAKE_MOVE_CMD: &str = "bugout-make-move-cmd"; diff --git a/botlink/src/stream/write_moves.rs b/botlink/src/stream/write_moves.rs new file mode 100644 index 000000000..ab594841a --- /dev/null +++ b/botlink/src/stream/write_moves.rs @@ -0,0 +1,15 @@ +use super::xadd::XAdderMM; +use crossbeam_channel::{select, Receiver}; +use log::error; +use micro_model_bot::MoveComputed; +use std::sync::Arc; +pub fn write_moves(move_computed_out: Receiver, xadder: Arc) { + loop { + select! { + recv(move_computed_out) -> msg => match msg { + Ok(MoveComputed(command)) => if let Err(e)=xadder.xadd_make_move_command(command) {error!("could not xadd move command : {:?}",e)}, + Err(e) => error!("Unable to receive move computed out {:?}",e) + } + } + } +} diff --git a/botlink/src/stream/xadd.rs b/botlink/src/stream/xadd.rs new file mode 100644 index 000000000..a5b7c5154 --- /dev/null +++ b/botlink/src/stream/xadd.rs @@ -0,0 +1,77 @@ +use crate::stream::topics; +use micro_model_moves::{Coord, GameId, GameState, MakeMoveCommand}; +use redis_conn_pool::redis::RedisError; +use redis_conn_pool::{redis, Pool}; +pub trait XAdderGS { + fn xadd_game_state(&self, game_id: GameId, game_state: GameState) -> Result<(), XAddError>; +} + +pub trait XAdderMM: Send + Sync { + fn xadd_make_move_command(&self, command: MakeMoveCommand) -> Result<(), XAddError>; +} + +#[derive(Debug)] +pub enum XAddError { + Redis(RedisError), + Ser(Box), +} + +pub struct RedisXAdderGS { + pub pool: Pool, +} +impl XAdderGS for RedisXAdderGS { + fn xadd_game_state(&self, game_id: GameId, game_state: GameState) -> Result<(), XAddError> { + let mut conn = self.pool.get().expect("redis pool"); + redis::cmd("XADD") + .arg(topics::GAME_STATES_CHANGELOG) + .arg("MAXLEN") + .arg("~") + .arg("1000") + .arg("*") + .arg("game_id") + .arg(game_id.0.to_string()) + .arg("data") + .arg(game_state.serialize()?) + .query::(&mut *conn)?; + Ok(()) + } +} + +pub struct RedisXAdderMM { + pub pool: Pool, +} +impl XAdderMM for RedisXAdderMM { + fn xadd_make_move_command(&self, command: MakeMoveCommand) -> Result<(), XAddError> { + let mut conn = self.pool.get().unwrap(); + + let mut redis_cmd = redis::cmd("XADD"); + redis_cmd + .arg(topics::MAKE_MOVE_CMD) + .arg("MAXLEN") + .arg("~") + .arg("1000") + .arg("*") + .arg("game_id") + .arg(command.game_id.0.to_string()) + .arg("player") + .arg(command.player.to_string()) + .arg("req_id") + .arg(command.req_id.0.to_string()); + if let Some(Coord { x, y }) = command.coord { + redis_cmd.arg("coord_x").arg(x).arg("coord_y").arg(y); + } + redis_cmd.query::(&mut *conn)?; + Ok(()) + } +} + +impl From for XAddError { + fn from(r: RedisError) -> Self { + XAddError::Redis(r) + } +} +impl From> for XAddError { + fn from(b: Box) -> Self { + XAddError::Ser(b) + } +} diff --git a/botlink/src/stream/xread.rs b/botlink/src/stream/xread.rs new file mode 100644 index 000000000..c78a4ee5e --- /dev/null +++ b/botlink/src/stream/xread.rs @@ -0,0 +1,119 @@ +use super::topics; +use crate::repo::AllEntryIds; +use log::warn; +use micro_model_bot::gateway::AttachBot; +use micro_model_moves::{GameId, GameState}; +use redis_conn_pool::redis; +use redis_conn_pool::Pool; +use redis_streams::XReadEntryId; +use std::collections::HashMap; +use std::str::FromStr; +use uuid::Uuid; + +const BLOCK_MSEC: u32 = 5000; + +pub type XReadResult = Vec>>>; + +/// xread_sorted performs a redis xread then sorts the results +/// +/// entry_ids: the minimum entry ids from which to read +pub trait XReader { + fn xread_sorted( + &self, + entry_ids: AllEntryIds, + ) -> Result, redis::RedisError>; +} + +pub struct RedisXReader { + pub pool: Pool, +} +impl XReader for RedisXReader { + fn xread_sorted( + &self, + entry_ids: AllEntryIds, + ) -> Result, redis::RedisError> { + let mut conn = self.pool.get().unwrap(); + let xrr = redis::cmd("XREAD") + .arg("BLOCK") + .arg(&BLOCK_MSEC.to_string()) + .arg("STREAMS") + .arg(topics::ATTACH_BOT_EV) + .arg(topics::GAME_STATES_CHANGELOG) + .arg(entry_ids.attach_bot_eid.to_string()) + .arg(entry_ids.game_states_eid.to_string()) + .query::(&mut *conn)?; + let unsorted = deser(xrr); + let sorted_keys: Vec = { + let mut ks: Vec = unsorted.keys().map(|k| *k).collect(); + ks.sort(); + ks + }; + let mut answer = vec![]; + for sk in sorted_keys { + if let Some(data) = unsorted.get(&sk) { + answer.push((sk, data.clone())) + } + } + Ok(answer) + } +} + +#[derive(Clone, Debug)] +pub enum StreamData { + AB(AttachBot), + GS(GameId, GameState), +} + +fn deser(xread_result: XReadResult) -> HashMap { + let mut stream_data = HashMap::new(); + + for hash in xread_result.iter() { + for (xread_topic, xread_data) in hash.iter() { + if &xread_topic[..] == topics::GAME_STATES_CHANGELOG { + for with_timestamps in xread_data { + for (k, v) in with_timestamps { + let shape: Result<(String, String, String, Option>), _> = // game-id data + redis::FromRedisValue::from_redis_value(&v); + if let Ok(s) = shape { + if let (Ok(seq_no), Some(game_id), Some(game_state)) = ( + XReadEntryId::from_str(k), + Uuid::from_str(&s.1).ok(), + s.3.clone().and_then(|bytes| GameState::from(&bytes).ok()), + ) { + stream_data + .insert(seq_no, StreamData::GS(GameId(game_id), game_state)); + } else { + warn!("Xread: Deser error around game states data") + } + } else { + warn!("Fail XREAD") + } + } + } + } else if &xread_topic[..] == topics::ATTACH_BOT_EV { + for with_timestamps in xread_data { + for (k, v) in with_timestamps { + let shape: Result<(String, Vec), _> = // data + redis::FromRedisValue::from_redis_value(&v); + if let Ok(s) = shape { + if let (Ok(seq_no), Some(command)) = ( + XReadEntryId::from_str(k), + AttachBot::from(&s.1.clone()).ok(), + ) { + stream_data.insert(seq_no, StreamData::AB(command)); + } else { + warn!("fail attach bot xread 0") + } + } else { + warn!("Fail attach bot XREAD 1") + } + } + } + } else { + warn!("Ignoring topic {}", &xread_topic[..]) + } + } + } + + stream_data +} diff --git a/botlink/src/websocket.rs b/botlink/src/websocket.rs new file mode 100644 index 000000000..2c869855a --- /dev/null +++ b/botlink/src/websocket.rs @@ -0,0 +1,84 @@ +use crate::env; +use bincode::{deserialize, serialize}; +use crossbeam_channel::{select, Receiver, Sender}; +use log::{info, error, warn}; +use micro_model_bot::{ComputeMove, MoveComputed}; +use std::net::TcpListener; +use std::thread; +use std::time::Duration; +use tungstenite::accept_hdr; +use tungstenite::handshake::server::{Request, Response}; +use tungstenite::http; +use tungstenite::util::NonBlockingResult; +use tungstenite::Message; + +pub fn listen(opts: WSOpts) { + let server = TcpListener::bind(&*env::ADDRESS).expect("WS bind"); + info!("WS bound to {}", &*env::ADDRESS); + + for stream in server.incoming() { + let move_computed_in = opts.move_computed_in.clone(); + let compute_move_out = opts.compute_move_out.clone(); + thread::spawn(move || { + let callback = |req: &Request, response: Response| { + if let Some(user_colon_pass) = &*env::AUTHORIZATION { + let mut is_authorized = false; + for (ref header, value) in req.headers() { + if **header == "Authorization" { + // see https://en.wikipedia.org/wiki/Basic_access_authentication + is_authorized = + *value == format!("Basic {}", base64::encode(user_colon_pass)) + } + } + if is_authorized { + Ok(response) + } else { + warn!("No Auth"); + Err(http::response::Builder::new() + .status(401) + .body(None) + .expect("cannot form response")) + } + } else { + Ok(response) + } + }; + let mut websocket = accept_hdr(stream.expect("stream"), callback).expect("websocket"); + loop { + select! { + recv(compute_move_out) -> msg => match msg { + Ok(cm) => { + let msg = Message::Binary(serialize(&cm).expect("bincode ser")); + websocket + .write_message(msg) + .expect("ws write") + }, + Err(e) => error!("error receiving cm {:?}",e) + }, + default(Duration::from_millis(10)) => { + while let Some(Message::Binary(data)) = websocket.read_message().no_block().expect("read no block") { + let move_computed: MoveComputed = + deserialize(&data).expect("bincode deser"); + if let Err(e) = move_computed_in.send(move_computed) { + error!("mc send err {:?}",e) + } + } + }, + } + } + }); + } +} + +pub struct WSOpts { + pub compute_move_out: Receiver, + pub move_computed_in: Sender, +} +impl WSOpts { + pub fn from(c: &crate::registry::Components) -> Self { + WSOpts { + compute_move_out: c.compute_move_out.clone(), + move_computed_in: c.move_computed_in.clone(), + } + } +} diff --git a/build-all-dc.sh b/build-all-dc.sh deleted file mode 100755 index bc1866ce3..000000000 --- a/build-all-dc.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -alias docker-compose='docker run --rm \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v "$PWD:/rootfs/$PWD" \ - -w="/rootfs/$PWD" \ -docker/compose:1.13.0' - -# This script is useful for environments where you -# do not have access to cargo, gradle etc -docker-compose build judge -docker-compose build changelog -docker-compose build history-provider -docker-compose build game-lobby -docker-compose build color-chooser -docker-compose build gateway -docker-compose build startup -docker-compose build reaper -docker-compose build bugle -docker-compose build kafkacat -docker-compose build micro-judge -docker-compose build micro-changelog diff --git a/build-giant-dc.sh b/build-giant-dc.sh index 960bdf227..03178ce02 100755 --- a/build-giant-dc.sh +++ b/build-giant-dc.sh @@ -1,5 +1,12 @@ #!/bin/bash +alias docker-compose='docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$PWD:/rootfs/$PWD" \ + -w="/rootfs/$PWD" \ +docker/compose:1.13.0' + + docker-compose -f dc-giant.yml build judge docker-compose -f dc-giant.yml build changelog docker-compose -f dc-giant.yml build game-lobby diff --git a/build-tiny-dc.sh b/build-tiny-dc.sh index 14481588b..65cc4e275 100755 --- a/build-tiny-dc.sh +++ b/build-tiny-dc.sh @@ -1,6 +1,14 @@ #!/bin/bash +alias docker-compose='docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$PWD:/rootfs/$PWD" \ + -w="/rootfs/$PWD" \ +docker/compose:1.13.0' + + docker-compose -f dc-tiny.yml build gateway docker-compose -f dc-tiny.yml build micro-judge docker-compose -f dc-tiny.yml build micro-changelog docker-compose -f dc-tiny.yml build bugle +docker-compose -f dc-tiny.yml build botlink diff --git a/dc-tiny.yml b/dc-tiny.yml index 015a223dd..20bf0baf2 100644 --- a/dc-tiny.yml +++ b/dc-tiny.yml @@ -32,14 +32,6 @@ services: - AWS_REGION - DISABLED - TAG_NAME - reverse-proxy: - image: abiosoft/caddy - ports: - - "80:80" - - "443:443" - volumes: - - /mnt/stateful_partition/BUGOUT/reverse-proxy/Caddyfile:/etc/Caddyfile - - /mnt/stateful_partition/BUGOUT/reverse-proxy/.caddy:/root/.caddy micro-judge: build: micro-judge/. links: @@ -52,3 +44,20 @@ services: - "redis" depends_on: - "redis" + botlink: + build: botlink/. + depends_on: + - "redis" + volumes: + - "./botlink/.env:/var/BUGOUT/botlink/.env" + reverse-proxy: + image: abiosoft/caddy + ports: + - "80:80" + - "443:443" + depends_on: + - "botlink" + - "gateway" + volumes: + - /mnt/stateful_partition/BUGOUT/reverse-proxy/Caddyfile:/etc/Caddyfile + - /mnt/stateful_partition/BUGOUT/reverse-proxy/.caddy:/root/.caddy \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2543bfa1a..567e3d197 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,14 +58,6 @@ services: - "kafka" depends_on: - "kafka" - reverse-proxy: - image: abiosoft/caddy - ports: - - "80:80" - - "443:443" - volumes: - - /mnt/stateful_partition/BUGOUT/reverse-proxy/Caddyfile:/etc/Caddyfile - - /mnt/stateful_partition/BUGOUT/reverse-proxy/.caddy:/root/.caddy changelog: build: changelog/. links: @@ -132,3 +124,20 @@ services: - "redis" depends_on: - "redis" + botlink: + build: botlink/. + depends_on: + - "redis" + volumes: + - "./botlink/.env:/var/BUGOUT/botlink/.env" + reverse-proxy: + image: abiosoft/caddy + ports: + - "80:80" + - "443:443" + depends_on: + - "botlink" + - "gateway" + volumes: + - /mnt/stateful_partition/BUGOUT/reverse-proxy/Caddyfile:/etc/Caddyfile + - /mnt/stateful_partition/BUGOUT/reverse-proxy/.caddy:/root/.caddy \ No newline at end of file diff --git a/reverse-proxy/Caddyfile.example.dev b/reverse-proxy/Caddyfile.example.dev index 841430450..4bbfc68b8 100644 --- a/reverse-proxy/Caddyfile.example.dev +++ b/reverse-proxy/Caddyfile.example.dev @@ -3,3 +3,7 @@ localhost proxy /gateway gateway:3012 { websocket } + +proxy /botlink botlink:3012 { + websocket +} diff --git a/reverse-proxy/Caddyfile.example.prod b/reverse-proxy/Caddyfile.example.prod index 79e6916ef..62b101b05 100644 --- a/reverse-proxy/Caddyfile.example.prod +++ b/reverse-proxy/Caddyfile.example.prod @@ -3,3 +3,7 @@ https://your.host.here proxy /gateway gateway:3012 { websocket } + +proxy /botlink botlink:3012 { + websocket +} diff --git a/tinybrain/README.md b/tinybrain/README.md index 139a3ab94..70d049443 100644 --- a/tinybrain/README.md +++ b/tinybrain/README.md @@ -2,6 +2,13 @@ We successfully built and ran KataGo on an [NVIDIA Jetson Nano developer board](https://developer.nvidia.com/embedded/jetson-nano-developer-kit). Here's how. +## Running + +```sh +cargo install --path . +target/release/tinybrain +``` + ## Prereq: Set up the Jetson Nano [You can follow the NVIDIA guide](https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit). diff --git a/tinybrain/Dockerfile b/tinybrain/dockerfail/Dockerfile similarity index 85% rename from tinybrain/Dockerfile rename to tinybrain/dockerfail/Dockerfile index e5ea764f3..24039b78f 100644 --- a/tinybrain/Dockerfile +++ b/tinybrain/dockerfail/Dockerfile @@ -1,3 +1,8 @@ +### THIS DOESN'T WORK +### but you could probably salvage it +### after moving it into the parent directory + + FROM rust AS builder WORKDIR /var/BUGOUT COPY src src diff --git a/tinybrain/build.sh b/tinybrain/dockerfail/build.sh similarity index 100% rename from tinybrain/build.sh rename to tinybrain/dockerfail/build.sh diff --git a/tinybrain/run.sh b/tinybrain/dockerfail/run.sh similarity index 100% rename from tinybrain/run.sh rename to tinybrain/dockerfail/run.sh