From 6c49c0a8c5745e838bef3b29a76d8b44079dee0c Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Fri, 29 Jul 2022 01:36:18 +0200 Subject: [PATCH] Initial Commit --- .dockerignore | 2 + .gitignore | 4 + Cargo.lock | 1913 +++++++++++++++++++++++ Cargo.toml | 12 + Dockerfile | 73 + backend/Cargo.toml | 31 + backend/example.config.toml | 31 + backend/src/collector.rs | 15 + backend/src/collector/markdown_web.rs | 16 + backend/src/main.rs | 285 ++++ common/Cargo.toml | 11 + common/src/lib.rs | 65 + frontend/Cargo.lock | 609 ++++++++ frontend/Cargo.toml | 31 + frontend/Trunk.toml | 18 + frontend/index.html | 36 + frontend/src/app.rs | 151 ++ frontend/src/components/color_picker.rs | 225 +++ frontend/src/components/mod.rs | 1 + frontend/src/css.rs | 7 + frontend/src/lib.rs | 12 + frontend/src/page/info.rs | 39 + frontend/src/page/lights.rs | 240 +++ frontend/src/page/mod.rs | 3 + frontend/src/page/not_found.rs | 25 + frontend/static/images/blueprint_bg.png | Bin 0 -> 4071 bytes frontend/static/images/hsb.png | Bin 0 -> 142125 bytes frontend/static/images/penguin1.svg | 84 + frontend/static/images/penguin2.svg | 66 + frontend/static/images/penguin3.svg | 67 + frontend/static/styles/common.scss | 267 ++++ frontend/static/styles/penguin.scss | 59 + 32 files changed, 4398 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Dockerfile create mode 100644 backend/Cargo.toml create mode 100644 backend/example.config.toml create mode 100644 backend/src/collector.rs create mode 100644 backend/src/collector/markdown_web.rs create mode 100644 backend/src/main.rs create mode 100644 common/Cargo.toml create mode 100644 common/src/lib.rs create mode 100644 frontend/Cargo.lock create mode 100644 frontend/Cargo.toml create mode 100644 frontend/Trunk.toml create mode 100755 frontend/index.html create mode 100644 frontend/src/app.rs create mode 100644 frontend/src/components/color_picker.rs create mode 100644 frontend/src/components/mod.rs create mode 100644 frontend/src/css.rs create mode 100644 frontend/src/lib.rs create mode 100644 frontend/src/page/info.rs create mode 100644 frontend/src/page/lights.rs create mode 100644 frontend/src/page/mod.rs create mode 100644 frontend/src/page/not_found.rs create mode 100644 frontend/static/images/blueprint_bg.png create mode 100644 frontend/static/images/hsb.png create mode 100644 frontend/static/images/penguin1.svg create mode 100644 frontend/static/images/penguin2.svg create mode 100644 frontend/static/images/penguin3.svg create mode 100644 frontend/static/styles/common.scss create mode 100644 frontend/static/styles/penguin.scss diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f1a0c7c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +target* diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6dd0daa --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target* +dist +config.toml + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2c709c8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1913 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "3.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1fe12880bae935d142c8702d500c63a4e8634b6c3c57ad72bf978fc7b6249a" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6db9e867166a43a53f7199b5e4d1f522a1e5bd626654be263c999ce59df39a" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87eba3c8c7f42ef17f6c659fc7416d0f4758cd3e58861ee63c5fa4a4dde649e4" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "lighter_lib", + "serde", +] + +[[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 = "cookie" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +dependencies = [ + "percent-encoding", + "time", + "version_check 0.9.4", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "css_typegen" +version = "0.2.0" +source = "git+https://github.com/hulthe/css_typegen.git?branch=master#ed1c4b1b7c8bf19e1ce045cafa12f3886041134c" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "dbg" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4677188513e0e9d7adced5997cf9a1e7a3c996c994f90093325c5332c1a8b221" +dependencies = [ + "version_check 0.1.5", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", +] + +[[package]] +name = "enclose" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[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.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check 0.9.4", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[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-file" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa5d6084efa4a2b182ef3a8649cb6506cb4843f22cf907c6e0a799944248ae90" +dependencies = [ + "futures-channel", + "gloo-events", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "929c53c913bb7a88d75d9dc3e9705f963d8c2b9001510b25ddaf671b9fb7049d" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util 0.7.3", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "headers" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1 0.10.0", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hemma" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "clap", + "common", + "futures", + "futures-util", + "lighter_lib", + "lighter_manager", + "log", + "markdown", + "pretty_env_logger", + "reqwest", + "ron", + "serde", + "tokio", + "toml", + "warp", +] + +[[package]] +name = "hemma_web" +version = "0.1.0" +dependencies = [ + "anyhow", + "common", + "css_typegen", + "lighter_lib", + "ron", + "seed", + "seed_router", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lighter_lib" +version = "0.1.0" +source = "git+https://git.nubo.sh/hulthe/lighter.git#d6a25648cec65dc4be166cc27b2c75b95aa5001d" +dependencies = [ + "serde", +] + +[[package]] +name = "lighter_manager" +version = "0.1.0" +source = "git+https://git.nubo.sh/hulthe/lighter.git#d6a25648cec65dc4be166cc27b2c75b95aa5001d" +dependencies = [ + "anyhow", + "clap", + "lighter_lib", + "log", + "mqtt-protocol", + "pretty_env_logger", + "serde", + "serde_json", + "tokio", + "toml", + "uuid 1.1.2", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "markdown" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3aab6a1d529b112695f72beec5ee80e729cb45af58663ec902c8fac764ecdd" +dependencies = [ + "lazy_static", + "pipeline", + "regex", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "mqtt-protocol" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0b17380dc69fbcf5f967828cfd10e55028ba83a57da1f580c5b0792ab807ac" +dependencies = [ + "byteorder", + "lazy_static", + "log", + "regex", + "thiserror", + "tokio", +] + +[[package]] +name = "multipart" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" +dependencies = [ + "buf_redux", + "httparse", + "log", + "mime", + "mime_guess", + "quick-error", + "rand", + "safemem", + "tempfile", + "twoway", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_str_bytes" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pipeline" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[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", + "version_check 0.9.4", +] + +[[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 0.9.4", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64", + "bitflags", + "serde", +] + +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +dependencies = [ + "base64", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "seed" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadc99b3d823229f987d3b5277c00dcff69d5011ed0ed38c20d6aaa66ed7372" +dependencies = [ + "console_error_panic_hook", + "cookie", + "dbg", + "enclose", + "futures", + "getrandom", + "gloo-file", + "gloo-timers", + "gloo-utils", + "indexmap", + "js-sys", + "rand", + "serde", + "serde_json", + "uuid 0.8.2", + "version_check 0.9.4", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "seed_router" +version = "0.1.0" +source = "git+https://git.nubo.sh/hulthe/seed_router.git#e0a428a8f9186a4590acb2b3771e50290aacbde1" +dependencies = [ + "seed", + "seed_router_derive", +] + +[[package]] +name = "seed_router_derive" +version = "0.1.0" +source = "git+https://git.nubo.sh/hulthe/seed_router.git#e0a428a8f9186a4590acb2b3771e50290aacbde1" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "seed", + "serde", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +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 = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8" +dependencies = [ + "futures-util", + "log", + "pin-project", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha-1 0.9.8", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "uuid" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "warp" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multipart", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util 0.6.10", + "tower-service", + "tracing", +] + +[[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.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d8de8415c823c8abd270ad483c6feeac771fad964890779f9a8cb24fbbc1bf" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ea3cd4d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +members = ["backend", "common", "frontend"] + +[profile.dev] +# Issue with const-generics +incremental = false + +[profile.release] +lto = true +opt-level = 's' +# Issue with const-generics +incremental = false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2e034d4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,73 @@ +################## +### BASE STAGE ### +################## +FROM rust:1.62.1 as base + +# Install build dependencies +RUN cargo install --locked cargo-make trunk strip_cargo_version +RUN rustup target add wasm32-unknown-unknown +RUN rustup target add x86_64-unknown-linux-musl + +# required by "ring" +RUN apt-get update && apt-get install -y musl-tools + +WORKDIR /app +RUN mkdir frontend backend common + +########################### +### STRIP-VERSION STAGE ### +########################### +FROM base AS strip-version + +COPY Cargo.lock Cargo.toml ./ +COPY frontend/Cargo.toml ./frontend/ +COPY backend/Cargo.toml ./backend/ +COPY common/Cargo.toml ./common/ +RUN strip_cargo_version + +################### +### BUILD STAGE ### +################### +FROM base AS build + +RUN cargo init --lib frontend +RUN cargo init --bin backend +RUN cargo init --lib common + +COPY --from=strip-version /app/frontend/Cargo.toml /app/frontend/ +COPY --from=strip-version /app/backend/Cargo.toml /app/backend/ +COPY --from=strip-version /app/common/Cargo.toml /app/common/ +COPY --from=strip-version /app/Cargo.toml /app/Cargo.lock /app/ + +WORKDIR /app/backend +RUN cargo build --release --target x86_64-unknown-linux-musl + +WORKDIR /app/frontend +RUN cargo build --release --target wasm32-unknown-unknown + +WORKDIR /app +COPY . . + +WORKDIR /app/backend +RUN cargo build --release --target x86_64-unknown-linux-musl +RUN strip /app/target/x86_64-unknown-linux-musl/release/hemma + +WORKDIR /app/frontend +RUN trunk build --release + +######################## +### PRODUCTION STAGE ### +######################## +FROM scratch + +ENV RUST_LOG="info" + +WORKDIR / + +# Copy application binary +COPY --from=build /app/target/x86_64-unknown-linux-musl/release/hemma / + +# Copy static web files +COPY --from=build /app/frontend/dist /www + +CMD ["/hemma", "--bind", "0.0.0.0:8000", "--frontend", "/www/"] diff --git a/backend/Cargo.toml b/backend/Cargo.toml new file mode 100644 index 0000000..957bf92 --- /dev/null +++ b/backend/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "hemma" +version = "0.1.0" +edition = "2021" + +[dependencies] +futures-util = "0.3.21" +log = "0.4.17" +pretty_env_logger = "0.4.0" +tokio = { version = "1.19.2", features = ["full"] } +warp = "0.3.2" +ron = "0.7.1" +reqwest = { version = "0.11.11", default_features = false, features = ["rustls-tls"] } +async-trait = "0.1.56" +anyhow = "1.0.58" +markdown = "0.3.0" +clap = { version = "3.2.6", features = ["derive"] } +toml = "0.5.9" +serde = { version = "1.0.138", features = ["derive"] } +futures = "0.3.21" + +[dependencies.common] +path = "../common" + +[dependencies.lighter_lib] +git = "https://git.nubo.sh/hulthe/lighter.git" +#path = "../../lighter/lib" + +[dependencies.lighter_manager] +git = "https://git.nubo.sh/hulthe/lighter.git" +#path = "../../lighter/manager" diff --git a/backend/example.config.toml b/backend/example.config.toml new file mode 100644 index 0000000..b75a662 --- /dev/null +++ b/backend/example.config.toml @@ -0,0 +1,31 @@ +[mqtt] +#address = "hostname" +#port = 1883 +#username = "user" +#password = "password" + +[collectors] +markdown_web_links = [ + "https://example.org/lmao.md" +] + +[[bulbs]] +id = "light/bedroom" + +[[bulbs]] +id = "light/living_room" + +[[groups]] +name = "Living Room" +bulbs = ["light/living_room"] +x = 0 +y = 0 +shape = { Rectangle = { w = 10, h = 10 } } + +[[groups]] +name = "Bedroom" +bulbs = ["light/bedroom"] +x = 11 +y = 0 +shape = { Rectangle = { w = 10, h = 10 } } + diff --git a/backend/src/collector.rs b/backend/src/collector.rs new file mode 100644 index 0000000..27c4e19 --- /dev/null +++ b/backend/src/collector.rs @@ -0,0 +1,15 @@ +mod markdown_web; + +pub use markdown_web::MarkdownWeb; + +use serde::Deserialize; + +#[async_trait::async_trait] +pub trait Collector { + async fn collect(&mut self) -> anyhow::Result; +} + +#[derive(Deserialize)] +pub struct CollectorConfig { + pub markdown_web_links: Vec, +} diff --git a/backend/src/collector/markdown_web.rs b/backend/src/collector/markdown_web.rs new file mode 100644 index 0000000..82405ab --- /dev/null +++ b/backend/src/collector/markdown_web.rs @@ -0,0 +1,16 @@ +use crate::collector::Collector; +use reqwest::get; + +pub struct MarkdownWeb { + pub url: String, +} + +#[async_trait::async_trait] +impl Collector for MarkdownWeb { + async fn collect(&mut self) -> anyhow::Result { + let text = get(&self.url).await?.text().await?; + let html = markdown::to_html(&text); + + Ok(html) + } +} diff --git a/backend/src/main.rs b/backend/src/main.rs new file mode 100644 index 0000000..503571d --- /dev/null +++ b/backend/src/main.rs @@ -0,0 +1,285 @@ +mod collector; + +use clap::Parser; +use collector::{Collector, CollectorConfig, MarkdownWeb}; +use common::{BulbMap, ClientMessage, ServerMessage}; +use futures_util::{SinkExt, StreamExt}; +use lighter_manager::{ + manager::{BulbCommand, BulbManager, BulbSelector, BulbsConfig}, + mqtt_conf::MqttConfig, +}; +use log::LevelFilter; +use serde::Deserialize; +use std::convert::Infallible; +use std::net::SocketAddr; +use std::path::PathBuf; +use tokio::sync::broadcast::error::RecvError; +use tokio::sync::{broadcast, mpsc}; +use tokio::time::{sleep, Duration}; +use tokio::{fs, select, task}; +use warp::ws::{self, WebSocket}; +use warp::{Filter, Rejection, Reply}; + +#[macro_use] +extern crate log; + +#[derive(Parser)] +struct Opt { + /// More logging + #[clap(short, long, parse(from_occurrences))] + verbose: u8, + + /// Supress non-error logs + #[clap(short, long)] + quiet: bool, + + #[clap(long, short, default_value = "127.0.0.0:8000")] + bind: SocketAddr, + + #[clap(long, default_value = "./www")] + frontend: String, + + #[clap(long, short)] + config: PathBuf, +} + +#[derive(Deserialize)] +struct Config { + mqtt: MqttConfig, + + collectors: CollectorConfig, + + #[serde(flatten)] + bulbs: BulbsConfig, + + #[serde(flatten)] + bulb_map: BulbMap, +} + +struct State { + config: Config, + client_message: broadcast::Sender, + server_message: broadcast::Sender, +} + +#[tokio::main] +async fn main() { + let opt = Opt::parse(); + + let log_level = match opt.verbose { + _ if opt.quiet => LevelFilter::Error, + 0 => LevelFilter::Info, + 1 => LevelFilter::Debug, + 2.. => LevelFilter::Trace, + }; + + pretty_env_logger::formatted_builder() + .default_format() + .filter_level(log_level) + .init(); + + let config = fs::read_to_string(&opt.config) + .await + .expect("Failed to read config"); + let config: Config = toml::from_str(&config).expect("Failed to parse config"); + + // we keep a receiver here to keep the channel active when no clients are connected + let (server_message, _receiver) = broadcast::channel(100); + let (client_message, _) = broadcast::channel(100); + + let state = State { + config, + client_message, + server_message, + }; + let state = Box::leak(Box::new(state)); + + task::spawn(info_collector(state)); + task::spawn(lights_collector(state)); + + let ws = warp::path("ws") + // The `ws()` filter will prepare the Websocket handshake. + .and(warp::ws()) + .map(|ws: warp::ws::Ws| { + // And then our closure will be called when it completes... + ws.on_upgrade(|websocket| { + info!("Client connected {:?}", websocket); + + client_handler(websocket, state) + }) + }); + + let api = warp::path("api").and(ws.recover(not_found)); + + let index_html = format!("{}/index.html", opt.frontend); + let frontend = warp::fs::dir(opt.frontend).or(warp::fs::file(index_html)); + + let routes = api.or(frontend); + + warp::serve(routes).run(opt.bind).await; +} + +async fn not_found(_: Rejection) -> Result { + Ok(warp::http::StatusCode::NOT_FOUND) +} + +#[derive(Clone)] +struct ClientRequest { + message: ClientMessage, + response: mpsc::Sender, +} + +async fn lights_collector(state: &State) { + let config = &state.config; + let server_message = &state.server_message; + let mut client_message = state.client_message.subscribe(); + + let (cmd, bulb_states) = BulbManager::launch(config.bulbs.clone(), config.mqtt.clone()) + .await + .expect("Failed to launch bulb manager"); + + loop { + let notify = bulb_states.notify_on_change(); + sleep(Duration::from_millis(1000 / 10)).await; // limit to 10 updates/second + select! { + _ = notify => { + for (id, mode) in bulb_states.bulbs().await.clone().into_iter() { + if let Err(e) = server_message.send(ServerMessage::BulbMode { id, mode }) { + error!("broadcast channel error: {e}"); + return; + } + } + } + request = client_message.recv() => { + let request = match request { + Ok(r) => r, + Err(_) => continue, + }; + + match request.message { + ClientMessage::SetBulbColor { id, color } => { + if let Err(e) = cmd.send(BulbCommand::SetColor(BulbSelector::Id(id), color)).await { + error!("bulb manager error: {e}"); + } + } + ClientMessage::SetBulbPower { id, power } => { + if let Err(e) = cmd.send(BulbCommand::SetPower(BulbSelector::Id(id), power)).await { + error!("bulb manager error: {e}"); + } + } + ClientMessage::GetBulbs => { + if let Err(e) = request.response.send(ServerMessage::BulbMap(config.bulb_map.clone())).await { + error!("GetBulbs response channel error: {e}"); + return; + } + for (id, mode) in bulb_states.bulbs().await.clone().into_iter() { + if let Err(e) = request.response.send(ServerMessage::BulbMode { id, mode }).await { + error!("GetBulbs response channel error: {e}"); + return; + } + } + } + _ => {} + } + } + } + } +} + +async fn info_collector(state: &State) { + let mut collectors: Vec> = vec![]; + + for url in &state.config.collectors.markdown_web_links { + collectors.push(Box::new(MarkdownWeb { + url: url.to_string(), + })); + } + + let mut collectors = collectors.into_boxed_slice(); + + let server_message = &state.server_message; + + let collectors_len = collectors.len(); + let next = move |i: usize| (i + 1) % collectors_len; + let mut i = 0; + + loop { + sleep(Duration::from_secs(30)).await; + + // don't bother collecting if no clients are connected + // there is always 1 receiver held by main process + if server_message.receiver_count() <= 1 { + continue; + } + + i = next(i); + let collector = &mut collectors[i]; + + let msg = match collector.collect().await { + Ok(html) => ServerMessage::InfoPage { html }, + Err(e) => { + warn!("collector error: {e}"); + continue; + } + }; + + if let Err(e) = server_message.send(msg) { + error!("broadcast channel error: {e}"); + return; + } + } +} + +async fn client_handler(mut socket: WebSocket, state: &State) { + let mut server_message = state.server_message.subscribe(); + let (server_responder, mut server_responses) = mpsc::channel(100); + + async fn handle_server_message(socket: &mut WebSocket, message: ServerMessage) { + let message = match ron::to_string(&message) { + Ok(msg) => msg, + Err(e) => return error!("Failed to serialize message: {e}"), + }; + + if let Err(e) = socket.send(ws::Message::text(message)).await { + return warn!("client error: {e}"); + } + } + + loop { + select! { + response = server_responses.recv() => { + if let Some(message) = response { + handle_server_message(&mut socket, message).await; + } + } + message = server_message.recv() => { + let message = match message { + Ok(msg) => msg, + Err(RecvError::Lagged(_)) => continue, + Err(RecvError::Closed) => return, + }; + handle_server_message(&mut socket, message).await; + + } + message = socket.next() => { + match message { + None => return info!("stream closed"), + Some(Err(e)) => return warn!("client error: {e}"), + Some(Ok(message)) => { + let message = ron::from_str(message.to_str().unwrap()).unwrap(); + + let request = ClientRequest { + message, + response: server_responder.clone(), + }; + + if let Err(e) = state.client_message.send(request) { + return error!("client message handlers error: {e}"); + } + } + + } + } + } + } +} diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000..57b538b --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0.137", features = ["derive"] } + +[dependencies.lighter_lib] +git = "https://git.nubo.sh/hulthe/lighter.git" +#path = "../../lighter/lib" diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 0000000..3ddcac0 --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,65 @@ +use lighter_lib::{BulbColor, BulbId, BulbMode}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[non_exhaustive] +pub enum ServerMessage { + InfoPage { + html: String, + }, + + /// Update the state of a bulb + BulbMode { + id: BulbId, + mode: BulbMode, + }, + + BulbMap(BulbMap), +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[non_exhaustive] +pub enum ClientMessage { + //SubscribeToInfo, + //SubscribeToBulbs, + GetBulbs, + SetBulbColor { id: BulbId, color: BulbColor }, + SetBulbPower { id: BulbId, power: bool }, +} + +/// A geometric description of rooms/groups of light bulbs +#[derive(Default, Deserialize, Serialize, Debug, Clone)] +pub struct BulbMap { + pub groups: Vec, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct BulbGroup { + pub name: String, + pub bulbs: Vec, + pub x: u32, + pub y: u32, + pub shape: BulbGroupShape, +} + +#[derive(Deserialize, Serialize, Debug, Clone, Copy)] +pub enum BulbGroupShape { + Circle { r: u32 }, + Rectangle { w: u32, h: u32 }, +} + +impl BulbGroupShape { + pub fn height(&self) -> u32 { + match self { + &Self::Circle { r } => r, + &Self::Rectangle { h, .. } => h, + } + } + + pub fn width(&self) -> u32 { + match self { + &Self::Circle { r } => r, + &Self::Rectangle { w, .. } => w, + } + } +} diff --git a/frontend/Cargo.lock b/frontend/Cargo.lock new file mode 100644 index 0000000..4656e96 --- /dev/null +++ b/frontend/Cargo.lock @@ -0,0 +1,609 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[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 = "cookie" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +dependencies = [ + "percent-encoding", + "time", + "version_check 0.9.4", +] + +[[package]] +name = "css_typegen" +version = "0.2.0" +source = "git+https://github.com/hulthe/css_typegen.git?branch=master#ed1c4b1b7c8bf19e1ce045cafa12f3886041134c" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "dbg" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4677188513e0e9d7adced5997cf9a1e7a3c996c994f90093325c5332c1a8b221" +dependencies = [ + "version_check 0.1.5", +] + +[[package]] +name = "enclose" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357" + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[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-file" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa5d6084efa4a2b182ef3a8649cb6506cb4843f22cf907c6e0a799944248ae90" +dependencies = [ + "futures-channel", + "gloo-events", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "929c53c913bb7a88d75d9dc3e9705f963d8c2b9001510b25ddaf671b9fb7049d" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "seed" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadc99b3d823229f987d3b5277c00dcff69d5011ed0ed38c20d6aaa66ed7372" +dependencies = [ + "console_error_panic_hook", + "cookie", + "dbg", + "enclose", + "futures", + "getrandom", + "gloo-file", + "gloo-timers", + "gloo-utils", + "indexmap", + "js-sys", + "rand", + "serde", + "serde_json", + "uuid", + "version_check 0.9.4", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "singit2" +version = "0.2.2" +dependencies = [ + "anyhow", + "css_typegen", + "seed", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[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.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml new file mode 100644 index 0000000..6ac585b --- /dev/null +++ b/frontend/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "hemma_web" +version = "0.1.0" +authors = ["Joakim Hulthe `/resource/x/y/z` +#rewrite = "/api/" +#backend = "http://localhost:8000/api/" + diff --git a/frontend/index.html b/frontend/index.html new file mode 100755 index 0000000..8a966a2 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hemma + + + + +
+ + diff --git a/frontend/src/app.rs b/frontend/src/app.rs new file mode 100644 index 0000000..3c0a4c6 --- /dev/null +++ b/frontend/src/app.rs @@ -0,0 +1,151 @@ +use crate::page; +use common::{ClientMessage, ServerMessage}; +use seed::app::orders::OrdersContainer; +use seed::prelude::*; +use seed::{log, window}; +use seed_router::Router; +use std::collections::VecDeque; + +pub type AppOrders = OrdersContainer>>; + +/// Delays between successive attempts to reconnect in case the socket breaks. In seconds. +const TIMEOUT_CONNECT_DELAYS: &[u32] = &[2, 5, 10, 10, 10, 20, 30, 60, 120, 300]; + +pub struct Model { + page: Pages, + send_queue: VecDeque, + socket: WebSocket, + ws_url: String, + timeout_count: usize, +} + +#[derive(Router)] +pub enum Pages { + #[page("404", NotFound)] + NotFound(page::not_found::Model), + + #[page("info", Info)] + Info(page::info::Model), + + #[page("lights", Lights)] + Lights(page::lights::Model), +} + +#[derive(Debug)] +pub enum PageMsg { + NotFound(page::not_found::Msg), + Info(page::info::Msg), + Lights(page::lights::Msg), +} + +#[derive(Debug)] +pub enum Msg { + Page(PageMsg), + + SendMessage(ClientMessage), + FlushMessageQueue, + + // Global + Connect, + SocketOpened(), + SocketClosed(CloseEvent), + SocketError(), + SocketMessage(WebSocketMessage), +} + +pub fn init(url: Url, orders: &mut impl Orders) -> Model { + orders.subscribe(Msg::SendMessage); + + let location = window().location(); + let host = location.host().expect("Failed to get hostname"); + let ws_protocol = match location.protocol().ok().as_deref() { + Some("http:") => "ws", + _ => "wss", + }; + + let ws_url = format!("{ws_protocol}://{host}/api/ws"); + + Model { + page: Pages::from_url(url, &mut orders.proxy(Msg::Page)) + .unwrap_or(Pages::NotFound(Default::default())), + send_queue: Default::default(), + socket: open_socket(&ws_url, orders), + ws_url, + timeout_count: 0, + } +} + +fn open_socket(url: &str, orders: &mut impl Orders) -> WebSocket { + WebSocket::builder(url, orders) + .on_open(Msg::SocketOpened) + .on_close(Msg::SocketClosed) + .on_error(Msg::SocketError) + .on_message(Msg::SocketMessage) + .build_and_open() + .expect("failed to open websocket") +} + +pub fn update(msg: Msg, model: &mut Model, orders: &mut AppOrders) { + #[cfg(debug_assertions)] + log!(format!("{msg:?}")); + + match msg { + Msg::Page(msg) => model.page.update(msg, &mut orders.proxy(Msg::Page)), + Msg::FlushMessageQueue => { + while let Some(message) = model.send_queue.pop_front() { + let serialized = ron::to_string(&message).unwrap(); + + if let Err(e) = model.socket.send_text(serialized) { + model.send_queue.push_front(message); + log!(e); + return; + } + } + } + Msg::Connect => { + model.socket = open_socket(&model.ws_url, orders); + } + Msg::SendMessage(message) => { + model.send_queue.push_back(message); + orders.send_msg(Msg::FlushMessageQueue); + } + Msg::SocketOpened() => { + model.timeout_count = 0; + orders.send_msg(Msg::FlushMessageQueue); + } + Msg::SocketClosed(_event) => { + let timeout_sec = TIMEOUT_CONNECT_DELAYS[model.timeout_count]; + let timeout_ms = timeout_sec * 1000; + orders.perform_cmd(cmds::timeout(timeout_ms, || Msg::Connect)); + + log!(format!( + "Socket closed, trying to reconnect in {timeout_sec} seconds" + )); + + model.timeout_count = TIMEOUT_CONNECT_DELAYS.len().min(model.timeout_count + 1); + } + Msg::SocketError() => {} + Msg::SocketMessage(message) => { + if let Err(e) = handle_ws_msg(message, orders) { + log!(e); + } + } + } +} + +fn handle_ws_msg(message: WebSocketMessage, orders: &mut impl Orders) -> anyhow::Result<()> { + let message = message.text().map_err(|e| anyhow::format_err!("{e:?}"))?; + let message: ServerMessage = ron::from_str(&message)?; + orders.notify(message); + + Ok(()) +} + +pub fn view(model: &Model) -> Vec> { + vec![model.page.view().map_msg(Msg::Page)] + //match &model.page { + // Pages::NotFound => vec![h1!["Not Found"]], + // Pages::InfoScreen => vec![div![C![C.info_box], raw![&model.info_page]]], + // Pages::Lights(page) => vec![], + //} +} diff --git a/frontend/src/components/color_picker.rs b/frontend/src/components/color_picker.rs new file mode 100644 index 0000000..49e6e9e --- /dev/null +++ b/frontend/src/components/color_picker.rs @@ -0,0 +1,225 @@ +use crate::css::C; +use lighter_lib::BulbColor; +use seed::prelude::*; +use seed::{attrs, div, C}; +use std::f32::consts::PI; +use web_sys::MouseEvent; + +#[derive(Default)] +pub struct ColorPicker { + hue: f32, + saturation: f32, + brightness: f32, + temperature: f32, + + mode: ColorPickerSetting, + dragging: Option, +} + +#[derive(Default)] +enum ColorPickerSetting { + #[default] + HSB, + Kelvin, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ColorPickerAttr { + HueSat, + Brightness, + Temperature, +} + +#[derive(Debug)] +pub enum ColorPickerMsg { + MouseDown(ColorPickerAttr, MouseEvent), + MouseMove(ColorPickerAttr, MouseEvent), + MouseUp(Option, MouseEvent), + + SetColor(BulbColor), +} + +impl ColorPicker { + pub fn update(&mut self, msg: ColorPickerMsg, orders: &mut impl Orders) { + match msg { + ColorPickerMsg::MouseDown(target, event) => { + self.dragging = Some(target); + self.handle_mouse_event(target, event); + } + ColorPickerMsg::MouseMove(target, event) => { + self.handle_mouse_event(target, event); + } + ColorPickerMsg::MouseUp(target, event) => { + if let Some(target) = target { + self.handle_mouse_event(target, event); + } + + match self.dragging.take() { + Some(ColorPickerAttr::HueSat) => self.mode = ColorPickerSetting::HSB, + Some(ColorPickerAttr::Brightness) => {} + Some(ColorPickerAttr::Temperature) => self.mode = ColorPickerSetting::Kelvin, + None => return, + } + + let color = match self.mode { + ColorPickerSetting::HSB => { + BulbColor::hsb(self.hue, self.saturation, self.brightness) + } + ColorPickerSetting::Kelvin => { + BulbColor::kelvin(self.temperature, self.brightness) + } + }; + + orders.send_msg(ColorPickerMsg::SetColor(color)); + } + ColorPickerMsg::SetColor { .. } => {} + } + } + + fn handle_mouse_event(&mut self, target: ColorPickerAttr, event: MouseEvent) { + if Some(target) != self.dragging { + return; + } + + let handle_bar = || { + let y = event.offset_y() as f32; + let height = 200.0; + 1.0 - (y / height).clamp(0.0, 1.0) + }; + + match target { + ColorPickerAttr::HueSat => { + let (x, y) = (event.offset_x() as f32, event.offset_y() as f32); + let radius = 100.0; + + let x = x - radius; + let y = y - radius; + + let angle = (x.atan2(y) + PI) / (2.0 * PI); + self.hue = 1.0 - angle; + self.saturation = ((x.powi(2) + y.powi(2)).sqrt() / radius).clamp(0.0, 1.0); + } + ColorPickerAttr::Brightness => self.brightness = handle_bar(), + ColorPickerAttr::Temperature => self.temperature = handle_bar(), + } + } + + pub fn view(&self) -> Node { + use ColorPickerAttr::{Brightness, HueSat, Temperature}; + use ColorPickerMsg::{MouseDown, MouseMove, MouseUp}; + + let (hs_x, hs_y) = { + let radius = 100.0; + let angle = -self.hue * PI * 2.0; + let x = -self.saturation * radius * angle.sin(); + let y = -self.saturation * radius * angle.cos(); + (x + radius - 5.0, y + radius - 5.0) + }; + + let br_y = { + let height = 200.0; + let marker_height = 10.0; + (1.0 - self.brightness) * height - marker_height / 2.0 + }; + + let temp_y = { + let height = 200.0; + let marker_height = 10.0; + (1.0 - self.temperature) * height - marker_height / 2.0 + }; + + let (r, g, b) = hsb_to_rgb(self.hue, 1.0, 1.0); + let saturation_gradient = match self.mode { + ColorPickerSetting::HSB => { + format!("background: linear-gradient(0deg, #000, rgba({r},{g},{b},1));") + } + ColorPickerSetting::Kelvin => format!("background: linear-gradient(0deg, #000, #fff);"), + }; + + div![ + C![C.color_picker], + mouse_ev(Ev::MouseUp, |ev| MouseUp(None, ev)), + div![ + C![C.color_wheel], + div![ + C![C.color_wheel_marker], + attrs! { + At::Style => format!("margin-left: {hs_x}px; margin-top: {hs_y}px;"), + }, + ], + mouse_ev(Ev::MouseDown, |ev| MouseDown(HueSat, ev)), + mouse_ev(Ev::MouseMove, |ev| MouseMove(HueSat, ev)), + mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(HueSat), ev)), + //mouse_ev(Ev::MouseLeave, |ev| MouseUp(HueSat, ev)), + ], + div![ + C![C.brightness_bar], + attrs! { At::Style => saturation_gradient }, + div![ + C![C.color_bar_marker], + attrs! { + At::Style => format!("margin-top: {br_y}px;"), + }, + ], + mouse_ev(Ev::MouseDown, |ev| MouseDown(Brightness, ev)), + mouse_ev(Ev::MouseMove, |ev| MouseMove(Brightness, ev)), + mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(Brightness), ev)), + //mouse_ev(Ev::MouseLeave, |ev| MouseUp(Brightness, ev)), + ], + div![ + C![C.temperature_bar], + div![ + C![C.color_bar_marker], + attrs! { + At::Style => format!("margin-top: {temp_y}px;"), + }, + ], + mouse_ev(Ev::MouseDown, |ev| MouseDown(Temperature, ev)), + mouse_ev(Ev::MouseMove, |ev| MouseMove(Temperature, ev)), + mouse_ev(Ev::MouseUp, |ev| MouseUp(Some(Temperature), ev)), + //mouse_ev(Ev::MouseLeave, |ev| MouseUp(Temperature, ev)), + ], + ] + } + + pub fn set_hsb(&mut self, h: f32, s: f32, b: f32) { + self.hue = h; + self.saturation = s; + self.brightness = b; + self.mode = ColorPickerSetting::HSB; + } + + pub fn set_kelvin(&mut self, t: f32, b: f32) { + self.temperature = t; + self.brightness = b; + self.mode = ColorPickerSetting::Kelvin; + } + + pub fn set_color(&mut self, color: BulbColor) { + match color { + BulbColor::HSB { h, s, b } => self.set_hsb(h, s, b), + BulbColor::Kelvin { t, b } => self.set_kelvin(t, b), + } + } +} + +fn hsb_to_rgb(h: f32, s: f32, b: f32) -> (u8, u8, u8) { + let h = 360.0 * h.clamp(0.0, 1.0); + + let c = b * s; // chroma + + let x = c * (1. - ((h / 60.) % 2. - 1.).abs()); + let m = b - c; + let m = |v| ((v + m) * 255.0) as u8; + + let (r, g, b) = match h { + _ if h < 60. => (c, x, 0.0), + _ if h < 120.0 => (x, c, 0.0), + _ if h < 180.0 => (0.0, c, x), + _ if h < 240.0 => (0.0, x, c), + _ if h < 300.0 => (x, 0.0, c), + _ => (c, 0.0, x), + }; + + (m(r), m(g), m(b)) +} diff --git a/frontend/src/components/mod.rs b/frontend/src/components/mod.rs new file mode 100644 index 0000000..5f83f0b --- /dev/null +++ b/frontend/src/components/mod.rs @@ -0,0 +1 @@ +pub mod color_picker; diff --git a/frontend/src/css.rs b/frontend/src/css.rs new file mode 100644 index 0000000..a6f664c --- /dev/null +++ b/frontend/src/css.rs @@ -0,0 +1,7 @@ +use css_typegen::css_typegen; + +// NOTE: Remember to edit index.html when adding new css-files! + +// Generate rust types for css-classes. +// Used for autocompletion and extra compile-time checks. +css_typegen!("frontend/static/styles"); diff --git a/frontend/src/lib.rs b/frontend/src/lib.rs new file mode 100644 index 0000000..f030495 --- /dev/null +++ b/frontend/src/lib.rs @@ -0,0 +1,12 @@ +mod app; +mod components; +mod css; +mod page; + +use seed::prelude::wasm_bindgen; +use seed::App; + +#[wasm_bindgen(start)] +pub fn start() { + App::start("app", app::init, app::update, app::view); +} diff --git a/frontend/src/page/info.rs b/frontend/src/page/info.rs new file mode 100644 index 0000000..167dbf8 --- /dev/null +++ b/frontend/src/page/info.rs @@ -0,0 +1,39 @@ +use common::ServerMessage; +use seed::prelude::*; +use seed::{div, raw}; +use seed_router::Page; + +#[derive(Default)] +pub struct Model { + content: String, +} + +#[derive(Debug)] +pub enum Msg { + ServerMessage(ServerMessage), +} + +impl Page for Model { + type Msg = Msg; + + fn new(orders: &mut impl Orders) -> Self { + orders.subscribe(Msg::ServerMessage); + + Model { + content: r#"
"#.into(), + } + } + + fn update(&mut self, msg: Self::Msg, _orders: &mut impl Orders) { + match msg { + Msg::ServerMessage(ServerMessage::InfoPage { html }) => { + self.content = html; + } + Msg::ServerMessage(_) => {} + } + } + + fn view(&self) -> Node { + div![raw![&self.content]] + } +} diff --git a/frontend/src/page/lights.rs b/frontend/src/page/lights.rs new file mode 100644 index 0000000..e30e230 --- /dev/null +++ b/frontend/src/page/lights.rs @@ -0,0 +1,240 @@ +use crate::components::color_picker::{ColorPicker, ColorPickerMsg}; +use crate::css::C; +use common::{BulbGroup, BulbGroupShape, BulbMap, ClientMessage, ServerMessage}; +use lighter_lib::{BulbId, BulbMode}; +use seed::prelude::*; +use seed::{attrs, button, div, C}; +use seed_router::Page; +use std::collections::{BTreeMap, HashSet}; +use std::fmt::Write; + +/// /lights page +#[derive(Default)] +pub struct Model { + bulb_states: BTreeMap, + + bulb_map: BulbMap, + + /// The currently selected bulb map groups + selected_groups: HashSet, + + /// Whether the currently selected map groups have been interacted with + groups_interacted: bool, + + color_picker: ColorPicker, +} + +#[derive(Debug)] +pub enum Msg { + ServerMessage(ServerMessage), + + SelectGroup(usize), + DeselectGroups, + ColorPicker(ColorPickerMsg), + SetBulbPower(bool), +} + +impl Page for Model { + type Msg = Msg; + + fn new(orders: &mut impl Orders) -> Self { + orders.subscribe(Msg::ServerMessage); + orders.notify(ClientMessage::GetBulbs); + + Model::default() + } + + fn update(&mut self, msg: Self::Msg, orders: &mut impl Orders) { + match msg { + Msg::ServerMessage(msg) => match msg { + ServerMessage::BulbMode { id, mode: new_mode } => { + *self.bulb_states.entry(id).or_default() = new_mode + //color_picker.set_color(mode.color); + } + ServerMessage::BulbMap(bulb_map) => { + self.bulb_map = bulb_map; + self.selected_groups.clear(); + } + _ => {} + }, + Msg::DeselectGroups => { + self.selected_groups.clear(); + } + Msg::SelectGroup(index) => { + if self.groups_interacted { + self.groups_interacted = false; + // If this group is the only selected group, don't clear it + if self.selected_groups.len() != 1 || !self.selected_groups.contains(&index) { + self.selected_groups.clear(); + } + } + + if !self.selected_groups.insert(index) { + self.selected_groups.remove(&index); + } else { + let bulb = self + .bulb_map + .groups + .get(index) + .and_then(|group| group.bulbs.first()) + .and_then(|id| self.bulb_states.get(id)); + + if let Some(bulb) = bulb { + self.color_picker.set_color(bulb.color); + } + } + } + Msg::ColorPicker(ColorPickerMsg::SetColor(color)) => { + self.groups_interacted = true; + self.for_selected_bulbs(|id, _| { + let message = ClientMessage::SetBulbColor { + id: id.clone(), + color, + }; + orders.notify(message); + }); + } + Msg::ColorPicker(msg) => { + self.color_picker + .update(msg, &mut orders.proxy(|msg| Msg::ColorPicker(msg))); + } + Msg::SetBulbPower(power) => { + self.groups_interacted = true; + self.for_selected_bulbs(|id, _| { + let message = ClientMessage::SetBulbPower { + id: id.clone(), + power, + }; + orders.notify(message); + }); + } + } + } + + fn view(&self) -> Node { + //let view_bulb = |(id, (mode, color_picker)): (&BulbId, &(BulbMode, ColorPicker))| { + // div![ + // C![C.bulb_box], + // h1![id], + // div![ + // C![C.bulb_controls], + // { + // let id = id.clone(); + // color_picker.view().map_msg(|msg| Msg::ColorPicker(id, msg)) + // }, + // button![ + // if mode.power { + // C![C.bulb_power_button, C.bulb_power_button_on] + // } else { + // C![C.bulb_power_button] + // }, + // { + // let id = id.clone(); + // let power = !mode.power; + // ev(Ev::Click, move |_| Msg::SetBulbPower(id, power)) + // }, + // ], + // ], + // ] + //}; + + let bulb_map_width = self + .bulb_map + .groups + .iter() + .map(|group| group.x + group.shape.width()) + .max() + .unwrap_or(0); + + let bulb_map_height = self + .bulb_map + .groups + .iter() + .map(|group| group.y + group.shape.height()) + .max() + .unwrap_or(0); + + let view_bulb_group = |(i, group): (usize, &BulbGroup)| { + let (w, h) = (group.shape.width(), group.shape.height()); + let mut style = String::new(); + write!( + &mut style, + "margin-left: {}rem; margin-top: {}rem; width: {}rem; height: {}rem;", + group.x, group.y, w, h + ) + .ok(); + + if let BulbGroupShape::Circle { r } = group.shape { + write!(&mut style, " border-radius: {r}rem;").ok(); + } + + div![ + &group.name[..1], + if self.selected_groups.contains(&i) { + C![C.bulb_group, C.bulb_group_selected] + } else { + C![C.bulb_group] + }, + attrs! { + At::Style => style, + }, + ev(Ev::Click, move |event| { + event.stop_propagation(); + Msg::SelectGroup(i) + }), + ] + }; + + let (_color, power) = self + .selected_groups + .iter() + .next() + .and_then(|&index| self.bulb_map.groups.get(index)) + .and_then(|group| group.bulbs.first()) + .and_then(|id| self.bulb_states.get(id)) + .map(|bulb| (bulb.color, bulb.power)) + .unwrap_or_default(); + + div![ + C![C.bulb_box], + div![ + C![C.bulb_map], + attrs! { + At::Style => format!("width: {}rem; height: {}rem;", bulb_map_width, bulb_map_height), + }, + ev(Ev::Click, |_| Msg::DeselectGroups), + self.bulb_map.groups.iter().enumerate().map(view_bulb_group), + ], + div![ + C![C.bulb_controls], + self.color_picker + .view() + .map_msg(|msg| Msg::ColorPicker(msg)), + button![ + if power { + C![C.bulb_power_button, C.bulb_power_button_on] + } else { + C![C.bulb_power_button] + }, + ev(Ev::Click, move |_| Msg::SetBulbPower(!power)), + div![attrs! { At::Id => "switch_socket" }], + div![attrs! { At::Id => "off_label" }, "Off"], + div![attrs! { At::Id => "on_label" }, "On"], + div![attrs! { At::Id => "lever_stem" }], + div![attrs! { At::Id => "lever_face" }], + ], + ], + ] + } +} + +impl Model { + fn for_selected_bulbs(&self, mut f: impl FnMut(&BulbId, &BulbMode)) { + self.selected_groups + .iter() + .filter_map(|&index| self.bulb_map.groups.get(index)) + .flat_map(|group| group.bulbs.iter()) + .filter_map(|id| self.bulb_states.get(id).map(|bulb| (id, bulb))) + .for_each(|(id, bulb)| f(id, bulb)); + } +} diff --git a/frontend/src/page/mod.rs b/frontend/src/page/mod.rs new file mode 100644 index 0000000..fe122ff --- /dev/null +++ b/frontend/src/page/mod.rs @@ -0,0 +1,3 @@ +pub mod info; +pub mod lights; +pub mod not_found; diff --git a/frontend/src/page/not_found.rs b/frontend/src/page/not_found.rs new file mode 100644 index 0000000..0a2e3b6 --- /dev/null +++ b/frontend/src/page/not_found.rs @@ -0,0 +1,25 @@ +use seed::h1; +use seed::prelude::*; +use seed_router::Page; + +#[derive(Default)] +pub struct Model; + +#[derive(Debug)] +pub enum Msg {} + +impl Page for Model { + type Msg = Msg; + + fn new(_orders: &mut impl Orders) -> Self { + Model + } + + fn update(&mut self, msg: Self::Msg, _orders: &mut impl Orders) { + match msg {} + } + + fn view(&self) -> Node { + h1!["404: Not found"] + } +} diff --git a/frontend/static/images/blueprint_bg.png b/frontend/static/images/blueprint_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..82ea8b8d5a15c8f1759290aa63501d596f204419 GIT binary patch literal 4071 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 Z{vTP+^<%g*M0o%J002ovPDHLkV1gh7w}$`# literal 0 HcmV?d00001 diff --git a/frontend/static/images/hsb.png b/frontend/static/images/hsb.png new file mode 100644 index 0000000000000000000000000000000000000000..2b728156889fd330b805acae9091107264de92dd GIT binary patch literal 142125 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Μ)pHJm`T##!r2F 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 literal 0 HcmV?d00001 diff --git a/frontend/static/images/penguin1.svg b/frontend/static/images/penguin1.svg new file mode 100644 index 0000000..7a3c662 --- /dev/null +++ b/frontend/static/images/penguin1.svg @@ -0,0 +1,84 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/frontend/static/images/penguin2.svg b/frontend/static/images/penguin2.svg new file mode 100644 index 0000000..f639671 --- /dev/null +++ b/frontend/static/images/penguin2.svg @@ -0,0 +1,66 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/frontend/static/images/penguin3.svg b/frontend/static/images/penguin3.svg new file mode 100644 index 0000000..a8adfb6 --- /dev/null +++ b/frontend/static/images/penguin3.svg @@ -0,0 +1,67 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/frontend/static/styles/common.scss b/frontend/static/styles/common.scss new file mode 100644 index 0000000..48f7d55 --- /dev/null +++ b/frontend/static/styles/common.scss @@ -0,0 +1,267 @@ +body { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #302f3b; + color: #ffffff; + height: 100%; + font-family: Ubuntu Mono,monospace; + font-size: x-large; +} + +@media (max-width: 460px) { + body { + font-size: large; + } +} + +.info_box { + margin: auto; + max-width: 40em; +} + +.nobr { + white-space: nowrap; +} + +.center { + margin: auto; +} + +.hidden { + visibility: hidden; +} + + /* Tooltip container */ + .tooltip { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; /* If you want dots under the hoverable text */ +} + +/* Tooltip text */ +.tooltip .tooltiptext { + visibility: hidden; + width: 120px; + background-color: #555; + color: #fff; + text-align: center; + padding: 5px 0; + border-radius: 6px; + + /* Position the tooltip text */ + position: absolute; + z-index: 1; + top: 125%; + left: 50%; + margin-left: -100px; + + /* Fade in tooltip */ + opacity: 0; + transition: opacity 0.3s; +} + +/* Tooltip arrow */ +.tooltip .tooltiptext::after { + content: ""; + position: absolute; + bottom: 100%; + left: 100px; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent #555 transparent; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.tooltip:hover .tooltiptext { + visibility: visible; + opacity: 1; +} + +.bulb_box { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: space-around; + width: fit-content; +} + +.bulb_box > * { + margin: 0.5em; +} + +.bulb_controls { + display: flex; + flex-direction: row; + align-items: center; + padding-right: 0.5em; + background: #56636e; + border: solid 0.25em #5b3f63; + +} + +.bulb_map { + background: url(images/blueprint_bg.png); + background-size: auto; + background-size: 1em; + padding: 2rem; + border: solid 0.4rem #5b3f63; +} + +.bulb_map::after { + position: absolute; + width: 100%; + height: 100%; + content: #0003; +} + +.bulb_group { + color: black; + text-align: center; + background: #aaaaaaaa; + border: solid 0.25rem white; + border-radius: 0.25rem; + font-size: 2em; + position: absolute; + box-shadow: #0006 0.1em 0.1em 0.1em; + transition: 0.3s ease-in-out; +} + +.bulb_group_selected { + border-color: gold; + scale: 1.05; + transition: 0.3s ease-in-out; +} + +.bulb_power_button { + width: 70px; + height: 175px; + border-radius: 50px; + margin-top: 1em; + margin-bottom: 1em; + background-color: #b5b5b5; + transition: background-color 0.2s ease-in-out; +} + +.bulb_power_button_on { +} + +.bulb_power_button > div { + position: absolute; + width: 40px; + margin-left: 8.75px; + color: #000; + font-weight: 700; +} + +.bulb_power_button > #lever_face { + height: 40px; + background-color: #cccccc; + margin-top: 25px; + transition: 0.3s ease-in-out; +} + +.bulb_power_button_on > #lever_face { + margin-top: -65px; +} + +.bulb_power_button > #lever_stem { + height: 30px; + background-color: #eeeeee; + margin-top: 0px; + transition: 0.3s ease-in-out; +} + +.bulb_power_button_on > #lever_stem { + margin-top: -30px; +} + +.bulb_power_button > #off_label { + height: 30px; + background-color: #cccccc; + padding-top: 15px; + margin-top: -45px; +} + +.bulb_power_button > #on_label { + height: 30px; + background-color: #cccccc; + padding-top: 15px; + margin-top: 0px; +} + +.bulb_power_button > #switch_socket { + width: 47.5px; + margin-top: -55px; + margin-left: 0; + height: 100px; + background-color: #4f4f4f; + border: solid 5px #fff; + border-radius: 5px; +} + +.color_picker { + display: flex; + flex-direction: row; + padding: 0.5em; +} + +.color_wheel { + background-image: url(/images/hsb.png); + width: 200px; + height: 200px; + background-size: contain; + border: solid 5px #a4829c; + border-radius: 200px; +} + +.color_wheel_marker { + width: 6px; + height: 6px; + background: white; + border: solid 2px black; + border-radius: 10px; + position: absolute; + pointer-events: none; + + transition: margin 0.1s ease-out; +} + +.brightness_bar { + width: 30px; + height: 200px; + margin-left: 10px; + border: solid 5px #a4829c; +} + +.temperature_bar { + width: 30px; + height: 200px; + margin-left: 10px; + background: linear-gradient(0deg, #f81, #eff); + border: solid 5px #a4829c; +} + +.color_bar_marker { + width: 30px; + height: 8px; + border-top: solid 2px black; + border-bottom: solid 2px black; + position: absolute; + background: white; + pointer-events: none; + + transition: margin 0.1s ease-out; +} diff --git a/frontend/static/styles/penguin.scss b/frontend/static/styles/penguin.scss new file mode 100644 index 0000000..d934142 --- /dev/null +++ b/frontend/static/styles/penguin.scss @@ -0,0 +1,59 @@ +@keyframes penguin-spin { + 0% { + transform: perspective(36em) rotateY(-90deg); + background-image: url(/images/penguin1.svg); + } + 24.99% { + transform: perspective(36em) rotateY(90deg); + background-image: url(/images/penguin1.svg); + } + 25% { + transform: perspective(36em) rotateY(90deg); + background-image: url(/images/penguin2.svg); + } + 49.99% { + transform: perspective(36em) rotateY(270deg); + background-image: url(/images/penguin2.svg); + } + 50% { + transform: perspective(36em) rotateY(270deg); + background-image: url(/images/penguin3.svg); + } + 74.99% { + transform: perspective(36em) rotateY(450deg); + background-image: url(/images/penguin3.svg); + } + 75% { + transform: perspective(36em) rotateY(450deg); + background-image: url(/images/penguin2.svg); + } + 99.99% { + transform: perspective(36em) rotateY(630deg); + background-image: url(/images/penguin2.svg); + } + 100% { + transform: perspective(36em) rotateY(630deg); + background-image: url(/images/penguin1.svg); + } +} + +.penguin { + width: 12em; + height: 12em; + margin: auto; + margin-top: 1em; + margin-bottom: 1em; + background-image: url(/images/penguin1.svg); + background-size: contain; + animation-name: penguin-spin; + animation-duration: 4s; + animation-iteration-count: infinite; + animation-timing-function: cubic-bezier(0.1, 0.5, 0.9, 0.5); +} + +.penguin_small { + width: 1.5em; + height: 1.5em; + margin-top: 0em; + margin-bottom: 0em; +}