diff --git a/.direnv/flake-profile b/.direnv/flake-profile index 814e327..e0f476a 120000 --- a/.direnv/flake-profile +++ b/.direnv/flake-profile @@ -1 +1 @@ -flake-profile-45-link \ No newline at end of file +flake-profile-48-link \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 19f7cff..5b0032d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,6 +606,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -724,7 +733,7 @@ dependencies = [ "bevy_transform", "bevy_utils", "blake3", - "derive_more", + "derive_more 1.0.0", "downcast-rs", "either", "petgraph 0.6.5", @@ -748,7 +757,7 @@ dependencies = [ "bevy_utils", "console_error_panic_hook", "ctrlc", - "derive_more", + "derive_more 1.0.0", "downcast-rs", "wasm-bindgen", "web-sys", @@ -774,7 +783,7 @@ dependencies = [ "bitflags 2.11.1", "blake3", "crossbeam-channel", - "derive_more", + "derive_more 1.0.0", "disqualified", "downcast-rs", "either", @@ -831,7 +840,7 @@ dependencies = [ "bevy_math", "bevy_reflect", "bytemuck", - "derive_more", + "derive_more 1.0.0", "encase", "serde", "wgpu-types 23.0.0", @@ -871,7 +880,7 @@ dependencies = [ "bevy_utils", "bevy_window", "bitflags 2.11.1", - "derive_more", + "derive_more 1.0.0", "nonmax", "radsort", "serde", @@ -919,7 +928,7 @@ dependencies = [ "bevy_utils", "bitflags 2.11.1", "concurrent-queue", - "derive_more", + "derive_more 1.0.0", "disqualified", "fixedbitset 0.5.7", "nonmax", @@ -961,7 +970,7 @@ dependencies = [ "bevy_input", "bevy_time", "bevy_utils", - "derive_more", + "derive_more 1.0.0", "gilrs", ] @@ -1025,7 +1034,7 @@ dependencies = [ "bevy_tasks", "bevy_transform", "bevy_utils", - "derive_more", + "derive_more 1.0.0", "gltf", "percent-encoding", "serde", @@ -1061,7 +1070,7 @@ dependencies = [ "bevy_utils", "bitflags 2.11.1", "bytemuck", - "derive_more", + "derive_more 1.0.0", "futures-lite", "image", "ktx2", @@ -1082,7 +1091,7 @@ dependencies = [ "bevy_math", "bevy_reflect", "bevy_utils", - "derive_more", + "derive_more 1.0.0", "smol_str", ] @@ -1164,7 +1173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edec18d90e6bab27b5c6131ee03172ece75b7edd0abe4e482a26d6db906ec357" dependencies = [ "bevy_reflect", - "derive_more", + "derive_more 1.0.0", "glam 0.29.3", "itertools 0.13.0", "rand 0.8.6", @@ -1190,7 +1199,7 @@ dependencies = [ "bevy_utils", "bitflags 2.11.1", "bytemuck", - "derive_more", + "derive_more 1.0.0", "hexasphere", "serde", "wgpu 23.0.1", @@ -1226,7 +1235,7 @@ dependencies = [ "bevy_window", "bitflags 2.11.1", "bytemuck", - "derive_more", + "derive_more 1.0.0", "fixedbitset 0.5.7", "nonmax", "radsort", @@ -1274,7 +1283,7 @@ dependencies = [ "bevy_ptr", "bevy_reflect_derive", "bevy_utils", - "derive_more", + "derive_more 1.0.0", "disqualified", "downcast-rs", "erased-serde", @@ -1327,7 +1336,7 @@ dependencies = [ "bevy_window", "bytemuck", "codespan-reporting 0.11.1", - "derive_more", + "derive_more 1.0.0", "downcast-rs", "encase", "futures-lite", @@ -1373,7 +1382,7 @@ dependencies = [ "bevy_render", "bevy_transform", "bevy_utils", - "derive_more", + "derive_more 1.0.0", "serde", "uuid", ] @@ -1400,7 +1409,7 @@ dependencies = [ "bevy_window", "bitflags 2.11.1", "bytemuck", - "derive_more", + "derive_more 1.0.0", "fixedbitset 0.5.7", "guillotiere", "nonmax", @@ -1470,7 +1479,7 @@ dependencies = [ "bevy_utils", "bevy_window", "cosmic-text 0.12.1", - "derive_more", + "derive_more 1.0.0", "serde", "smallvec", "sys-locale", @@ -1501,7 +1510,7 @@ dependencies = [ "bevy_hierarchy", "bevy_math", "bevy_reflect", - "derive_more", + "derive_more 1.0.0", ] [[package]] @@ -1531,7 +1540,7 @@ dependencies = [ "bevy_utils", "bevy_window", "bytemuck", - "derive_more", + "derive_more 1.0.0", "nonmax", "smallvec", "taffy", @@ -2016,10 +2025,13 @@ dependencies = [ ] [[package]] -name = "cassowary" -version = "0.3.0" +name = "castaway" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] [[package]] name = "cc" @@ -2059,9 +2071,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -2209,7 +2221,6 @@ dependencies = [ "chrono", "clap", "clover-hub-macros", - "crossterm 0.28.1", "decorum", "futures", "git2", @@ -2224,6 +2235,7 @@ dependencies = [ "overflow-proof", "queues", "rand 0.8.6", + "ratatui", "regex", "rmp-serde", "rodio 0.20.1", @@ -2244,7 +2256,7 @@ dependencies = [ "tracing", "tracing-log", "tracing-subscriber", - "tui", + "tui-logger", "url", "uuid", "zenoh", @@ -2333,6 +2345,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2432,6 +2458,15 @@ dependencies = [ "const_soft_float", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -2696,32 +2731,17 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" -dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot 0.12.3", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "bitflags 2.11.1", "crossterm_winapi", - "mio 1.0.3", + "derive_more 2.1.1", + "document-features", + "mio", "parking_lot 0.12.3", - "rustix 0.38.44", - "serde", + "rustix 1.0.7", "signal-hook", "signal-hook-mio", "winapi", @@ -2765,6 +2785,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf 0.11.3", +] + [[package]] name = "ctor-lite" version = "0.1.0" @@ -2794,7 +2824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" dependencies = [ "bitflags 2.11.1", - "libloading 0.7.4", + "libloading 0.8.9", "winapi", ] @@ -2858,6 +2888,12 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + [[package]] name = "der" version = "0.7.10" @@ -2899,7 +2935,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", ] [[package]] @@ -2914,6 +2959,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", +] + [[package]] name = "digest" version = "0.10.7" @@ -2986,7 +3044,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.9", ] [[package]] @@ -3283,6 +3341,16 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set 0.5.3", + "regex", +] + [[package]] name = "fast-srgb8" version = "1.0.0" @@ -3336,6 +3404,23 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -4071,7 +4156,7 @@ dependencies = [ "bitflags 2.11.1", "com", "libc", - "libloading 0.7.4", + "libloading 0.8.9", "thiserror 1.0.69", "widestring", "winapi", @@ -4990,6 +5075,15 @@ dependencies = [ "serde", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + [[package]] name = "inflections" version = "1.1.1" @@ -5036,6 +5130,19 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instability" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "instant" version = "0.1.13" @@ -5127,10 +5234,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" dependencies = [ "jiff-static", + "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde", + "windows-sys 0.59.0", ] [[package]] @@ -5144,6 +5253,21 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "jiff-tzdb" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -5203,6 +5327,17 @@ dependencies = [ "serde", ] +[[package]] +name = "kasuari" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe90c1150662e858c7d5f945089b7517b0a80d8bf7ba4b1b5ffc984e7230a5b" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.12", +] + [[package]] name = "keccak" version = "0.1.6" @@ -5272,6 +5407,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "lazy_static" version = "1.5.0" @@ -5437,6 +5578,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "line-clipping" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.11.1", +] + [[package]] name = "linebender_resource_handle" version = "0.1.1" @@ -5509,6 +5659,9 @@ name = "lru" version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown 0.16.1", +] [[package]] name = "lru-slab" @@ -5577,6 +5730,16 @@ dependencies = [ "twox-hash", ] +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix 0.29.0", + "winapi", +] + [[package]] name = "macaddr" version = "1.0.1" @@ -5645,6 +5808,12 @@ dependencies = [ "libc", ] +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + [[package]] name = "memoffset" version = "0.7.1" @@ -5740,18 +5909,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - [[package]] name = "mio" version = "1.0.3" @@ -5771,7 +5928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029e1f407e261176a983a6599c084efd322d9301028055c87174beac71397ba3" dependencies = [ "log", - "mio 1.0.3", + "mio", "nix 0.29.0", "serialport", "winapi", @@ -6264,6 +6421,15 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -7044,6 +7210,16 @@ dependencies = [ "serde", ] +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + [[package]] name = "phf_generator" version = "0.11.3" @@ -7595,6 +7771,91 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +[[package]] +name = "ratatui" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termwiz", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" +dependencies = [ + "bitflags 2.11.1", + "compact_str", + "hashbrown 0.16.1", + "indoc", + "itertools 0.14.0", + "kasuari", + "lru 0.16.3", + "strum 0.27.1", + "thiserror 2.0.12", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3" +dependencies = [ + "cfg-if", + "crossterm", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f1342a13e83e4bb9d0b793d0ea762be633f9582048c892ae9041ef39c936f4" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f76fe0bd0ed4295f0321b1676732e2454024c15a35d01904ddb315afd3d545c" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.16.1", + "indoc", + "instability", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "strum 0.27.1", + "time", + "unicode-segmentation", + "unicode-width 0.2.0", +] + [[package]] name = "ratchet" version = "0.1.0" @@ -8658,8 +8919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", - "mio 0.8.11", - "mio 1.0.3", + "mio", "signal-hook", ] @@ -9464,6 +9724,69 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf 0.11.3", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bitflags 2.11.1", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset 0.4.2", + "hex 0.4.3", + "lazy_static", + "libc", + "log", + "memmem", + "nix 0.29.0", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf 0.11.3", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", +] + [[package]] name = "tesseract" version = "0.1.0" @@ -9543,7 +9866,9 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde_core", "time-core", @@ -9671,7 +9996,7 @@ checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", - "mio 1.0.3", + "mio", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", @@ -9939,17 +10264,20 @@ dependencies = [ ] [[package]] -name = "tui" -version = "0.19.0" +name = "tui-logger" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" +checksum = "1a6965ab2d37d9bcb0de9eb62631540ff4043048785f35136c58ef233f887a50" dependencies = [ - "bitflags 1.3.2", - "cassowary", - "crossterm 0.25.0", - "serde", + "env_filter", + "jiff", + "lazy_static", + "log", + "parking_lot 0.12.3", + "ratatui", + "tracing", + "tracing-subscriber", "unicode-segmentation", - "unicode-width 0.1.14", ] [[package]] @@ -10114,6 +10442,17 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-truncate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" +dependencies = [ + "itertools 0.14.0", + "unicode-segmentation", + "unicode-width 0.2.0", +] + [[package]] name = "unicode-width" version = "0.1.14" @@ -10191,6 +10530,7 @@ version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ + "atomic", "getrandom 0.4.2", "js-sys", "serde_core", @@ -10262,6 +10602,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -10645,6 +10994,78 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +[[package]] +name = "wezterm-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" +dependencies = [ + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.3", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-dynamic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", +] + +[[package]] +name = "wezterm-dynamic-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wezterm-input-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] + [[package]] name = "wgpu" version = "0.19.4" @@ -10858,7 +11279,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.7.4", + "libloading 0.8.9", "log", "metal 0.27.0", "naga 0.19.2", diff --git a/clover-hub/Cargo.toml b/clover-hub/Cargo.toml index adec43e..16e5c97 100644 --- a/clover-hub/Cargo.toml +++ b/clover-hub/Cargo.toml @@ -36,11 +36,8 @@ uart = ["dep:serialport", "dep:tokio-serial"] [dependencies] # CLI -crossterm = { version = "0.28.1", features = ["serde"] } -tui = { version = "0.19", default-features = false, features = [ - 'crossterm', - 'serde', -] } +ratatui = "0.30.0" +tui-logger = { version = "0.18.2", features = ["tracing-support"] } clap = { version = "4.5.4", features = ["derive"] } # Debugging Tools diff --git a/clover-hub/src/lib.rs b/clover-hub/src/lib.rs index 311972f..5c4e308 100644 --- a/clover-hub/src/lib.rs +++ b/clover-hub/src/lib.rs @@ -2,6 +2,7 @@ #![feature(ascii_char)] #![feature(trivial_bounds)] +pub mod logging; pub mod server; pub mod tui; pub mod utils; @@ -22,6 +23,7 @@ use std::time::Duration; use tokio::time; use tokio_util::sync::CancellationToken; +use crate::logging::setup_logging; use crate::server::server_main; use crate::tui::tui_main; @@ -42,18 +44,7 @@ pub fn cli() -> Command { .flatten_help(true) .args(aio_args()) .subcommand(Command::new("aio").args(aio_args())) - .subcommand( - Command::new("server") - .arg( - Arg::new("data_dir") - .short('d') - .long("data-dir") - .required(false) - .default_value("/opt/clover") - .help("The data directory to use other than `/opt/clover`"), - ) - .arg(port_arg()), - ) + .subcommand(Command::new("server").arg(data_dir_arg()).arg(port_arg())) .subcommand( Command::new("tui") .arg( @@ -81,8 +72,17 @@ pub fn port_arg() -> Arg { )) } +pub fn data_dir_arg() -> Arg { + Arg::new("data_dir") + .short('d') + .long("data-dir") + .required(false) + .default_value("/opt/clover") + .help("The data directory to use other than `/opt/clover`") +} + pub fn aio_args() -> Vec { - vec![port_arg()] + vec![data_dir_arg(), port_arg()] } pub fn unwrap_port_arg(arg: Result) -> u16 { @@ -198,11 +198,14 @@ pub async fn run(big_boy_token: CancellationToken) { let matches = Box::leak(Box::new(cli().get_matches())); let subcommand = matches.subcommand(); + let aio_shutdown_token = big_boy_token.clone(); match subcommand { Some(("run", sub_matches)) => { let run_command = sub_matches.subcommand().unwrap_or(("aio", sub_matches)); match run_command { ("aio", sub_matches) => { + let logging_provider = setup_logging(false); + info!("Starting CloverHub!"); let cancellation_token = CancellationToken::new(); let from_server_token = CancellationToken::new(); @@ -232,12 +235,11 @@ pub async fn run(big_boy_token: CancellationToken) { }); let tui_port = Arc::new(port); - let tui_token = cancellation_token.clone(); let tui_handle = tokio::task::spawn(async move { let _ = tui_main( *tui_port.to_owned(), Ok::("localhost".to_string()).ok(), - tui_token, + aio_shutdown_token, ) .await; }); @@ -250,10 +252,13 @@ pub async fn run(big_boy_token: CancellationToken) { tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle, server_handle]) => { info!("Exiting..."); + let _ = logging_provider.shutdown(); exit(0); }} } ("server", sub_matches) => { + let logging_provider = setup_logging(true); + info!("Starting CloverHub!"); let from_server_token = CancellationToken::new(); let server_cancellation_token_clone = from_server_token.clone(); @@ -282,10 +287,13 @@ pub async fn run(big_boy_token: CancellationToken) { tokio::select! {_ = futures::future::join_all(vec![signal_handle, server_handle]) => { info!("Exiting..."); + let _ = logging_provider.shutdown(); exit(0); }} } ("tui", sub_matches) => { + let logging_provider = setup_logging(false); + info!("Starting CloverHub!"); let cancellation_token = CancellationToken::new(); let host = sub_matches @@ -300,12 +308,11 @@ pub async fn run(big_boy_token: CancellationToken) { info!("Running Terminal UI..."); let tui_host = Arc::new(host); - let tui_token = cancellation_token.clone(); let tui_handle = tokio::task::spawn(async move { tui_main( port, Ok::((*tui_host.to_owned()).to_string()).ok(), - tui_token, + aio_shutdown_token, ) .await .err(); @@ -315,6 +322,7 @@ pub async fn run(big_boy_token: CancellationToken) { tokio::select! {_ = futures::future::join_all(vec![signal_handle, tui_handle]) => { info!("Exiting..."); + let _ = logging_provider.shutdown(); exit(0); }} } @@ -329,7 +337,7 @@ pub async fn run(big_boy_token: CancellationToken) { .into_iter() .flatten() .collect::>(); - info!("Calling out to {ext:?} with {args:?}"); + println!("Calling out to {ext:?} with {args:?}"); } _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!() } diff --git a/clover-hub/src/logging.rs b/clover-hub/src/logging.rs new file mode 100644 index 0000000..0b10792 --- /dev/null +++ b/clover-hub/src/logging.rs @@ -0,0 +1,73 @@ +use std::sync::Arc; + +use opentelemetry_appender_tracing::layer; +use opentelemetry_sdk::logs::SdkLoggerProvider; +use opentelemetry_sdk::Resource; +use tracing_log::LogTracer; +use tracing_subscriber::{ + prelude::*, + EnvFilter, +}; + +pub fn setup_logging(use_stdout: bool) -> SdkLoggerProvider { + // This *shouldn't* ever break. + LogTracer::init().unwrap(); + + // let exporter = opentelemetry_stdout::LogExporter::default(); + let provider: SdkLoggerProvider = SdkLoggerProvider::builder() + .with_resource(Resource::builder().with_service_name("clover-hub").build()) + // TODO: Send logs to Zenoh log endpoint. + // .with_simple_exporter(exporter) + .build(); + + // To prevent a telemetry-induced-telemetry loop, OpenTelemetry's own internal + // logging is properly suppressed. However, logs emitted by external components + // (such as reqwest, tonic, etc.) are not suppressed as they do not propagate + // OpenTelemetry context. Until this issue is addressed + // (https://github.com/open-telemetry/opentelemetry-rust/issues/2877), + // filtering like this is the best way to suppress such logs. + // + // The filter levels are set as follows: + // - Allow `info` level and above by default. + // - Completely restrict logs from `hyper`, `tonic`, `h2`, and `reqwest`. + // + let otel_filter = EnvFilter::new("info") + .add_directive("hyper=off".parse().unwrap()) + .add_directive("tonic=off".parse().unwrap()) + .add_directive("h2=off".parse().unwrap()) + .add_directive("reqwest=off".parse().unwrap()); + let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider).with_filter(otel_filter); + + let env_filter = EnvFilter::try_from_env("CLOVER_LOG") + .unwrap_or_else(|_| EnvFilter::new("info").add_directive("clover_hub=debug".parse().unwrap())); + let stdout_layer = tracing_subscriber::fmt::layer() + .with_writer(std::io::stderr) + .with_thread_names(true) + .with_filter(env_filter); + + // No, I can't just option the .with(...) because rust is stupid when it comes to traits as types in uninitalized variables. + if use_stdout { + let subscriber = tracing_subscriber::registry() + .with(otel_layer) + .with(stdout_layer); + // .with(zenoh_layer); + + tracing::subscriber::set_global_default(subscriber) + .expect("Failed to set global tracing subscriber"); + } else { + let subscriber = tracing_subscriber::registry() + .with(otel_layer) + .with(tui_logger::TuiTracingSubscriberLayer); + // .with(zenoh_layer); + + tui_logger::init_logger(tui_logger::LevelFilter::Debug).unwrap(); + + tracing::subscriber::set_global_default(subscriber) + .expect("Failed to set global tracing subscriber"); + } + + // Debugging console for tokio + // console_subscriber::init(); + + provider +} diff --git a/clover-hub/src/main.rs b/clover-hub/src/main.rs index 2e96393..a139fca 100644 --- a/clover-hub/src/main.rs +++ b/clover-hub/src/main.rs @@ -11,65 +11,13 @@ //! Terminal User Interface to manage a clover instance over UART/SSH. //! -use opentelemetry_appender_tracing::layer; -use opentelemetry_sdk::logs::SdkLoggerProvider; -use opentelemetry_sdk::Resource; use std::error::Error; use tokio_util::sync::CancellationToken; -use tracing_log::LogTracer; -use tracing_subscriber::{ - prelude::*, - EnvFilter, -}; use clover_hub::run; #[tokio::main] pub async fn main() -> Result<(), Box> { - LogTracer::init()?; - - // let exporter = opentelemetry_stdout::LogExporter::default(); - let provider: SdkLoggerProvider = SdkLoggerProvider::builder() - .with_resource(Resource::builder().with_service_name("clover-hub").build()) - // TODO: Send logs to Zenoh log endpoint. - // .with_simple_exporter(exporter) - .build(); - - // To prevent a telemetry-induced-telemetry loop, OpenTelemetry's own internal - // logging is properly suppressed. However, logs emitted by external components - // (such as reqwest, tonic, etc.) are not suppressed as they do not propagate - // OpenTelemetry context. Until this issue is addressed - // (https://github.com/open-telemetry/opentelemetry-rust/issues/2877), - // filtering like this is the best way to suppress such logs. - // - // The filter levels are set as follows: - // - Allow `info` level and above by default. - // - Completely restrict logs from `hyper`, `tonic`, `h2`, and `reqwest`. - // - let otel_filter = EnvFilter::new("info") - .add_directive("hyper=off".parse().unwrap()) - .add_directive("tonic=off".parse().unwrap()) - .add_directive("h2=off".parse().unwrap()) - .add_directive("reqwest=off".parse().unwrap()); - let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider).with_filter(otel_filter); - - let env_filter = EnvFilter::try_from_env("CLOVER_LOG") - .unwrap_or_else(|_| EnvFilter::new("info").add_directive("clover_hub=debug".parse().unwrap())); - let stdout_layer = tracing_subscriber::fmt::layer() - .with_thread_names(true) - .with_filter(env_filter); - - let subscriber = tracing_subscriber::registry() - .with(otel_layer) - .with(stdout_layer); - // .with(zenoh_layer); - - tracing::subscriber::set_global_default(subscriber) - .expect("Failed to set global tracing subscriber"); - - // Debugging console for tokio - // console_subscriber::init(); - let big_boy_token = CancellationToken::new(); tokio::select! { @@ -77,7 +25,5 @@ pub async fn main() -> Result<(), Box> { _ = big_boy_token.cancelled() => {} } - let _ = provider.shutdown(); - Ok(()) } diff --git a/clover-hub/src/server/appd/mod.rs b/clover-hub/src/server/appd/mod.rs index bc7ae99..2a0d447 100644 --- a/clover-hub/src/server/appd/mod.rs +++ b/clover-hub/src/server/appd/mod.rs @@ -14,12 +14,6 @@ use bollard::{ }; use docker::remove_app; use ipc::handle_ipc_msg; -use log::{ - debug, - error, - info, - warn, -}; use models::AppDStore; use nexus::{ arbiter::models::ApiKeyWithoutUID, @@ -28,6 +22,13 @@ use nexus::{ }; use std::sync::Arc; use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + info, + instrument, + warn, +}; // TODO: Create application manifest schema/models @@ -48,6 +49,7 @@ pub async fn gen_user() -> UserConfig { } } +#[instrument(skip(store, user, cancellation_tokens))] pub async fn appd_main( store: AppDStore, user: NexusUser, diff --git a/clover-hub/src/server/inference_engine/ipc.rs b/clover-hub/src/server/inference_engine/ipc.rs index ae2800f..8b13789 100644 --- a/clover-hub/src/server/inference_engine/ipc.rs +++ b/clover-hub/src/server/inference_engine/ipc.rs @@ -1,57 +1 @@ -use anyhow::anyhow; -use log::{ - debug, - info, -}; -use nexus::server::models::IPCMessageWithId; -use serde::{ - Deserialize, - Serialize, -}; -use std::str::FromStr; -use strum::VariantNames; -use tokio::sync::broadcast::Sender; -use url::Url; -#[derive(Debug, PartialEq)] -pub enum Events { - None, -} - -impl FromStr for Events { - type Err = anyhow::Error; - - fn from_str(input: &str) -> Result { - match input { - "" => Ok(Events::None), - "/" => Ok(Events::None), - _ => Err(anyhow!("String \"{}\" not part of enum!", input)), - } - } -} - -pub async fn handle_ipc_msg(ipc_rx: Sender) { - while let Ok(msg) = ipc_rx.subscribe().recv().await { - let kind = Url::parse(&msg.kind.clone()).unwrap(); - - // Verify that we care about this event. - if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.inference-engine") { - debug!("Processing: {}", msg.kind.clone()); - - match Events::from_str(kind.path()) { - Ok(event_type) => { - match event_type { - _ => { - // TODO - debug!("TODO"); - } - } - } - Err(_e) => { - // TODO - debug!("TODO"); - } - } - } - } -} diff --git a/clover-hub/src/server/inference_engine/mod.rs b/clover-hub/src/server/inference_engine/mod.rs index 9168f41..a2f6aef 100644 --- a/clover-hub/src/server/inference_engine/mod.rs +++ b/clover-hub/src/server/inference_engine/mod.rs @@ -7,12 +7,6 @@ pub mod ipc; -use ipc::handle_ipc_msg; -use log::{ - debug, - error, - info, -}; use nexus::{ arbiter::models::ApiKeyWithoutUID, server::models::UserConfig, @@ -21,6 +15,13 @@ use nexus::{ use std::sync::Arc; use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + info, + instrument, + span, +}; use super::warehouse::config::models::Config; @@ -57,6 +58,7 @@ impl InferenceEngineStore { } } +#[instrument(skip(inference_engine_store, user, cancellation_tokens))] pub async fn inference_engine_main( inference_engine_store: InferenceEngineStore, user: NexusUser, @@ -64,41 +66,64 @@ pub async fn inference_engine_main( ) { info!("Starting Inference Engine..."); - let ipc_recv_token = cancellation_tokens.0.clone(); - let (ipc_rx, ipc_handle) = user.subscribe(); - let ipc_recv_handle = tokio::task::spawn(async move { - tokio::select! { - _ = ipc_recv_token.cancelled() => { - debug!("ipc_recv exited"); - }, - _ = handle_ipc_msg(ipc_rx) => {} + let mut zenoh_config = zenoh::Config::default(); + + zenoh_config.insert_json5("connect/endpoints", "tcp/localhost:6699"); + + debug!("Connecting to Zenoh..."); + let session = Arc::new(zenoh::open(zenoh_config).await.unwrap()); + debug!("Connected to Zenoh!"); + + let ipc_token = cancellation_tokens.0.clone(); + let ipc_session = session.clone(); + let ipc_handle = tokio::task::spawn(async move { + let subscriber = ipc_session + .declare_subscriber("com/reboot-codes/clover/server/inference_engine/**") + .await + .unwrap(); + + while !ipc_token.is_cancelled() { + match subscriber.recv_async().await { + Ok(sample) => { + // Refer to z_bytes.rs to see how to deserialize different types of message + let payload = sample + .payload() + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); + + debug!( + ">> [Subscriber] Received {} ('{}': '{}')", + sample.kind(), + sample.key_expr().as_str(), + payload + ); + if let Some(att) = sample.attachment() { + let att = att.try_to_string().unwrap_or_else(|e| e.to_string().into()); + debug!(" ({att})"); + } + } + Err(msg) => { + error!("{}", msg); + } + } } }); - - let init_user = Arc::new(user.clone()); + let init_session = session.clone(); cancellation_tokens .0 .run_until_cancelled(async move { - match init_user.send( - &"nexus://com.reboot-codes.clover.inference-engine/status".to_string(), - &"finished-init".to_string(), - &None, - ) { - Err(e) => { - error!( - "Error when letting peers know about complete init status: {}", - e - ); - } - _ => {} - } + let init_publisher = init_session + .declare_publisher("com/reboot-codes/clover/server/inference_engine/status") + .await + .unwrap(); + + init_publisher.put("ready"); }) .await; let cleanup_token = cancellation_tokens.0.clone(); tokio::select! { _ = cleanup_token.cancelled() => { - ipc_recv_handle.abort(); ipc_handle.abort(); info!("Cleaning up networks..."); diff --git a/clover-hub/src/server/modman/mod.rs b/clover-hub/src/server/modman/mod.rs index e5662e8..339253e 100644 --- a/clover-hub/src/server/modman/mod.rs +++ b/clover-hub/src/server/modman/mod.rs @@ -15,12 +15,6 @@ pub mod modules; use busses::start_busses; use ipc::handle_ipc_msg; -use log::{ - debug, - error, - info, - warn, -}; use models::ModManStore; use modules::{ deinit_module, @@ -33,6 +27,13 @@ use nexus::{ }; use std::sync::Arc; use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + info, + instrument, + warn, +}; /// The minimum required permissions and configuration for ModMan to use Nexus. pub async fn gen_user() -> UserConfig { @@ -53,6 +54,7 @@ pub async fn gen_user() -> UserConfig { } /// Begin the ModMan threads and sub-processes to ensure module/compoent communications. +#[instrument(skip(store, user, cancellation_tokens))] pub async fn modman_main( store: ModManStore, user: NexusUser, diff --git a/clover-hub/src/server/renderer/mod.rs b/clover-hub/src/server/renderer/mod.rs index 096a875..327a7df 100644 --- a/clover-hub/src/server/renderer/mod.rs +++ b/clover-hub/src/server/renderer/mod.rs @@ -14,11 +14,6 @@ pub mod system_ui; use self::system_ui::system_ui_main; use crate::utils::RecvSync; use ipc::handle_ipc_msg; -use log::error; -use log::{ - debug, - info, -}; use nexus::{ arbiter::models::ApiKeyWithoutUID, server::models::UserConfig, @@ -30,6 +25,12 @@ use std::sync::Mutex as StdMutex; use system_ui::SystemUIIPC; use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + info, + instrument, +}; use super::warehouse::config::models::Config; @@ -67,6 +68,7 @@ impl RendererStore { } } +#[instrument(skip(store, user, cancellation_tokens))] pub async fn renderer_main( store: RendererStore, user: NexusUser, diff --git a/clover-hub/src/server/warehouse/mod.rs b/clover-hub/src/server/warehouse/mod.rs index 7dff110..56ea4fa 100644 --- a/clover-hub/src/server/warehouse/mod.rs +++ b/clover-hub/src/server/warehouse/mod.rs @@ -15,11 +15,6 @@ pub mod repos; use config::models::Config; use ipc::handle_ipc_msg; -use log::{ - debug, - error, - info, -}; use models::WarehouseStore; use nexus::user::NexusUser; use nexus::{ @@ -40,6 +35,12 @@ use tokio::io::{ AsyncWriteExt, }; use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + info, + instrument, +}; /// The primary startup Error enum. /// Warehouse will return this enum in [`setup_warehouse`]. @@ -62,6 +63,7 @@ pub enum Error { /// 1. Ensures that the data directory exists, /// 2. Loads the core [configuration file](config) (paired management devices, permanently attached hardware, core Modules to initalize, etc), /// 3. and preps [Repository storage](repos). +#[instrument] pub async fn setup_warehouse(data_dir: String, store: Arc) -> Result<(), Error> { let mut err = None; let mut data_dir_path = OsPath::new().join(data_dir.clone()); @@ -237,6 +239,7 @@ pub async fn gen_user() -> UserConfig { } /// Main service function for Warehouse. Maintains an ongoing connection to Zenoh, and will manage filesystem operations as needed. +#[instrument(skip(store, user, cancellation_tokens))] pub async fn warehouse_main( store: Arc, user: NexusUser, diff --git a/clover-hub/src/tui/mod.rs b/clover-hub/src/tui/mod.rs index d2239a6..921e6c1 100644 --- a/clover-hub/src/tui/mod.rs +++ b/clover-hub/src/tui/mod.rs @@ -1,85 +1,114 @@ -use crossterm::{ - event::{ - DisableMouseCapture, - EnableMouseCapture, +use ratatui::{ + crossterm::event::{ + self, + Event, + KeyCode, + KeyEvent, + KeyEventKind, }, - execute, - terminal::{ - disable_raw_mode, - enable_raw_mode, - EnterAlternateScreen, - LeaveAlternateScreen, + prelude::*, + widgets::{ + Block, + Borders, + Tabs, }, }; -use log::info; use std::{ io, - thread, time::Duration, }; use tokio_util::sync::CancellationToken; -use tui::{ - backend::CrosstermBackend, - layout::{ - Constraint, - Direction, - Layout, - }, - style::{ - Color, - Style, - }, - text::{ - Span, - Spans, - }, - widgets::{ - Block, - Borders, - Paragraph, - }, - Terminal, +use tracing::{ + debug, + info, + instrument, +}; +use tui_logger::{ + TuiLoggerLevelOutput, + TuiLoggerSmartWidget, }; +#[instrument] pub async fn tui_main( port: u16, host: Option, - cancellation_token: CancellationToken, + server_cancellation_token: CancellationToken, ) -> Result<(), io::Error> { - info!("Starting TUI..."); + let mut app = CloverTUI::new(server_cancellation_token); + ratatui::run(move |terminal| app.run(terminal)); + Ok(()) +} - // setup terminal - enable_raw_mode().err(); - let mut stdout = io::stdout(); - execute!(stdout, EnterAlternateScreen, EnableMouseCapture).err(); - let backend = CrosstermBackend::new(stdout); - let mut terminal = Terminal::new(backend)?; +type LazyResult = std::result::Result>; - terminal.draw(|f| { - let chunks = Layout::default() - .direction(Direction::Vertical) - .margin(1) - .constraints([Constraint::Percentage(100)].as_ref()) - .split(f.size()); - let title = Paragraph::new(vec![Spans::from(Span::styled( - format!("Connecting to {}:{}...", host.unwrap(), port), - Style::default().fg(Color::Yellow), - ))]) - .block(Block::default().title("Clover TUI").borders(Borders::ALL)); - f.render_widget(title, chunks[0]); - })?; +struct CloverTUI { + server_cancellation_token: CancellationToken, +} - thread::sleep(Duration::from_millis(5000)); +impl CloverTUI { + fn new(server_cancellation_token: CancellationToken) -> Self { + Self { + server_cancellation_token, + } + } - // restore terminal - disable_raw_mode().err(); - execute!( - terminal.backend_mut(), - LeaveAlternateScreen, - DisableMouseCapture - ) - .err(); - terminal.show_cursor().err(); + fn run(&mut self, terminal: &mut ratatui::DefaultTerminal) -> LazyResult<()> { + while !self.server_cancellation_token.is_cancelled() { + terminal.draw(|frame| self.render(frame))?; + self.handle_events()?; + } + Ok(()) + } - Ok(()) + fn render(&mut self, frame: &mut ratatui::Frame) { + let area = frame.area(); + let buf = frame.buffer_mut(); + + let [tabs_area, smart_area, help_area] = Layout::vertical([ + Constraint::Length(3), + Constraint::Fill(50), + Constraint::Length(3), + ]) + .areas(area); + + TuiLoggerSmartWidget::default() + .style_error(Style::default().fg(Color::Red)) + .style_debug(Style::default().fg(Color::Green)) + .style_warn(Style::default().fg(Color::Yellow)) + .style_trace(Style::default().fg(Color::Magenta)) + .style_info(Style::default().fg(Color::Cyan)) + .output_separator(':') + .output_timestamp(Some("%H:%M:%S".to_string())) + .output_level(Some(TuiLoggerLevelOutput::Abbreviated)) + .output_target(true) + .output_file(true) + .output_line(true) + .render(smart_area, buf); + + Text::from(vec!["Q: Quit".into()]) + .style(Color::Gray) + .centered() + .render(help_area, buf); + } + + fn handle_events(&mut self) -> LazyResult<()> { + if event::poll(Duration::from_millis(30))? { + match event::read()? { + // it's important to check that the event is a key press event as + // crossterm also emits key release and repeat events on Windows. + Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { + self.handle_key_event(key_event) + } + _ => {} + }; + } + Ok(()) + } + + fn handle_key_event(&mut self, key_event: KeyEvent) { + match key_event.code { + KeyCode::Char('q') => self.server_cancellation_token.cancel(), + _ => {} + } + } } diff --git a/flake.nix b/flake.nix index f921bbf..8e63222 100644 --- a/flake.nix +++ b/flake.nix @@ -129,7 +129,7 @@ # nix develop devShells.default = let - cloverEnv = pkgs.writeShellScriptBin "clover-up" '' + cloverCompose = pkgs.writeShellScriptBin "clover-up" '' CURRENT_REPO_ROOT=${pkgs.git}/bin/git rev-parse --show-toplevel 2>/dev/null # Fallback to the current working directory if not inside a git repo @@ -149,6 +149,26 @@ exec ${pkgs.process-compose}/bin/process-compose up --no-server -f $PROCESS_COMPOSE_FILE ''; + + cloverHubCMD = pkgs.writeShellScriptBin "clover-hub" '' + # Ensure that libraries are actually passed to the development setup. + LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath libraries}" + RUST_BACKTRACE=1 + CLOVER_LOG="clover=debug,clover-hub-macros=debug,wgpu_hal=error" + CLOVER_SIMULATED_CONTROLS="true" + CLOVER_MASTER_PRINT="true" + + exec cargo run --bin="clover-hub" -- $@ + ''; + + cloverHubZenoh = pkgs.writeShellScriptBin "clover-zenoh" '' + RUST_LOG=info,zenohd=debug + + exec zenohd -l tcp/0.0.0.0:6699 --adminspace-permissions rw \ + --cfg='adminspace/enabled:true' \ + --cfg='adminspace/permissions/read:true' \ + --cfg='adminspace/permissions/write:true' + ''; in craneLib.devShell { inherit buildInputs; @@ -163,7 +183,9 @@ tokio-console zenoh process-compose - cloverEnv + cloverCompose + cloverHubCMD + cloverHubZenoh flutter ]) ++ libraries; diff --git a/process-compose.yaml b/process-compose.yaml index eab3852..399c3c3 100644 --- a/process-compose.yaml +++ b/process-compose.yaml @@ -3,15 +3,14 @@ version: "0.5" processes: zenohd-router: command: > - zenohd -l tcp/0.0.0.0:6699 --adminspace-permissions rw --cfg=':{metadata:{name:"com.reboot-codes.clover.server"},adminspace:{enabled:true,permissions:{read:true,write:true}}' + clover-zenoh availability: restart: "always" clover-hub: command: > - RUST_BACKTRACE=1 CLOVER_LOG="clover=debug,clover-hub-macros=debug,wgpu_hal=error" CLOVER_SIMULATED_CONTROLS="true" CLOVER_MASTER_PRINT="true" cargo run --bin="clover-hub" run server + clover-hub run server availability: restart: "on_failure" - # Wait until the local Zenoh TCP socket is actively listening before booting the hub depends_on: zenohd-router: condition: process_started diff --git a/todo.md b/todo.md index 180e9b3..2519179 100644 --- a/todo.md +++ b/todo.md @@ -3,6 +3,7 @@ - [ ] CloverHub - [ ] Server - [ ] Centralize common crates and types + - [ ] Fix TUI segfault bug - [ ] Move to Tracing - [x] add `tracing`, `tracing-subscriber`, `tracing-log` - [ ] Add file parsing for log rules @@ -15,6 +16,7 @@ - [ ] Move to Zenoh for in-memory store (RocksDB?) - [ ] Implement dynamic host IDs - [ ] Refactor IPC threads + - [ ] Add debug screen to TUI - [ ] Create system theme paradigm (theme colors) - [ ] Renderer - [ ] SystemUI diff --git a/website/public/.gitignore b/website/public/.gitignore new file mode 100644 index 0000000..8e695ec --- /dev/null +++ b/website/public/.gitignore @@ -0,0 +1 @@ +doc diff --git a/website/src/components/nav/BigHero.astro b/website/src/components/nav/BigHero.astro new file mode 100644 index 0000000..d0ea537 --- /dev/null +++ b/website/src/components/nav/BigHero.astro @@ -0,0 +1,8 @@ +--- +const { class: className, ...rest } = Astro.props; +--- + +
+
+ +
diff --git a/website/src/components/nav/NavBar.astro b/website/src/components/nav/NavBar.astro new file mode 100644 index 0000000..d1300ae --- /dev/null +++ b/website/src/components/nav/NavBar.astro @@ -0,0 +1,5 @@ +
+
+

C.L.O.V.E.R.

+
+