From da326594781f5d09510fda79e5c1d3521ec1ca47 Mon Sep 17 00:00:00 2001 From: Christopher Dietz Date: Sat, 1 Jun 2024 14:41:33 -0700 Subject: [PATCH 1/4] New frontend web client written using Rust and Yew.rs (#459) Adds a new web client runner built from the ground up using rust and yew.rs. Part of #261 Right now web client must be manually built and launched separate to launching the backend. A followup PR will add a new flag to tell runner to use the new web client. Both the old and new client will be supported until the new front end has been thoroughly tested and has feature parity. --------- Co-authored-by: Julien Cretin --- .../runner-host/crates/web-client/.gitignore | 1 + .../runner-host/crates/web-client/Cargo.lock | 1199 +++++++++++++++++ .../runner-host/crates/web-client/Cargo.toml | 22 + .../runner-host/crates/web-client/README.md | 28 + .../data/components/button_pressed.svg | 21 + .../data/components/button_unpressed.svg | 20 + .../data/components/monochrome_led_off.svg | 14 + .../data/components/monochrome_led_on.svg | 18 + .../crates/web-client/data/favicon.png | Bin 0 -> 6076 bytes .../crates/web-client/data/index.scss | 32 + .../crates/web-client/data/manifest.json | 15 + .../runner-host/crates/web-client/index.html | 18 + .../runner-host/crates/web-client/src/app.rs | 68 + .../crates/web-client/src/board.rs | 61 + .../crates/web-client/src/board_components.rs | 16 + .../web-client/src/board_components/button.rs | 77 ++ .../web-client/src/board_components/led.rs | 58 + .../crates/web-client/src/console.rs | 74 + .../crates/web-client/src/hooks.rs | 59 + .../runner-host/crates/web-client/src/main.rs | 26 + crates/runner-host/crates/web-client/test.sh | 22 + scripts/ci-copyright.sh | 2 +- 22 files changed, 1850 insertions(+), 1 deletion(-) create mode 100644 crates/runner-host/crates/web-client/.gitignore create mode 100644 crates/runner-host/crates/web-client/Cargo.lock create mode 100644 crates/runner-host/crates/web-client/Cargo.toml create mode 100644 crates/runner-host/crates/web-client/README.md create mode 100644 crates/runner-host/crates/web-client/data/components/button_pressed.svg create mode 100644 crates/runner-host/crates/web-client/data/components/button_unpressed.svg create mode 100644 crates/runner-host/crates/web-client/data/components/monochrome_led_off.svg create mode 100644 crates/runner-host/crates/web-client/data/components/monochrome_led_on.svg create mode 100644 crates/runner-host/crates/web-client/data/favicon.png create mode 100644 crates/runner-host/crates/web-client/data/index.scss create mode 100644 crates/runner-host/crates/web-client/data/manifest.json create mode 100644 crates/runner-host/crates/web-client/index.html create mode 100644 crates/runner-host/crates/web-client/src/app.rs create mode 100644 crates/runner-host/crates/web-client/src/board.rs create mode 100644 crates/runner-host/crates/web-client/src/board_components.rs create mode 100644 crates/runner-host/crates/web-client/src/board_components/button.rs create mode 100644 crates/runner-host/crates/web-client/src/board_components/led.rs create mode 100644 crates/runner-host/crates/web-client/src/console.rs create mode 100644 crates/runner-host/crates/web-client/src/hooks.rs create mode 100644 crates/runner-host/crates/web-client/src/main.rs create mode 100755 crates/runner-host/crates/web-client/test.sh diff --git a/crates/runner-host/crates/web-client/.gitignore b/crates/runner-host/crates/web-client/.gitignore new file mode 100644 index 00000000..178135c2 --- /dev/null +++ b/crates/runner-host/crates/web-client/.gitignore @@ -0,0 +1 @@ +/dist/ diff --git a/crates/runner-host/crates/web-client/Cargo.lock b/crates/runner-host/crates/web-client/Cargo.lock new file mode 100644 index 00000000..c0cac133 --- /dev/null +++ b/crates/runner-host/crates/web-client/Cargo.lock @@ -0,0 +1,1199 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "boolinator" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gloo" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" +dependencies = [ + "gloo-console 0.2.3", + "gloo-dialogs 0.1.1", + "gloo-events 0.1.2", + "gloo-file 0.2.3", + "gloo-history 0.1.5", + "gloo-net 0.3.1", + "gloo-render 0.1.1", + "gloo-storage 0.2.2", + "gloo-timers 0.2.6", + "gloo-utils 0.1.7", + "gloo-worker 0.2.1", +] + +[[package]] +name = "gloo" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249" +dependencies = [ + "gloo-console 0.3.0", + "gloo-dialogs 0.2.0", + "gloo-events 0.2.0", + "gloo-file 0.3.0", + "gloo-history 0.2.2", + "gloo-net 0.4.0", + "gloo-render 0.2.0", + "gloo-storage 0.3.0", + "gloo-timers 0.3.0", + "gloo-utils 0.2.0", + "gloo-worker 0.4.0", +] + +[[package]] +name = "gloo-console" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" +dependencies = [ + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-console" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261" +dependencies = [ + "gloo-utils 0.2.0", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-dialogs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-dialogs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-events" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-events" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" +dependencies = [ + "gloo-events 0.1.2", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f" +dependencies = [ + "gloo-events 0.2.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" +dependencies = [ + "gloo-events 0.1.2", + "gloo-utils 0.1.7", + "serde", + "serde-wasm-bindgen 0.5.0", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6" +dependencies = [ + "getrandom", + "gloo-events 0.2.0", + "gloo-utils 0.2.0", + "serde", + "serde-wasm-bindgen 0.6.5", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.1.7", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.2.0", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-render" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-render" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" +dependencies = [ + "gloo-utils 0.1.7", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils 0.2.0", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-worker" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" +dependencies = [ + "anymap2", + "bincode", + "gloo-console 0.2.3", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-worker" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" +dependencies = [ + "bincode", + "futures", + "gloo-utils 0.2.0", + "gloo-worker-macros", + "js-sys", + "pinned", + "serde", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-worker-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "implicit-clone" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a9aa791c7b5a71b636b7a68207fdebf171ddfc593d9c8506ec4cbc527b6a84" +dependencies = [ + "implicit-clone-derive", + "indexmap", +] + +[[package]] +name = "implicit-clone-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" +dependencies = [ + "quote", + "syn 2.0.55", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pinned" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" +dependencies = [ + "futures", + "rustversion", + "thiserror", +] + +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn 2.0.55", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prokio" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" +dependencies = [ + "futures", + "gloo 0.8.1", + "num_cpus", + "once_cell", + "pin-project", + "pinned", + "tokio", + "tokio-stream", + "wasm-bindgen-futures", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "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 = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "pin-project-lite", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.55", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" +dependencies = [ + "log", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "web-client" +version = "0.1.0" +dependencies = [ + "log", + "serde_json", + "wasm-bindgen", + "wasm-logger", + "web-common", + "web-sys", + "yew", + "yew-hooks", +] + +[[package]] +name = "web-common" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "yew" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac" +dependencies = [ + "console_error_panic_hook", + "futures", + "gloo 0.10.0", + "implicit-clone", + "indexmap", + "js-sys", + "prokio", + "rustversion", + "serde", + "slab", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro", +] + +[[package]] +name = "yew-hooks" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6f2fe60864adbcc36f1d51f748a186f56f99857c55521d4c9ec1c6e4a0d0a9" +dependencies = [ + "gloo 0.10.0", + "js-sys", + "log", + "serde", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew", +] + +[[package]] +name = "yew-macro" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2" +dependencies = [ + "boolinator", + "once_cell", + "prettyplease", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.55", +] diff --git a/crates/runner-host/crates/web-client/Cargo.toml b/crates/runner-host/crates/web-client/Cargo.toml new file mode 100644 index 00000000..f98342a4 --- /dev/null +++ b/crates/runner-host/crates/web-client/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "web-client" +version = "0.1.0" +authors = ["csdietz@google.com"] +license = "Apache-2.0" +publish = false +edition = "2021" + +[dependencies] +log = "0.4.21" +serde_json = "1.0.111" +wasm-bindgen = "0.2.92" +wasm-logger = "0.2.0" +web-common = { path = "../web-common" } +web-sys = "0.3.69" +yew = { version = "0.21", features = ["csr"] } +yew-hooks = "0.3.1" + +[lints] +clippy.unit-arg = "allow" +rust.unsafe-op-in-unsafe-fn = "warn" +rust.unused-crate-dependencies = "warn" diff --git a/crates/runner-host/crates/web-client/README.md b/crates/runner-host/crates/web-client/README.md new file mode 100644 index 00000000..1cc754df --- /dev/null +++ b/crates/runner-host/crates/web-client/README.md @@ -0,0 +1,28 @@ +# Wasefire Web Client + +This is a fairly minimal web app for interacting with the runner that's built +with [Yew](https://yew.rs) and [Trunk](https://trunkrs.dev/). + +## Running + +```bash +trunk serve +``` + +Rebuilds the app whenever a change is detected and runs a local server +to host it. + +There's also the `trunk watch` command which does the same thing but without +hosting it. + +## Release + +```bash +trunk build --release +``` + +This builds the app in release mode similar to `cargo build --release`. +You can also pass the `--release` flag to `trunk serve` if you need to get +every last drop of performance. + +Unless overwritten, the output will be located in the `dist` directory. diff --git a/crates/runner-host/crates/web-client/data/components/button_pressed.svg b/crates/runner-host/crates/web-client/data/components/button_pressed.svg new file mode 100644 index 00000000..ae559d07 --- /dev/null +++ b/crates/runner-host/crates/web-client/data/components/button_pressed.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/data/components/button_unpressed.svg b/crates/runner-host/crates/web-client/data/components/button_unpressed.svg new file mode 100644 index 00000000..c5906eb6 --- /dev/null +++ b/crates/runner-host/crates/web-client/data/components/button_unpressed.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/data/components/monochrome_led_off.svg b/crates/runner-host/crates/web-client/data/components/monochrome_led_off.svg new file mode 100644 index 00000000..f1b0768e --- /dev/null +++ b/crates/runner-host/crates/web-client/data/components/monochrome_led_off.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/data/components/monochrome_led_on.svg b/crates/runner-host/crates/web-client/data/components/monochrome_led_on.svg new file mode 100644 index 00000000..ed17a10c --- /dev/null +++ b/crates/runner-host/crates/web-client/data/components/monochrome_led_on.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/data/favicon.png b/crates/runner-host/crates/web-client/data/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca3e6b47ccb1a1dee75fbd13474dec7f612c905 GIT binary patch literal 6076 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 c7C!z}6{MZgW*L!&sd`n9DFTOC8+yDRo literal 0 HcmV?d00001 diff --git a/crates/runner-host/crates/web-client/data/index.scss b/crates/runner-host/crates/web-client/data/index.scss new file mode 100644 index 00000000..34d746d4 --- /dev/null +++ b/crates/runner-host/crates/web-client/data/index.scss @@ -0,0 +1,32 @@ +/* Scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: rgb(12, 74, 19) rgb(10, 10, 10); +} + +*::-webkit-scrollbar { + width: 12px; +} + +*::-webkit-scrollbar-track { + background: rgba(10, 10, 10, .9); +} + +*::-webkit-scrollbar-thumb { + background-color: blue; + border-radius: 20px; + border: 3px solid rgb(12, 74, 19); +} + +svg { + pointer-events: none; +} + +.button { + user-drag: none; + -webkit-user-drag: none; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} diff --git a/crates/runner-host/crates/web-client/data/manifest.json b/crates/runner-host/crates/web-client/data/manifest.json new file mode 100644 index 00000000..e662edaf --- /dev/null +++ b/crates/runner-host/crates/web-client/data/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Wasefire", + "name": "Wasefire web UI", + "icons": [ + { + "src": "/favicon.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "start_url": "/", + "theme_color": "#337E36", + "background_color": "#fff", + "display": "standalone" +} diff --git a/crates/runner-host/crates/web-client/index.html b/crates/runner-host/crates/web-client/index.html new file mode 100644 index 00000000..9778dcf7 --- /dev/null +++ b/crates/runner-host/crates/web-client/index.html @@ -0,0 +1,18 @@ + + + + Wasefire + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/src/app.rs b/crates/runner-host/crates/web-client/src/app.rs new file mode 100644 index 00000000..8ed799a9 --- /dev/null +++ b/crates/runner-host/crates/web-client/src/app.rs @@ -0,0 +1,68 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::{info, warn}; +use web_common::{Command, Event}; +use yew::prelude::*; + +use crate::board::Board; +use crate::console::Console; +use crate::hooks::use_runner_connection; + +#[function_component(App)] +pub fn app() -> Html { + let runner_connection = use_runner_connection(String::from("ws://127.0.0.1:5000/board")); + + let on_new_console_msg = Callback::from({ + let runner_connection = runner_connection.clone(); + move |msg: String| runner_connection.send_console_event(msg) + }); + + let on_board_ready = Callback::from({ + let runner_connection = runner_connection.clone(); + move |()| runner_connection.send_board_ready() + }); + + let send_event_callback = Callback::from({ + let runner_connection = runner_connection.clone(); + move |event: Event| runner_connection.send_event(event) + }); + + use_effect_with(runner_connection.command_state.clone(), move |command_state| { + if let Some(command) = &**command_state { + info!("Command: {command:?}"); + match command { + Command::Connected => info!("Connected to runner"), + Command::Disconnected => warn!("Disconnected from runner"), + _ => (), // Command for other component so ignoring. + } + } + || () + }); + + html! { +
+ + +
+ } +} diff --git a/crates/runner-host/crates/web-client/src/board.rs b/crates/runner-host/crates/web-client/src/board.rs new file mode 100644 index 00000000..265c7a3c --- /dev/null +++ b/crates/runner-host/crates/web-client/src/board.rs @@ -0,0 +1,61 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::info; +use web_common::{Command, Component, Event}; +use yew::prelude::*; +use yew::{function_component, html, Html, Properties}; + +use crate::board_components::button::Button; +use crate::board_components::led::LED; + +#[derive(Properties, PartialEq)] +pub struct Props { + pub command_state: UseStateHandle>, + pub on_board_ready: Callback<()>, + pub on_event: Callback, +} + +#[function_component] +pub fn Board(Props { command_state, on_board_ready, on_event }: &Props) -> Html { + let board_config = use_state(|| None); + + use_effect_with(command_state.clone(), { + let board_config = board_config.clone(); + let on_board_ready = on_board_ready.clone(); + move |command_state| { + if let Some(Command::BoardConfig { components }) = &**command_state { + info!("Board config: {components:?}"); + board_config.set(Some(components.clone())); + on_board_ready.emit(()); + } + || () + } + }); + + return html! { +
{ + if let Some(board_config) = &*board_config { + board_config.iter().map(|component| match component { + Component::Button{id} => html!(
+ }; +} diff --git a/crates/runner-host/crates/web-client/src/board_components.rs b/crates/runner-host/crates/web-client/src/board_components.rs new file mode 100644 index 00000000..f0e88b2f --- /dev/null +++ b/crates/runner-host/crates/web-client/src/board_components.rs @@ -0,0 +1,16 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod button; +pub mod led; diff --git a/crates/runner-host/crates/web-client/src/board_components/button.rs b/crates/runner-host/crates/web-client/src/board_components/button.rs new file mode 100644 index 00000000..942c3f15 --- /dev/null +++ b/crates/runner-host/crates/web-client/src/board_components/button.rs @@ -0,0 +1,77 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::info; +use web_common::{ButtonState, Event}; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +pub struct Props { + #[prop_or_default] + pub id: usize, + pub on_event: Callback, +} + +#[function_component] +pub fn Button(Props { id, on_event }: &Props) -> Html { + let id = *id; + let pressed = use_state(|| false); + let press = Callback::from({ + let pressed = pressed.clone(); + let on_event = on_event.clone(); + move |_| { + info!("Pressed button id: {id}"); + pressed.set(true); + on_event.emit(Event::Button { component_id: id, state: ButtonState::Pressed }); + } + }); + + let unpress = Callback::from({ + let pressed = pressed.clone(); + let on_event = on_event.clone(); + move |_| { + info!("Unpressed button id: {id}"); + // Necessary because it may also be triggered when the mouse stops hovering over the + // button. + if *pressed { + pressed.set(false); + on_event.emit(Event::Button { component_id: id, state: ButtonState::Released }); + } + } + }); + + return html! { +
+ + +
+ }; +} diff --git a/crates/runner-host/crates/web-client/src/board_components/led.rs b/crates/runner-host/crates/web-client/src/board_components/led.rs new file mode 100644 index 00000000..31f46e8f --- /dev/null +++ b/crates/runner-host/crates/web-client/src/board_components/led.rs @@ -0,0 +1,58 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::info; +use web_common::Command; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +pub struct Props { + #[prop_or_default] + pub id: usize, + pub command_state: UseStateHandle>, +} + +#[function_component] +pub fn LED(Props { id, command_state }: &Props) -> Html { + let id = *id; + let lit = use_state(|| false); + let command_state = command_state.clone(); + use_effect_with(command_state, { + let lit = lit.clone(); + move |command_state| { + if let Some(Command::Set { component_id, state }) = &**command_state { + if *component_id == id { + info!("Set command: component_id: {component_id} state: {state}"); + lit.set(*state); + } + } + } + }); + + return html! { +
+ + + + }; +} diff --git a/crates/runner-host/crates/web-client/src/console.rs b/crates/runner-host/crates/web-client/src/console.rs new file mode 100644 index 00000000..dbf570ed --- /dev/null +++ b/crates/runner-host/crates/web-client/src/console.rs @@ -0,0 +1,74 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::info; +use wasm_bindgen::JsCast; +use web_common::Command; +use web_sys::HtmlInputElement; +use yew::prelude::*; +use yew_hooks::prelude::*; + +#[derive(Properties, PartialEq)] + +pub struct Props { + #[prop_or_default] + pub id: usize, + pub command_state: UseStateHandle>, + pub on_new_console_msg: Callback, +} +#[function_component(Console)] +pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html { + let history = use_list(vec![]); + let console_ref = use_node_ref(); + + let onsubmit = Callback::from({ + let history = history.clone(); + let console_ref = console_ref.clone(); + let on_new_console_msg = on_new_console_msg.clone(); + move |e: SubmitEvent| { + e.prevent_default(); + let input_form: HtmlInputElement = + console_ref.get().unwrap().value_of().dyn_into().unwrap(); + let value = input_form.value(); + info!("sending console message: {value}"); + history.push(format!("[send]: {value}")); + on_new_console_msg.emit(value); + input_form.set_value(""); + } + }); + + use_effect_with(command_state.clone(), { + let history = history.clone(); + move |command_state| { + if let Some(command) = &**command_state { + info!("Command: {command:?}"); + if let Command::Log { message } = command { + history.push(format!("[recv]: {message}")); + } + } + || () + } + }); + + html! { +
+

{ "Log history: " }

+ { for history.current().iter().map(|message| html!(

{ message }

)) } +
+ + +
+
+ } +} diff --git a/crates/runner-host/crates/web-client/src/hooks.rs b/crates/runner-host/crates/web-client/src/hooks.rs new file mode 100644 index 00000000..6d3c19bc --- /dev/null +++ b/crates/runner-host/crates/web-client/src/hooks.rs @@ -0,0 +1,59 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use log::{info, warn}; +use web_common::{Command, Event}; +use yew::prelude::*; +use yew_hooks::prelude::*; + +#[derive(Clone)] +pub struct UseRunnerConnectionHandle { + pub ws: UseWebSocketHandle, + pub command_state: UseStateHandle>, +} + +impl UseRunnerConnectionHandle { + pub fn send_console_event(&self, console_msg: String) { + warn!("Backend processing of console input not yet implemented."); + warn!("Ignoring message: {console_msg}"); + } + pub fn send_board_ready(&self) { + let command = Event::BoardReady; + self.ws.send(serde_json::to_string(&command).unwrap()); + } + pub fn send_event(&self, event: Event) { + self.ws.send(serde_json::to_string(&event).unwrap()); + } +} + +#[hook] +pub fn use_runner_connection(backend_address: String) -> UseRunnerConnectionHandle { + let ws = use_websocket(backend_address.clone()); + let command_state = use_state(|| None); + // Receive message by depending on `ws.message`. + use_effect_with(ws.message.clone(), { + let command_state = command_state.clone(); + move |message| { + if let Some(message) = &**message { + info!("Message: {message}"); + match serde_json::from_str::(message) { + Ok(command) => command_state.set(Some(command)), + Err(err) => warn!("Error parsing message: {err}"), + } + } + || () + } + }); + return UseRunnerConnectionHandle { ws, command_state }; +} diff --git a/crates/runner-host/crates/web-client/src/main.rs b/crates/runner-host/crates/web-client/src/main.rs new file mode 100644 index 00000000..75436d60 --- /dev/null +++ b/crates/runner-host/crates/web-client/src/main.rs @@ -0,0 +1,26 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use app::App; + +mod app; +mod board; +mod board_components; +mod console; +mod hooks; + +fn main() { + wasm_logger::init(wasm_logger::Config::default()); + yew::Renderer::::new().render(); +} diff --git a/crates/runner-host/crates/web-client/test.sh b/crates/runner-host/crates/web-client/test.sh new file mode 100755 index 00000000..b3e064be --- /dev/null +++ b/crates/runner-host/crates/web-client/test.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +. "$(git rev-parse --show-toplevel)"/scripts/test-helper.sh + +test_helper + +cargo test --bin=web-client diff --git a/scripts/ci-copyright.sh b/scripts/ci-copyright.sh index c0206d54..08ac416a 100755 --- a/scripts/ci-copyright.sh +++ b/scripts/ci-copyright.sh @@ -24,7 +24,7 @@ for file in $(git ls-files); do *.gitignore|.git*) continue ;; third_party/*) continue ;; *LICENSE) continue ;; - *.css|*.html|*.pdf|*.png|*.svg) continue ;; + *.css|*.scss|*.html|*.pdf|*.png|*.svg) continue ;; *.cff|*.json|*.lock|*.md|*.toml|*.x|*.wasm|*.yml) continue ;; */data/*.rs) continue ;; esac From 71a1466352b9b9647f71e1cbd6e367e0b0d387c5 Mon Sep 17 00:00:00 2001 From: Christopher Dietz Date: Thu, 11 Jul 2024 05:05:37 -0700 Subject: [PATCH 2/4] Serve the new web client instead of the old one (#522) Co-authored-by: Julien Cretin --- crates/runner-host/Cargo.lock | 140 +++++++ crates/runner-host/Cargo.toml | 3 +- .../runner-host/crates/web-client/Cargo.lock | 184 ++++++--- .../runner-host/crates/web-client/Cargo.toml | 5 +- .../runner-host/crates/web-client/src/app.rs | 9 +- .../crates/web-server/public/board.js | 368 ------------------ .../web-server/public/board_components.js | 140 ------- .../web-server/public/components/button.svg | 25 -- .../public/components/monochrome_led.svg | 18 - .../crates/web-server/public/favicon.png | Bin 6076 -> 0 bytes .../crates/web-server/public/index.html | 37 -- .../crates/web-server/public/manifest.json | 15 - .../web-server/public/service-worker.js | 71 ---- .../crates/web-server/public/style.css | 50 --- .../crates/web-server/public/title.svg | 125 ------ .../runner-host/crates/web-server/src/lib.rs | 2 +- crates/runner-host/src/main.rs | 4 + scripts/wrapper.sh | 2 + 18 files changed, 282 insertions(+), 916 deletions(-) delete mode 100644 crates/runner-host/crates/web-server/public/board.js delete mode 100644 crates/runner-host/crates/web-server/public/board_components.js delete mode 100644 crates/runner-host/crates/web-server/public/components/button.svg delete mode 100644 crates/runner-host/crates/web-server/public/components/monochrome_led.svg delete mode 100644 crates/runner-host/crates/web-server/public/favicon.png delete mode 100644 crates/runner-host/crates/web-server/public/index.html delete mode 100644 crates/runner-host/crates/web-server/public/manifest.json delete mode 100644 crates/runner-host/crates/web-server/public/service-worker.js delete mode 100644 crates/runner-host/crates/web-server/public/style.css delete mode 100644 crates/runner-host/crates/web-server/public/title.svg diff --git a/crates/runner-host/Cargo.lock b/crates/runner-host/Cargo.lock index 0157c97f..92acfc72 100644 --- a/crates/runner-host/Cargo.lock +++ b/crates/runner-host/Cargo.lock @@ -213,6 +213,38 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.98" @@ -849,6 +881,18 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libusb1-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -1252,6 +1296,7 @@ dependencies = [ "usbd-serial", "usbip-device", "wasefire-board-api", + "wasefire-cli-tools", "wasefire-error", "wasefire-interpreter", "wasefire-logger", @@ -1261,6 +1306,16 @@ dependencies = [ "web-server", ] +[[package]] +name = "rusb" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4" +dependencies = [ + "libc", + "libusb1-sys", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1310,6 +1365,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.202" @@ -1341,6 +1405,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1558,6 +1631,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1711,6 +1818,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1816,6 +1929,20 @@ dependencies = [ "wasefire-store", ] +[[package]] +name = "wasefire-cli-tools" +version = "0.1.0-git" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", + "rusb", + "serde", + "toml", + "wasefire-protocol", + "wasefire-protocol-usb", +] + [[package]] name = "wasefire-error" version = "0.1.1-git" @@ -1851,10 +1978,14 @@ dependencies = [ name = "wasefire-protocol-usb" version = "0.1.0-git" dependencies = [ + "anyhow", + "rusb", "usb-device", "wasefire-board-api", "wasefire-error", "wasefire-logger", + "wasefire-protocol", + "wasefire-wire", ] [[package]] @@ -2093,6 +2224,15 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/crates/runner-host/Cargo.toml b/crates/runner-host/Cargo.toml index e656d4a5..e7c77796 100644 --- a/crates/runner-host/Cargo.toml +++ b/crates/runner-host/Cargo.toml @@ -17,6 +17,7 @@ usb-device = { version = "0.3.2", optional = true } usbd-serial = { version = "0.2.2", optional = true } usbip-device = { version = "0.2.0", optional = true } wasefire-board-api = { path = "../board", features = ["std"] } +wasefire-cli-tools = { path = "../cli-tools", optional = true } wasefire-error = { path = "../error" } wasefire-interpreter = { path = "../interpreter", optional = true } wasefire-logger = { path = "../logger" } @@ -55,7 +56,7 @@ usb = [ "wasefire-scheduler/board-api-platform-protocol", "wasefire-scheduler/board-api-usb-serial", ] -web = ["dep:web-server"] +web = ["dep:wasefire-cli-tools", "dep:web-server"] # Exactly one is enabled by xtask. debug = ["wasefire-logger/log", "wasefire-protocol-usb?/log", "wasefire-scheduler/log"] release = [] diff --git a/crates/runner-host/crates/web-client/Cargo.lock b/crates/runner-host/crates/web-client/Cargo.lock index c0cac133..3634c18c 100644 --- a/crates/runner-host/crates/web-client/Cargo.lock +++ b/crates/runner-host/crates/web-client/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -25,15 +25,15 @@ checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -61,9 +61,9 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" @@ -73,9 +73,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -158,7 +158,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] @@ -193,9 +193,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gloo" @@ -248,6 +248,25 @@ dependencies = [ "gloo-worker 0.4.0", ] +[[package]] +name = "gloo" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15282ece24eaf4bd338d73ef580c6714c8615155c4190c781290ee3fa0fd372" +dependencies = [ + "gloo-console 0.3.0", + "gloo-dialogs 0.2.0", + "gloo-events 0.2.0", + "gloo-file 0.3.0", + "gloo-history 0.2.2", + "gloo-net 0.5.0", + "gloo-render 0.2.0", + "gloo-storage 0.3.0", + "gloo-timers 0.3.0", + "gloo-utils 0.2.0", + "gloo-worker 0.5.0", +] + [[package]] name = "gloo-console" version = "0.2.3" @@ -413,6 +432,27 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.2.0", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-render" version = "0.1.1" @@ -545,6 +585,25 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-worker" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085f262d7604911c8150162529cefab3782e91adb20202e8658f7275d2aefe5d" +dependencies = [ + "bincode", + "futures", + "gloo-utils 0.2.0", + "gloo-worker-macros", + "js-sys", + "pinned", + "serde", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-worker-macros" version = "0.1.0" @@ -554,14 +613,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" @@ -597,7 +656,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] @@ -627,9 +686,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "log" @@ -639,15 +698,15 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -664,9 +723,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] @@ -700,7 +759,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] @@ -728,12 +787,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] @@ -772,9 +831,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -798,30 +857,30 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" @@ -862,14 +921,14 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -909,9 +968,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -920,29 +979,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "pin-project-lite", @@ -961,9 +1020,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" [[package]] name = "toml_edit" @@ -995,7 +1054,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] [[package]] @@ -1046,7 +1105,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -1080,7 +1139,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1106,6 +1165,7 @@ dependencies = [ name = "web-client" version = "0.1.0" dependencies = [ + "gloo-utils 0.2.0", "log", "serde_json", "wasm-bindgen", @@ -1169,11 +1229,11 @@ dependencies = [ [[package]] name = "yew-hooks" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6f2fe60864adbcc36f1d51f748a186f56f99857c55521d4c9ec1c6e4a0d0a9" +checksum = "cbe7d30ef9d9afb9be38b1b310c42d59963c6d1c950f0e0435b78b346b4b24bf" dependencies = [ - "gloo 0.10.0", + "gloo 0.11.0", "js-sys", "log", "serde", @@ -1195,5 +1255,5 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.66", ] diff --git a/crates/runner-host/crates/web-client/Cargo.toml b/crates/runner-host/crates/web-client/Cargo.toml index f98342a4..d503e2f9 100644 --- a/crates/runner-host/crates/web-client/Cargo.toml +++ b/crates/runner-host/crates/web-client/Cargo.toml @@ -7,14 +7,15 @@ publish = false edition = "2021" [dependencies] +gloo-utils = "0.2.0" log = "0.4.21" -serde_json = "1.0.111" +serde_json = "1.0.117" wasm-bindgen = "0.2.92" wasm-logger = "0.2.0" web-common = { path = "../web-common" } web-sys = "0.3.69" yew = { version = "0.21", features = ["csr"] } -yew-hooks = "0.3.1" +yew-hooks = "0.3.2" [lints] clippy.unit-arg = "allow" diff --git a/crates/runner-host/crates/web-client/src/app.rs b/crates/runner-host/crates/web-client/src/app.rs index 8ed799a9..789a833d 100644 --- a/crates/runner-host/crates/web-client/src/app.rs +++ b/crates/runner-host/crates/web-client/src/app.rs @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use gloo_utils::window; use log::{info, warn}; +use wasm_bindgen::UnwrapThrowExt; use web_common::{Command, Event}; use yew::prelude::*; @@ -22,7 +24,12 @@ use crate::hooks::use_runner_connection; #[function_component(App)] pub fn app() -> Html { - let runner_connection = use_runner_connection(String::from("ws://127.0.0.1:5000/board")); + let runner_connection = { + let host = window().location().host().unwrap_throw(); + let web_socket_url = format!("ws://{host}/board"); + info!("Connecting to runner at {web_socket_url}"); + use_runner_connection(web_socket_url) + }; let on_new_console_msg = Callback::from({ let runner_connection = runner_connection.clone(); diff --git a/crates/runner-host/crates/web-server/public/board.js b/crates/runner-host/crates/web-server/public/board.js deleted file mode 100644 index d5b78ba0..00000000 --- a/crates/runner-host/crates/web-server/public/board.js +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implements the main UI for the board. - */ - -// How many linkes to keep in the log. -const MAX_LOG_LINES = 300; - -/** Websocket wrapper class. - * - * Ensures that a connection to the backend is healthy, or tries to fix it. - * Serializes messages to and from the backend. - * - * @class MessageChannel - */ -class MessageChannel { - constructor({urlEndpoint, onOpen, onMessage, onClose}) { - this._args = {urlEndpoint, onOpen, onMessage, onClose}; - this._connect(this._args); - } - - _connect({urlEndpoint, onOpen, onMessage, onClose}) { - this.ws = new WebSocket(urlEndpoint); - this.ws.onopen = (event) => onOpen(); - this.ws.onmessage = (event) => onMessage(this._parseMessage(event)); - this.ws.onclose = (event) => { - setTimeout(() => this._connect(this._args), 1000); - onClose(); - }; - this.ws.onerror = (event) => { - this.ws.close(); - }; - } - - send(message) { - this.ws.send(this._encodeMessage(message)); - } - - _encodeMessage(message) { - return JSON.stringify(message); - } - - _parseMessage(event) { - const message = JSON.parse(event.data); - return message; - } -} - -/** Draws the board. - * - * Since the app is simple, this draws the board directly as an SVG. - * If the complexity of the UI increases, we'll move to a JS framework like - * Vue or Lit. - * - * @class BoardDrawer - */ -class BoardDrawer { - constructor(outputElement) { - this.ioPanel = document.createElement("div"); - this.log = document.createElement("div"); - this.inputWrapper = document.createElement("div"); - this.input = document.createElement("input"); - this.button = document.createElement("button"); - this.board = document.createElement("div"); - this.overlay = document.createElement("div"); - this.overlayCentered = document.createElement("div"); - this.overlayCenteredTitle = document.createElement("div"); - this.overlayCenteredMessage = document.createElement("div"); - this.overlay.appendChild(this.overlayCentered); - this.overlayCentered.appendChild(this.overlayCenteredTitle); - this.overlayCentered.appendChild(this.overlayCenteredMessage); - this.inputWrapper.appendChild(this.input); - this.inputWrapper.appendChild(this.button); - this.ioPanel.appendChild(this.log); - this.ioPanel.appendChild(this.inputWrapper); - outputElement.appendChild(this.ioPanel); - outputElement.appendChild(this.board); - outputElement.appendChild(this.overlay); - this._svg = SVG().addTo(this.board).size("100%", "100%"); - this.setVisibility(false); - this.reset(); - } - - /** Places a component on the board. - * - */ - async placeComponent({type}) { - const response = await fetch(`components/${type}.svg`); - const component = this._svg - .group() - .svg(await response.text()) - .move(10, this._nextComponentY); - this._nextComponentY = component.height() + 10 + component.y(); - this._nextComponentX = Math.max( - component.width() + component.x(), - this._nextComponentX, - ); - this.ioPanel.style.left = `${this._nextComponentX + 40}px`; - return component; - } - - async reset() { - this._nextComponentY = 90; - this._nextComponentX = 0; - // Destroy log. - this.log.textContent = ""; - } - - async start() { - await this._build(); - } - - /** Saves the callback to call when the user types something. - * - */ - async setInputCallback(callback) { - this._inputCallback = callback; - } - - async _build() { - this.overlay.style.position = "fixed"; - this.overlay.style.top = "0"; - this.overlay.style.bottom = "0"; - this.overlay.style.right = "0"; - this.overlay.style.left = "0"; - this.overlay.style.background = "white"; - this.overlay.style.display = "flex"; - this.overlay.style.justifyContent = "center"; - this.overlay.style.alignItems = "center"; - this.overlayCentered.style.display = "flex"; - this.overlayCentered.style.flexDirection = "column"; - this.overlayCentered.style.justifyContent = "center"; - this.overlayCentered.style.alignItems = "center"; - this.overlayCenteredTitle.style.fontFamily = "'Montserrat', sans-serif"; - this.overlayCenteredTitle.style.fontSize = "1.5rem"; - this.overlayCenteredTitle.textContent = "Wasefire"; - this.overlayCenteredMessage.style.minHeight = "1rem"; - this.overlayCenteredMessage.style.marginTop = "1rem"; - this.overlayCenteredMessage.style.fontFamily = "'Montserrat', sans-serif"; - this.overlayCenteredMessage.style.fontSize = ".9rem"; - this.overlayCenteredMessage.style.color = "rgba(100,100,100,1)"; - this.board.style.minHeight = "300px"; - this.board.style.minWidth = "100%"; - this._svg - .rect("100%", "100%") - .fill("rgb(51, 126, 58)") - .move(0, 12) - .stroke({color: "rgb(12, 74, 19)", width: 2}) - .radius(5); - const response = await fetch("title.svg"); - const title = this._svg.svg(await response.text()); - this.ioPanel.style.position = "absolute"; - this.ioPanel.style.minWidth = "20px"; - this.ioPanel.style.minHeight = "20px"; - this.ioPanel.style.background = "rgba(45,45,45,.95)"; - this.ioPanel.style.boxShadow = "3px 3px 0 rgba(10,10,10,.95)"; - this.ioPanel.style.top = "100px"; - this.ioPanel.style.right = "20px"; - this.ioPanel.style.left = "20px"; - this.ioPanel.style.bottom = "20px"; - this.ioPanel.style.display = "flex"; - this.ioPanel.style.flexDirection = "column"; - this.log.style.flexGrow = "1"; - this.log.style.color = "white"; - this.log.style.paddingLeft = "1rem"; - this.log.style.overflowY = "auto"; - this.log.style.flexDirection = "column-reverse"; - this.log.style.display = "flex"; - this.log.style.fontFamily = "'Fira Code'"; - this.inputWrapper.style.display = "flex"; - this.input.style.flexGrow = "1"; - this.input.focus(); - this.input.onkeyup = (event) => { - if (event.key != "Enter") return; - this._sendInput(); - }; - this.button.textContent = "Send"; - this.button.style.cursor = "pointer"; - this.button.onclick = () => this._sendInput(); - } - - async _sendInput() { - this.button.disabled = true; - if (this._inputCallback) { - await this._inputCallback({ - type: "input", - message: this.input.value, - }); - this.appendInput(this.input.value); - } - this.input.value = ""; - this.button.disabled = false; - } - - _dropOldLogElements() { - [...this.log.children] - .slice(MAX_LOG_LINES) - .map((c) => this.log.removeChild(c)); - } - - _appendLog(message) { - const p = document.createElement("p"); - p.innerText = message; - p.style.margin = "3px 0"; - p.style.transition = "opacity .1s linear"; - p.style.opacity = "0.5"; - this.log.prepend(p); - setTimeout(() => { - p.style.opacity = "1"; - }, 1); - this._dropOldLogElements(); - return p; - } - - appendInput(message) { - const p = this._appendLog(message); - p.style.marginLeft = "auto"; - p.style.marginRight = "1rem"; - p.style.color = "rgba(200,255,255,0.7)"; - } - - appendStatus(message) { - const p = this._appendLog(message); - p.style.color = "rgba(0,255,255,0.7)"; - this.overlayCenteredMessage.innerText = message; - } - - appendEvent(message) { - const p = this._appendLog(message); - p.style.color = "rgba(0,100,255,0.7)"; - } - - appendLog(message) { - this._appendLog(message); - } - - setVisibility(visible) { - const overlayVisibility = visible ? "hidden" : "visible"; - if (this.overlay.style.visibility == overlayVisibility) return; - this.overlay.style.visibility = overlayVisibility; - this.overlayCenteredTitle.classList.remove("loading-title"); - this.overlayCenteredMessage.classList.remove("loading-message"); - if (visible) return; - setTimeout(() => { - this.overlayCenteredTitle.classList.add("loading-title"); - this.overlayCenteredMessage.classList.add("loading-message"); - }, 50); - } -} - -/** Top controller class. - * - * Creates a board and a message channel. Processes user messages. - * - * @class Board - */ -class Board { - constructor(urlEndpoint, outputElement) { - this._connected = false; - this._components = []; - this._drawer = new BoardDrawer(outputElement); - this._channel = new MessageChannel({ - urlEndpoint, - onOpen: () => { - this._connected = true; - this._drawer.setVisibility(false); - this._drawer.appendStatus( - "Connection established! Waiting for runner configuration...", - ); - }, - onClose: () => { - if (this._connected) { - this._drawer.appendStatus( - "Backend disconnected. Waiting for it to restart...", - ); - this._connected = false; - } - }, - onMessage: (message) => this.processMessage(message), - }); - this._drawer.setInputCallback((message) => this._channel.send(message)); - this._ensureOnlyThisTabIsOpen(); - } - - getComponentFromId(id) { - for (const component of this._components) { - if (component.id == id) return component; - } - } - - async processMessage(message) { - const messageType = message["type"]; - if (messageType == "board_config") { - this._drawer.appendStatus("Board configuration received."); - this._drawer.setVisibility(true); - this._setupBoard(message["components"]); - } else if (messageType == "set") { - const component = this.getComponentFromId(message["componentId"]); - if (component) component.set(message["state"]); - } else if (messageType == "disconnected") { - this._drawer.appendStatus( - "Runner disconnected. Waiting for new connection...", - ); - this._drawer.setVisibility(false); - } else if (messageType == "connected") { - this._drawer.appendStatus("Backend connected. Waiting for runner..."); - this._drawer.setVisibility(false); - } else if (messageType == "log") { - this._drawer.appendLog(message["message"]); - } else { - this._drawer.appendStatus(`Unknown message: ${JSON.stringify(message)}`); - } - } - - async _setupBoard(componentsSpecs) { - this._components.map((c) => c.destroy()); - this._drawer.reset(); - this._components = []; - - for (const componentSpecs of componentsSpecs) { - const componentType = componentSpecs["type"]; - const componentId = componentSpecs["id"]; - const componentClass = { - monochrome_led: MonochromeLedComponent, - button: ButtonComponent, - }[componentType]; - const component = new componentClass( - componentId, - this._drawer, - this._channel, - ); - await component.place(); - await component.reset(); - this._components.push(component); - } - this._drawer.appendStatus("Board is ready!"); - this._channel.send({ - componentType: "board_ready", - }); - } - - async start() { - await this._drawer.start(); - } - - _ensureOnlyThisTabIsOpen() { - // Allows only one tab to be open on this site. - // This prevents messages from being lost. - const broadcast = new BroadcastChannel('intertab'); - broadcast.onmessage = function(event) { - if (event?.data?.message === 'TAKEOVER') window.close(); - } - broadcast.postMessage({ message: 'TAKEOVER' }); - } -} diff --git a/crates/runner-host/crates/web-server/public/board_components.js b/crates/runner-host/crates/web-server/public/board_components.js deleted file mode 100644 index f9b4abcd..00000000 --- a/crates/runner-host/crates/web-server/public/board_components.js +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implements the available board components. - */ - -/** - * Board component abstract class. - * - * @class BoardComponent - */ -class BoardComponent { - /** - @constructor - @abstract - */ - constructor(componentId, boardDrawer, channel) { - if (new.target === BoardComponent) - throw new Error("Abstract class cannot be instantiated."); - this._drawer = boardDrawer; - this._channel = channel; - this.id = componentId; - } - - destroy() { - if (!this._element) return; - this._element.svg(""); - } - - /** - @abstract - */ - reset() { - throw new Error("Abstract method called."); - } -} - -/** - * A clickable button. - * - * @class ButtonComponent - * @extends {BoardComponent} - */ -class ButtonComponent extends BoardComponent { - constructor(componentId, boardDrawer, channel) { - super(componentId, boardDrawer, channel); - this._status = false; - } - - async place() { - this._element = await this._drawer.placeComponent({type: "button"}); - this._element.on("mousedown", () => this.onPressed()); - this._element.on("mouseup", () => this.onReleased()); - } - - onPressed() { - this._channel.send({ - componentId: this.id, - componentType: "button", - state: "pressed", - }); - this.set(true); - } - onReleased() { - this._channel.send({ - componentId: this.id, - componentType: "button", - state: "released", - }); - this.set(false); - } - - reset() { - this.set(false); - } - - get() { - return this._status; - } - - set(value) { - this._status = value; - const pressed = this._element.findOne("#pressed"); - const notPressed = this._element.findOne("#not_pressed"); - if (value) { - pressed.show(); - notPressed.hide(); - } else { - notPressed.show(); - pressed.hide(); - } - } -} - -/** - * A blinky led. - * - * @class ButtonComponent - * @extends {BoardComponent} - */ -class MonochromeLedComponent extends BoardComponent { - constructor(componentId, boardDrawer, channel) { - super(componentId, boardDrawer, channel); - this._status = false; - } - - async place() { - this._element = await this._drawer.placeComponent({type: "monochrome_led"}); - } - - reset() { - this.set(false); - } - - get() { - return this._status; - } - - set(value) { - this._status = value; - const light = this._element.findOne("#on"); - if (value) { - light.show(); - } else { - light.hide(); - } - } -} diff --git a/crates/runner-host/crates/web-server/public/components/button.svg b/crates/runner-host/crates/web-server/public/components/button.svg deleted file mode 100644 index e13771a8..00000000 --- a/crates/runner-host/crates/web-server/public/components/button.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/crates/runner-host/crates/web-server/public/components/monochrome_led.svg b/crates/runner-host/crates/web-server/public/components/monochrome_led.svg deleted file mode 100644 index ed17a10c..00000000 --- a/crates/runner-host/crates/web-server/public/components/monochrome_led.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/crates/runner-host/crates/web-server/public/favicon.png b/crates/runner-host/crates/web-server/public/favicon.png deleted file mode 100644 index 6ca3e6b47ccb1a1dee75fbd13474dec7f612c905..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6076 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 c7C!z}6{MZgW*L!&sd`n9DFTOC8+yDRo diff --git a/crates/runner-host/crates/web-server/public/index.html b/crates/runner-host/crates/web-server/public/index.html deleted file mode 100644 index 26e3de97..00000000 --- a/crates/runner-host/crates/web-server/public/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - Wasefire - - - - - - - - - - - - -
- - - - - diff --git a/crates/runner-host/crates/web-server/public/manifest.json b/crates/runner-host/crates/web-server/public/manifest.json deleted file mode 100644 index e662edaf..00000000 --- a/crates/runner-host/crates/web-server/public/manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "short_name": "Wasefire", - "name": "Wasefire web UI", - "icons": [ - { - "src": "/favicon.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "start_url": "/", - "theme_color": "#337E36", - "background_color": "#fff", - "display": "standalone" -} diff --git a/crates/runner-host/crates/web-server/public/service-worker.js b/crates/runner-host/crates/web-server/public/service-worker.js deleted file mode 100644 index a07c81fe..00000000 --- a/crates/runner-host/crates/web-server/public/service-worker.js +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -const CACHE_KEY = "wasefire v0.1"; - -const CACHE = [ - "/", - "index.html", - "style.css", - "title.svg", - "board_components.js", - "board.js", - "manifest.json", - "favicon.png", - "components/button.svg", - "components/monochrome_led.svg", -]; - -async function install() { - const cache = await self.caches.open(CACHE_KEY); - await cache.addAll(CACHE); - await self.skipWaiting(); -} - -async function deleteOldCaches() { - for (const key of await self.caches.keys()) { - if (key !== CACHE_KEY) self.caches.delete(key); - } -} - -async function fetchFromNetworkOrCache(request) { - const url = new URL(request.url); - const cache = await self.caches.open(CACHE_KEY); - let liveResponse = null; - try { - liveResponse = await fetch(request); - } catch (err) { - // Backend is offline. - } - // Update the cache. - if (liveResponse && liveResponse.ok) { - cache.put(request, liveResponse.clone()); - return liveResponse; - } - const cached_response = await cache.match(request); - return cached_response; -} - -self.addEventListener("install", (event) => event.waitUntil(install())); - -self.addEventListener("activate", (event) => - event.waitUntil(deleteOldCaches().then(self.clients.claim())), -); - -self.addEventListener("fetch", (event) => { - const url = new URL(event.request.url); - if (self.location.hostname != url.hostname) return; - if (url.pathname.endsWith('board')) return; - event.respondWith(fetchFromNetworkOrCache(event.request)); -}); diff --git a/crates/runner-host/crates/web-server/public/style.css b/crates/runner-host/crates/web-server/public/style.css deleted file mode 100644 index 67ed3384..00000000 --- a/crates/runner-host/crates/web-server/public/style.css +++ /dev/null @@ -1,50 +0,0 @@ -/* Scrollbar */ -* { - scrollbar-width: thin; - scrollbar-color: rgb(12,74,19) rgb(10,10,10); -} -*::-webkit-scrollbar { - width: 12px; -} -*::-webkit-scrollbar-track { - background: rgba(10,10,10,.9); -} -*::-webkit-scrollbar-thumb { - background-color: blue; - border-radius: 20px; - border: 3px solid rgb(12, 74, 19); -} - - -/* Loading animation */ -.loading-title { - animation: loading-title 1s cubic-bezier(0.2, 0.6, 0.4, 1.000) both; -} -@keyframes loading-title { - 0% { - letter-spacing: -0.4em; - opacity: 0; - } - 50% { - opacity: 0.5; - } - 100% { - opacity: 1; - } -} - -.loading-message { - animation: loading-message 1.0s linear both; -} -@keyframes loading-message { - 0% { - opacity: 0; - } - 20% { - opacity: 0; - } - 100% { - opacity: 1; - } -} - diff --git a/crates/runner-host/crates/web-server/public/title.svg b/crates/runner-host/crates/web-server/public/title.svg deleted file mode 100644 index e1aae33b..00000000 --- a/crates/runner-host/crates/web-server/public/title.svg +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/crates/runner-host/crates/web-server/src/lib.rs b/crates/runner-host/crates/web-server/src/lib.rs index a39e6cd4..774ed89f 100644 --- a/crates/runner-host/crates/web-server/src/lib.rs +++ b/crates/runner-host/crates/web-server/src/lib.rs @@ -42,7 +42,7 @@ impl Client { let (sender, mut receiver) = oneshot::channel(); let client = Arc::new(Mutex::new(Some((sender, events)))); - let static_files = warp::fs::dir("crates/web-server/public"); + let static_files = warp::fs::dir("crates/web-client/dist"); let ws = warp::path("board") .and(warp::ws()) .and(warp::any().map(move || client.clone())) diff --git a/crates/runner-host/src/main.rs b/crates/runner-host/src/main.rs index b5b0b0f8..dd02cce2 100644 --- a/crates/runner-host/src/main.rs +++ b/crates/runner-host/src/main.rs @@ -79,6 +79,10 @@ async fn main() -> Result<()> { } } }); + let mut wrapper_command = std::process::Command::new("../../scripts/wrapper.sh"); + let build_command = + wrapper_command.args(["trunk", "build", "crates/web-client/index.html"]); + wasefire_cli_tools::cmd::execute(build_command)?; let url = format!("{}:{}", flags.web_options.web_host, flags.web_options.web_port); web_server::Client::new(&url, sender).await? }; diff --git a/scripts/wrapper.sh b/scripts/wrapper.sh index 00c12525..27a404f3 100755 --- a/scripts/wrapper.sh +++ b/scripts/wrapper.sh @@ -39,6 +39,7 @@ ensure_cargo() { { cargo install --list --root="$CARGO_ROOT" | grep -q "^$1 v$2:\$"; } && return [ "$1" = cargo-edit ] && ensure lib openssl [ "$1" = taplo-cli ] && locked= + [ "$1" = trunk ] && locked= shift 2 x cargo install $locked --root="$CARGO_ROOT" "$flags" "$@" } @@ -57,6 +58,7 @@ case "$1" in probe-rs) ensure_cargo probe-rs-tools 0.24.0 ;; rust-objcopy|rust-size) ensure_cargo cargo-binutils 0.3.6 ;; taplo) ensure_cargo taplo-cli 0.9.0 ;; + trunk) ensure_cargo trunk 0.19.3 ;; twiggy) ensure_cargo twiggy 0.7.0 ;; *) IS_CARGO=n ;; esac From 9f0ba024d8b5a458d668aa80d8c6fa3c34ec0fff Mon Sep 17 00:00:00 2001 From: Christopher Dietz Date: Thu, 1 Aug 2024 11:57:28 +0000 Subject: [PATCH 3/4] Added CSS styling and fixed reconnecting to backend without reload. (#549) - Added CSS to match existing web client look. - Changed timeout on websockets to 1 second (1000 ms) - Also made the client reset and disable input when the websocket connection goes down. Should be the final bit that needs to be done to replace the old web client. --------- Co-authored-by: Julien Cretin --- .../crates/web-client/data/index.scss | 44 ++++++ .../crates/web-client/data/title.svg | 125 ++++++++++++++++++ .../runner-host/crates/web-client/index.html | 2 +- .../runner-host/crates/web-client/src/app.rs | 5 + .../crates/web-client/src/board.rs | 18 ++- .../crates/web-client/src/console.rs | 27 +++- .../crates/web-client/src/hooks.rs | 54 ++++++-- crates/runner-host/src/main.rs | 2 +- 8 files changed, 250 insertions(+), 27 deletions(-) create mode 100644 crates/runner-host/crates/web-client/data/title.svg diff --git a/crates/runner-host/crates/web-client/data/index.scss b/crates/runner-host/crates/web-client/data/index.scss index 34d746d4..fa4ef266 100644 --- a/crates/runner-host/crates/web-client/data/index.scss +++ b/crates/runner-host/crates/web-client/data/index.scss @@ -22,7 +22,15 @@ svg { pointer-events: none; } +.board { + padding: 18px; + width: 30px; // Matches size of icons. +} + .button { + /* + Prevents bug where button gets stuck on drag. + */ user-drag: none; -webkit-user-drag: none; user-select: none; @@ -30,3 +38,39 @@ svg { -webkit-user-select: none; -ms-user-select: none; } + +.console { + position: absolute; + min-width: 20px; + min-height: 20px; + background: rgba(45, 45, 45, 0.95); + box-shadow: rgba(10, 10, 10, 0.95) 3px 3px 0px; + inset: 100px 20px 20px 79px; + display: flex; + flex-direction: column; +} + +.console-form { + display: flex; +} + +input#consolein { + flex-grow: 1; +} + +.console-display { + flex-grow: 1; + color: white; + overflow-y: auto; + flex-direction: column-reverse; + display: flex; + font-family: "Fira Code", monospace; +} + +body { + background-color: rgb(51, 126, 58); + border: 7px solid white; + border-top: 14px solid white; + min-height: 100vh; + margin: 0; +} diff --git a/crates/runner-host/crates/web-client/data/title.svg b/crates/runner-host/crates/web-client/data/title.svg new file mode 100644 index 00000000..e1aae33b --- /dev/null +++ b/crates/runner-host/crates/web-client/data/title.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/runner-host/crates/web-client/index.html b/crates/runner-host/crates/web-client/index.html index 9778dcf7..dbcd0571 100644 --- a/crates/runner-host/crates/web-client/index.html +++ b/crates/runner-host/crates/web-client/index.html @@ -4,7 +4,7 @@ Wasefire - + diff --git a/crates/runner-host/crates/web-client/src/app.rs b/crates/runner-host/crates/web-client/src/app.rs index 789a833d..6589e4b1 100644 --- a/crates/runner-host/crates/web-client/src/app.rs +++ b/crates/runner-host/crates/web-client/src/app.rs @@ -60,6 +60,11 @@ pub fn app() -> Html { html! {
+ Html let board_config = board_config.clone(); let on_board_ready = on_board_ready.clone(); move |command_state| { - if let Some(Command::BoardConfig { components }) = &**command_state { - info!("Board config: {components:?}"); - board_config.set(Some(components.clone())); - on_board_ready.emit(()); + if let Some(command) = &**command_state { + match command { + Command::BoardConfig { components } => { + info!("Board config: {components:?}"); + board_config.set(Some(components.clone())); + on_board_ready.emit(()); + } + Command::Disconnected => { + board_config.set(None); + } + _ => (), + } } || () } @@ -54,7 +62,7 @@ pub fn Board(Props { command_state, on_board_ready, on_event }: &Props) -> Html } }).collect::() } else { - html!(
{"Waiting for backend connection..."}
) + html!(
) } } }; diff --git a/crates/runner-host/crates/web-client/src/console.rs b/crates/runner-host/crates/web-client/src/console.rs index dbf570ed..e381a906 100644 --- a/crates/runner-host/crates/web-client/src/console.rs +++ b/crates/runner-host/crates/web-client/src/console.rs @@ -31,6 +31,7 @@ pub struct Props { pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html { let history = use_list(vec![]); let console_ref = use_node_ref(); + let button_enabled = use_state(|| false); let onsubmit = Callback::from({ let history = history.clone(); @@ -50,11 +51,24 @@ pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html use_effect_with(command_state.clone(), { let history = history.clone(); + let button_enabled = button_enabled.clone(); move |command_state| { if let Some(command) = &**command_state { info!("Command: {command:?}"); - if let Command::Log { message } = command { - history.push(format!("[recv]: {message}")); + + match command { + Command::Log { message } => { + history.push(format!("[recv]: {message}")); + } + Command::Disconnected => { + history.push("Disconnected from runner".to_string()); + button_enabled.set(false); + } + Command::Connected => { + history.push("Connected to runner".to_string()); + button_enabled.set(true); + } + _ => (), } } || () @@ -63,11 +77,12 @@ pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html html! {
-

{ "Log history: " }

- { for history.current().iter().map(|message| html!(

{ message }

)) } -
+
+ { for history.current().iter().rev().map(|message| html!(
{ message }
)) } +
+ - +
} diff --git a/crates/runner-host/crates/web-client/src/hooks.rs b/crates/runner-host/crates/web-client/src/hooks.rs index 6d3c19bc..23ddba2e 100644 --- a/crates/runner-host/crates/web-client/src/hooks.rs +++ b/crates/runner-host/crates/web-client/src/hooks.rs @@ -37,23 +37,49 @@ impl UseRunnerConnectionHandle { } } +fn set_disconnected(command_state: UseStateHandle>) { + match &*command_state { + None | Some(Command::Disconnected) => (), + _ => command_state.set(Some(Command::Disconnected)), + } +} + #[hook] pub fn use_runner_connection(backend_address: String) -> UseRunnerConnectionHandle { - let ws = use_websocket(backend_address.clone()); let command_state = use_state(|| None); - // Receive message by depending on `ws.message`. - use_effect_with(ws.message.clone(), { - let command_state = command_state.clone(); - move |message| { - if let Some(message) = &**message { - info!("Message: {message}"); - match serde_json::from_str::(message) { - Ok(command) => command_state.set(Some(command)), - Err(err) => warn!("Error parsing message: {err}"), + let ws = use_websocket_with_options( + backend_address, + UseWebSocketOptions { + reconnect_interval: Some(1000), + onmessage: Some(Box::new({ + let command_state = command_state.clone(); + move |message| { + info!("Message: {message}"); + match serde_json::from_str::(message.as_str()) { + Ok(command) => command_state.set(Some(command)), + Err(err) => warn!("Error parsing message: {err}"), + } } - } - || () - } - }); + })), + onclose: Some(Box::new({ + let command_state = command_state.clone(); + move |close_event| { + let close_event_type = close_event.type_(); + warn!("Socket closed {close_event_type} setting disconnect event."); + set_disconnected(command_state.clone()); + } + })), + onerror: Some(Box::new({ + let command_state = command_state.clone(); + move |event| { + let event_type = event.type_(); + warn!("Socket error: {event_type} setting disconnect event."); + set_disconnected(command_state.clone()); + } + })), + ..Default::default() + }, + ); + return UseRunnerConnectionHandle { ws, command_state }; } diff --git a/crates/runner-host/src/main.rs b/crates/runner-host/src/main.rs index dd02cce2..df5aa0d3 100644 --- a/crates/runner-host/src/main.rs +++ b/crates/runner-host/src/main.rs @@ -81,7 +81,7 @@ async fn main() -> Result<()> { }); let mut wrapper_command = std::process::Command::new("../../scripts/wrapper.sh"); let build_command = - wrapper_command.args(["trunk", "build", "crates/web-client/index.html"]); + wrapper_command.args(["trunk", "build", "--release", "crates/web-client/index.html"]); wasefire_cli_tools::cmd::execute(build_command)?; let url = format!("{}:{}", flags.web_options.web_host, flags.web_options.web_port); web_server::Client::new(&url, sender).await? From aa8caf7f02067396a4d3437e5856fc4693f159f0 Mon Sep 17 00:00:00 2001 From: Julien Cretin Date: Thu, 1 Aug 2024 21:17:27 +0200 Subject: [PATCH 4/4] review --- .github/CODEOWNERS | 1 + crates/runner-host/crates/web-client/README.md | 15 ++++++--------- crates/runner-host/crates/web-client/src/app.rs | 15 ++++----------- crates/runner-host/crates/web-client/src/board.rs | 8 ++++---- .../web-client/src/board_components/button.rs | 5 ++--- .../crates/web-client/src/board_components/led.rs | 8 ++++---- .../runner-host/crates/web-client/src/console.rs | 12 +++++------- crates/runner-host/crates/web-client/src/hooks.rs | 8 +++----- crates/runner-host/crates/web-client/src/main.rs | 4 +--- crates/runner-host/src/main.rs | 7 +++---- 10 files changed, 33 insertions(+), 50 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d4b98526..511120a6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,2 @@ * @ia0 +/crates/runner-host/crates/web-client/ @chris-dietz @ia0 diff --git a/crates/runner-host/crates/web-client/README.md b/crates/runner-host/crates/web-client/README.md index 1cc754df..61e5a44c 100644 --- a/crates/runner-host/crates/web-client/README.md +++ b/crates/runner-host/crates/web-client/README.md @@ -1,7 +1,7 @@ # Wasefire Web Client -This is a fairly minimal web app for interacting with the runner that's built -with [Yew](https://yew.rs) and [Trunk](https://trunkrs.dev/). +This is a fairly minimal web app for interacting with the host runner. It is built with +[Yew](https://yew.rs) and [Trunk](https://trunkrs.dev/). ## Running @@ -9,11 +9,9 @@ with [Yew](https://yew.rs) and [Trunk](https://trunkrs.dev/). trunk serve ``` -Rebuilds the app whenever a change is detected and runs a local server -to host it. +Rebuilds the app whenever a change is detected and runs a local server to host it. -There's also the `trunk watch` command which does the same thing but without -hosting it. +There's also the `trunk watch` command which does the same thing but without hosting it. ## Release @@ -21,8 +19,7 @@ hosting it. trunk build --release ``` -This builds the app in release mode similar to `cargo build --release`. -You can also pass the `--release` flag to `trunk serve` if you need to get -every last drop of performance. +This builds the app in release mode similar to `cargo build --release`. You can also pass the +`--release` flag to `trunk serve` if you need to get every last drop of performance. Unless overwritten, the output will be located in the `dist` directory. diff --git a/crates/runner-host/crates/web-client/src/app.rs b/crates/runner-host/crates/web-client/src/app.rs index 6589e4b1..5848a7af 100644 --- a/crates/runner-host/crates/web-client/src/app.rs +++ b/crates/runner-host/crates/web-client/src/app.rs @@ -15,7 +15,7 @@ use gloo_utils::window; use log::{info, warn}; use wasm_bindgen::UnwrapThrowExt; -use web_common::{Command, Event}; +use web_common::Command; use yew::prelude::*; use crate::board::Board; @@ -30,20 +30,17 @@ pub fn app() -> Html { info!("Connecting to runner at {web_socket_url}"); use_runner_connection(web_socket_url) }; - let on_new_console_msg = Callback::from({ let runner_connection = runner_connection.clone(); - move |msg: String| runner_connection.send_console_event(msg) + move |msg| runner_connection.send_console_event(msg) }); - let on_board_ready = Callback::from({ let runner_connection = runner_connection.clone(); move |()| runner_connection.send_board_ready() }); - let send_event_callback = Callback::from({ let runner_connection = runner_connection.clone(); - move |event: Event| runner_connection.send_event(event) + move |event| runner_connection.send_event(event) }); use_effect_with(runner_connection.command_state.clone(), move |command_state| { @@ -60,11 +57,7 @@ pub fn app() -> Html { html! {
- + Html } }); - return html! { + html! {
{ if let Some(board_config) = &*board_config { board_config.iter().map(|component| match component { - Component::Button{id} => html!(
- }; + } } diff --git a/crates/runner-host/crates/web-client/src/board_components/button.rs b/crates/runner-host/crates/web-client/src/board_components/button.rs index 942c3f15..10592212 100644 --- a/crates/runner-host/crates/web-client/src/board_components/button.rs +++ b/crates/runner-host/crates/web-client/src/board_components/button.rs @@ -36,7 +36,6 @@ pub fn Button(Props { id, on_event }: &Props) -> Html { on_event.emit(Event::Button { component_id: id, state: ButtonState::Pressed }); } }); - let unpress = Callback::from({ let pressed = pressed.clone(); let on_event = on_event.clone(); @@ -51,7 +50,7 @@ pub fn Button(Props { id, on_event }: &Props) -> Html { } }); - return html! { + html! {
Html { style={if !*pressed { "" } else { "display: none;" }} />
- }; + } } diff --git a/crates/runner-host/crates/web-client/src/board_components/led.rs b/crates/runner-host/crates/web-client/src/board_components/led.rs index 31f46e8f..fe816da3 100644 --- a/crates/runner-host/crates/web-client/src/board_components/led.rs +++ b/crates/runner-host/crates/web-client/src/board_components/led.rs @@ -27,8 +27,8 @@ pub struct Props { pub fn LED(Props { id, command_state }: &Props) -> Html { let id = *id; let lit = use_state(|| false); - let command_state = command_state.clone(); - use_effect_with(command_state, { + + use_effect_with(command_state.clone(), { let lit = lit.clone(); move |command_state| { if let Some(Command::Set { component_id, state }) = &**command_state { @@ -40,7 +40,7 @@ pub fn LED(Props { id, command_state }: &Props) -> Html { } }); - return html! { + html! {
Html { style={if !*lit { "" } else { "display: none;" }} /> - }; + } } diff --git a/crates/runner-host/crates/web-client/src/console.rs b/crates/runner-host/crates/web-client/src/console.rs index e381a906..bc9b0bc3 100644 --- a/crates/runner-host/crates/web-client/src/console.rs +++ b/crates/runner-host/crates/web-client/src/console.rs @@ -20,19 +20,18 @@ use yew::prelude::*; use yew_hooks::prelude::*; #[derive(Properties, PartialEq)] - pub struct Props { #[prop_or_default] pub id: usize, pub command_state: UseStateHandle>, pub on_new_console_msg: Callback, } + #[function_component(Console)] pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html { let history = use_list(vec![]); let console_ref = use_node_ref(); let button_enabled = use_state(|| false); - let onsubmit = Callback::from({ let history = history.clone(); let console_ref = console_ref.clone(); @@ -55,7 +54,6 @@ pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html move |command_state| { if let Some(command) = &**command_state { info!("Command: {command:?}"); - match command { Command::Log { message } => { history.push(format!("[recv]: {message}")); @@ -77,12 +75,12 @@ pub fn console(Props { id, command_state, on_new_console_msg }: &Props) -> Html html! {
-
- { for history.current().iter().rev().map(|message| html!(
{ message }
)) } -
+
{ + for history.current().iter().rev().map(|message| html!(
{ message }
)) + }
- +
} diff --git a/crates/runner-host/crates/web-client/src/hooks.rs b/crates/runner-host/crates/web-client/src/hooks.rs index 23ddba2e..c7eb49a7 100644 --- a/crates/runner-host/crates/web-client/src/hooks.rs +++ b/crates/runner-host/crates/web-client/src/hooks.rs @@ -29,8 +29,7 @@ impl UseRunnerConnectionHandle { warn!("Ignoring message: {console_msg}"); } pub fn send_board_ready(&self) { - let command = Event::BoardReady; - self.ws.send(serde_json::to_string(&command).unwrap()); + self.ws.send(serde_json::to_string(&Event::BoardReady).unwrap()); } pub fn send_event(&self, event: Event) { self.ws.send(serde_json::to_string(&event).unwrap()); @@ -55,7 +54,7 @@ pub fn use_runner_connection(backend_address: String) -> UseRunnerConnectionHand let command_state = command_state.clone(); move |message| { info!("Message: {message}"); - match serde_json::from_str::(message.as_str()) { + match serde_json::from_str::(&message) { Ok(command) => command_state.set(Some(command)), Err(err) => warn!("Error parsing message: {err}"), } @@ -80,6 +79,5 @@ pub fn use_runner_connection(backend_address: String) -> UseRunnerConnectionHand ..Default::default() }, ); - - return UseRunnerConnectionHandle { ws, command_state }; + UseRunnerConnectionHandle { ws, command_state } } diff --git a/crates/runner-host/crates/web-client/src/main.rs b/crates/runner-host/crates/web-client/src/main.rs index 75436d60..ffb17310 100644 --- a/crates/runner-host/crates/web-client/src/main.rs +++ b/crates/runner-host/crates/web-client/src/main.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use app::App; - mod app; mod board; mod board_components; @@ -22,5 +20,5 @@ mod hooks; fn main() { wasm_logger::init(wasm_logger::Config::default()); - yew::Renderer::::new().render(); + yew::Renderer::::new().render(); } diff --git a/crates/runner-host/src/main.rs b/crates/runner-host/src/main.rs index df5aa0d3..9c8d065e 100644 --- a/crates/runner-host/src/main.rs +++ b/crates/runner-host/src/main.rs @@ -79,10 +79,9 @@ async fn main() -> Result<()> { } } }); - let mut wrapper_command = std::process::Command::new("../../scripts/wrapper.sh"); - let build_command = - wrapper_command.args(["trunk", "build", "--release", "crates/web-client/index.html"]); - wasefire_cli_tools::cmd::execute(build_command)?; + let mut trunk = std::process::Command::new("../../scripts/wrapper.sh"); + trunk.args(["trunk", "build", "--release", "crates/web-client/index.html"]); + wasefire_cli_tools::cmd::execute(&mut trunk)?; let url = format!("{}:{}", flags.web_options.web_host, flags.web_options.web_port); web_server::Client::new(&url, sender).await? };