feat: dynamic count of machines, use config
This commit is contained in:
@@ -1 +1,2 @@
|
||||
/target
|
||||
config.toml
|
||||
Generated
+285
-27
@@ -32,6 +32,23 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.6.1"
|
||||
@@ -102,6 +119,9 @@ name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@@ -147,9 +167,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.4.3"
|
||||
version = "1.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d"
|
||||
checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
@@ -203,6 +223,55 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.15.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b85f248a4de22d204ceabc6299d89d2c70fbd7f09fea53c06c852369652d8139"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"convert_case 0.6.0",
|
||||
"json5",
|
||||
"pathdiff",
|
||||
"ron",
|
||||
"rust-ini",
|
||||
"serde-untagged",
|
||||
"serde_core",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"winnow",
|
||||
"yaml-rust2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.10.0"
|
||||
@@ -280,6 +349,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
@@ -302,9 +377,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88490bf1b990d87eaaa7ac8aa887f629a08e7359765b4911faf63c3763347d23"
|
||||
checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -312,26 +387,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "084e274f91c482280130e1e34e0b8d6e66776a060d7b6de7b84289ca778868c4"
|
||||
checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff"
|
||||
dependencies = [
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.24.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f5792fa0d41cd2325ce0ffa64f0a340eaebd4971a3a0c5e1ffd2cc488a355e"
|
||||
checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -364,7 +439,7 @@ version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"convert_case 0.10.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
@@ -381,6 +456,15 @@ dependencies = [
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlv-list"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
|
||||
dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.12"
|
||||
@@ -398,9 +482,18 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.17.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
@@ -408,6 +501,17 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
@@ -557,7 +661,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -634,6 +738,12 @@ dependencies = [
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
@@ -656,6 +766,15 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -693,7 +812,7 @@ dependencies = [
|
||||
"indoc",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -732,6 +851,17 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json5"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kasuari"
|
||||
version = "0.4.12"
|
||||
@@ -799,9 +929,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
@@ -827,6 +957,7 @@ name = "machinetui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"config",
|
||||
"crossterm",
|
||||
"futures",
|
||||
"rand 0.10.2",
|
||||
@@ -956,6 +1087,16 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
|
||||
dependencies = [
|
||||
"dlv-list",
|
||||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "palette"
|
||||
version = "0.7.7"
|
||||
@@ -1012,6 +1153,12 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.9.0"
|
||||
@@ -1345,6 +1492,20 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81116b9531d61eabc41aeb228e4b6b2435bcca3233b98cf3b3077d4e6e9debb3"
|
||||
dependencies = [
|
||||
"bitflags 2.13.1",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"typeid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rumqttc"
|
||||
version = "0.25.1"
|
||||
@@ -1366,6 +1527,16 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ordered-multimap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -1398,7 +1569,7 @@ dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.103.14",
|
||||
"rustls-webpki 0.103.15",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -1446,9 +1617,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.14"
|
||||
version = "0.103.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a"
|
||||
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
@@ -1522,6 +1693,18 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-untagged"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
@@ -1539,7 +1722,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1555,6 +1738,15 @@ dependencies = [
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
@@ -1703,9 +1895,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||
checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1825,7 +2017,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1860,6 +2052,15 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.53.1"
|
||||
@@ -1885,7 +2086,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1923,6 +2124,43 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.4+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.3+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
@@ -1978,9 +2216,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.24.1"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9"
|
||||
checksum = "f053576934f05a761a402421fbbe3d425d9366f75f978806a037b3ca481abecc"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"getrandom 0.4.3",
|
||||
@@ -2245,12 +2483,32 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust2"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b36710ce3a279cfce8465dbab826f161675a262950b922cb2c3663852dfe9eb0"
|
||||
dependencies = [
|
||||
"arraydeque",
|
||||
"encoding_rs",
|
||||
"hashlink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.9.0"
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.104"
|
||||
config = "0.15.25"
|
||||
crossterm = { version = "0.29.0", features = ["event-stream"] }
|
||||
futures = "0.3.34"
|
||||
rand = "0.10.2"
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use anyhow::Result;
|
||||
use rumqttc::MqttOptions;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ConfigData {
|
||||
pub mqtt: MqttConfig,
|
||||
#[serde(rename = "machine", default)]
|
||||
pub machines: Vec<MachineConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MqttConfig {
|
||||
pub device_id: String,
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MachineConfig {
|
||||
pub name: String,
|
||||
pub topic: String,
|
||||
}
|
||||
|
||||
pub fn load() -> Result<ConfigData> {
|
||||
let source = config::File::with_name("config").format(config::FileFormat::Toml);
|
||||
let config = config::Config::builder().add_source(source).build()?;
|
||||
Ok(config.try_deserialize()?)
|
||||
}
|
||||
|
||||
impl MqttConfig {
|
||||
pub fn as_options(&self) -> MqttOptions {
|
||||
MqttOptions::new(&self.device_id, &self.host, self.port)
|
||||
}
|
||||
}
|
||||
+18
-26
@@ -1,11 +1,11 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use rumqttc::{AsyncClient, Event, MqttOptions, Packet, Publish, QoS};
|
||||
use rumqttc::{AsyncClient, Event, Packet, Publish, QoS};
|
||||
use serde::Deserialize;
|
||||
use time::{OffsetDateTime, PrimitiveDateTime};
|
||||
|
||||
use crate::{data, events};
|
||||
use crate::{config::ConfigData, data, events};
|
||||
|
||||
time::serde::format_description!(
|
||||
tasmota_time,
|
||||
@@ -13,11 +13,8 @@ time::serde::format_description!(
|
||||
"[year]-[month]-[day]T[hour]:[minute]:[second]"
|
||||
);
|
||||
|
||||
const MACHINE1_TOPIC: &str = "tele/tasmota_F68B94/SENSOR";
|
||||
const MACHINE2_TOPIC: &str = "tele/tasmota_F81A3C/SENSOR";
|
||||
|
||||
pub struct MachineData {
|
||||
pub name: String,
|
||||
pub topic: String,
|
||||
pub voltage: f32,
|
||||
pub current: f32,
|
||||
pub last_updated: OffsetDateTime,
|
||||
@@ -40,12 +37,12 @@ pub struct TasmotaEnergyData {
|
||||
current: f32,
|
||||
}
|
||||
|
||||
fn publish_to_machine_data(name: String, publish: Publish) -> Result<data::MachineData> {
|
||||
fn publish_to_machine_data(topic: String, publish: Publish) -> Result<data::MachineData> {
|
||||
let data = publish.payload.to_vec();
|
||||
let data: TasmotaData = serde_json::from_slice(&data)?;
|
||||
|
||||
Ok(data::MachineData {
|
||||
name,
|
||||
topic,
|
||||
voltage: data.energy.voltage,
|
||||
current: data.energy.current,
|
||||
last_updated: data.time.assume_utc(),
|
||||
@@ -65,36 +62,31 @@ fn start_timestamp_task(event_sender: events::EventSender) {
|
||||
});
|
||||
}
|
||||
|
||||
async fn start_data_fetch_task(event_sender: events::EventSender) -> Result<()> {
|
||||
let options = MqttOptions::new("machinetui", "192.168.178.251", 1883);
|
||||
async fn start_data_fetch_task(
|
||||
config: &ConfigData,
|
||||
event_sender: events::EventSender,
|
||||
) -> Result<()> {
|
||||
let options = config.mqtt.as_options();
|
||||
let (client, mut event_loop) = AsyncClient::new(options, 10);
|
||||
|
||||
client.subscribe(MACHINE1_TOPIC, QoS::AtLeastOnce).await?;
|
||||
client.subscribe(MACHINE2_TOPIC, QoS::AtLeastOnce).await?;
|
||||
for machine in &config.machines {
|
||||
client.subscribe(&machine.topic, QoS::AtLeastOnce).await?;
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Keep client alive
|
||||
let _client = client;
|
||||
|
||||
loop {
|
||||
match event_loop.poll().await {
|
||||
Ok(Event::Incoming(Packet::Publish(publish))) => match publish.topic.as_str() {
|
||||
MACHINE1_TOPIC => {
|
||||
let machine_data =
|
||||
publish_to_machine_data("machine 1".into(), publish).unwrap();
|
||||
topic => {
|
||||
let machine_data = publish_to_machine_data(topic.into(), publish).unwrap();
|
||||
event_sender
|
||||
.send(events::Event::MachineUpdate(machine_data))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
MACHINE2_TOPIC => {
|
||||
let machine_data =
|
||||
publish_to_machine_data("machine 2".into(), publish).unwrap();
|
||||
event_sender
|
||||
.send(events::Event::MachineUpdate(machine_data))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Ok(_) => {}
|
||||
Err(_err) => {}
|
||||
@@ -105,8 +97,8 @@ async fn start_data_fetch_task(event_sender: events::EventSender) -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn start(event_sender: events::EventSender) -> Result<()> {
|
||||
pub async fn start(config: &ConfigData, event_sender: events::EventSender) -> Result<()> {
|
||||
start_timestamp_task(event_sender.clone());
|
||||
start_data_fetch_task(event_sender).await?;
|
||||
start_data_fetch_task(config, event_sender).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+9
-4
@@ -1,16 +1,21 @@
|
||||
use anyhow::Result;
|
||||
|
||||
mod config;
|
||||
mod data;
|
||||
mod events;
|
||||
mod interaction;
|
||||
mod tui;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let config = config::load()?;
|
||||
let (event_sender, event_receiver) = events::channel();
|
||||
|
||||
data::start(event_sender.clone()).await?;
|
||||
tokio::try_join!(tui::start(event_receiver), interaction::start(event_sender))?;
|
||||
data::start(&config, event_sender.clone()).await?;
|
||||
tokio::try_join!(
|
||||
tui::start(&config, event_receiver),
|
||||
interaction::start(event_sender)
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+88
-44
@@ -1,71 +1,96 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::{
|
||||
prelude::*,
|
||||
symbols::border,
|
||||
widgets::{Block, Padding, Paragraph},
|
||||
widgets::{Axis, Block, Chart, Dataset, GraphType, Padding, Paragraph},
|
||||
};
|
||||
use time::{OffsetDateTime, format_description::BorrowedFormatItem, macros::format_description};
|
||||
|
||||
use crate::{data, events};
|
||||
use crate::{
|
||||
config::ConfigData,
|
||||
data::{self},
|
||||
events,
|
||||
};
|
||||
|
||||
const TIME_FORMAT: &'static [BorrowedFormatItem] = format_description!("[hour]:[minute]:[second]");
|
||||
const HISTORY_LEN: usize = 120;
|
||||
|
||||
pub struct App {
|
||||
pub struct App<'a> {
|
||||
pub timestamp: OffsetDateTime,
|
||||
pub machines: Vec<data::MachineData>,
|
||||
pub machines: HashMap<String, data::MachineData>,
|
||||
pub history: HashMap<String, VecDeque<(f64, f64)>>,
|
||||
|
||||
config: &'a ConfigData,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
impl<'a> App<'a> {
|
||||
pub fn new(config: &'a ConfigData) -> Self {
|
||||
Self {
|
||||
timestamp: OffsetDateTime::now_local().unwrap(),
|
||||
machines: vec![
|
||||
data::MachineData {
|
||||
name: "machine 1".into(),
|
||||
voltage: 0f32,
|
||||
current: 0f32,
|
||||
last_updated: OffsetDateTime::now_utc(),
|
||||
},
|
||||
data::MachineData {
|
||||
name: "machine 2".into(),
|
||||
voltage: 0f32,
|
||||
current: 0f32,
|
||||
last_updated: OffsetDateTime::now_utc(),
|
||||
},
|
||||
],
|
||||
machines: HashMap::new(),
|
||||
history: HashMap::new(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &App {
|
||||
impl<'a> Widget for &App<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let [headline_area, machines_area, _] = Layout::vertical([
|
||||
let [headline_area, machines_area, chart_area] = Layout::vertical([
|
||||
Constraint::Length(3),
|
||||
Constraint::Length(6),
|
||||
Constraint::Min(0),
|
||||
])
|
||||
.areas(area);
|
||||
|
||||
let [machine1_area, machine2_area] =
|
||||
Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)]).areas(machines_area);
|
||||
|
||||
Headline {
|
||||
timestamp: &self.timestamp,
|
||||
}
|
||||
.render(headline_area, buf);
|
||||
|
||||
MachineData {
|
||||
data: &self.machines[0],
|
||||
}
|
||||
.render(machine1_area, buf);
|
||||
let machine_area_const = vec![Constraint::Fill(1); self.config.machines.len()];
|
||||
let machine_areas = Layout::horizontal(machine_area_const).split(machines_area);
|
||||
let machine_zip = self
|
||||
.config
|
||||
.machines
|
||||
.iter()
|
||||
.zip(machine_areas.iter().copied());
|
||||
|
||||
for (machine_config, machine_area) in machine_zip {
|
||||
let machine_data = self.machines.get(&machine_config.topic);
|
||||
|
||||
MachineData {
|
||||
data: &self.machines[1],
|
||||
name: &machine_config.name,
|
||||
data: machine_data,
|
||||
}
|
||||
.render(machine2_area, buf);
|
||||
.render(machine_area, buf);
|
||||
}
|
||||
|
||||
let datasets: Vec<Dataset<'_>> = self
|
||||
.history
|
||||
.iter()
|
||||
.map(|(name, data)| {
|
||||
let data = data.as_slices().0;
|
||||
Dataset::default()
|
||||
.name(Line::from(name.as_str()))
|
||||
.marker(symbols::Marker::Braille)
|
||||
.graph_type(GraphType::Line)
|
||||
.style(Color::Cyan)
|
||||
.data(data)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let chart = Chart::new(datasets)
|
||||
.block(Block::bordered().title("Current usage (A)"))
|
||||
.x_axis(Axis::default().bounds([0.0, HISTORY_LEN as f64]))
|
||||
.y_axis(Axis::default().bounds([0.0, 10f64]));
|
||||
|
||||
chart.render(chart_area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +127,8 @@ impl<'a> Widget for &Headline<'a> {
|
||||
}
|
||||
|
||||
pub struct MachineData<'a> {
|
||||
data: &'a data::MachineData,
|
||||
name: &'a str,
|
||||
data: Option<&'a data::MachineData>,
|
||||
}
|
||||
|
||||
impl<'a> Widget for &MachineData<'a> {
|
||||
@@ -117,6 +143,20 @@ impl<'a> Widget for &MachineData<'a> {
|
||||
let block_area = block.inner(area);
|
||||
block.render(area, buf);
|
||||
|
||||
let machine = match self.data {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// Render no data
|
||||
let area_const = [Constraint::Length(1), Constraint::Min(0)];
|
||||
let [name_area, no_data_area] = Layout::vertical(area_const).areas(block_area);
|
||||
|
||||
let text = format!("Name: {}", self.name).bold().fg(Color::Blue);
|
||||
Paragraph::new(text).render(name_area, buf);
|
||||
Paragraph::new("no data").render(no_data_area, buf);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let layout_const = [
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
@@ -127,18 +167,18 @@ impl<'a> Widget for &MachineData<'a> {
|
||||
Layout::vertical(layout_const).areas(block_area);
|
||||
|
||||
let format = format_description!("[year]-[month]-[day] [hour]:[month]:[second]");
|
||||
let last_updated = self.data.last_updated.format(format).unwrap();
|
||||
let last_updated = machine.last_updated.format(format).unwrap();
|
||||
|
||||
let text = format!("Name: {}", self.data.name).bold().fg(Color::Blue);
|
||||
let text = format!("Name: {}", self.name).bold().fg(Color::Blue);
|
||||
Paragraph::new(text).render(name_area, buf);
|
||||
let text = Line::from(vec![
|
||||
"Voltage: ".bold(),
|
||||
format!("{:.0} V", self.data.voltage).into(),
|
||||
format!("{:.0} V", machine.voltage).into(),
|
||||
]);
|
||||
Paragraph::new(text).render(voltage_area, buf);
|
||||
let text = Line::from(vec![
|
||||
"Current: ".bold(),
|
||||
format!("{:.03} A", self.data.current).into(),
|
||||
format!("{:.03} A", machine.current).into(),
|
||||
]);
|
||||
Paragraph::new(text).render(current_area, buf);
|
||||
let text = Line::from(vec!["Last updated: ".bold(), last_updated.into()]);
|
||||
@@ -146,12 +186,12 @@ impl<'a> Widget for &MachineData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(event_receiver: events::EventReceiver) -> Result<()> {
|
||||
pub async fn start(config: &ConfigData, event_receiver: events::EventReceiver) -> Result<()> {
|
||||
let mut event_receiver = event_receiver;
|
||||
let mut terminal = ratatui::init();
|
||||
|
||||
let mut running = true;
|
||||
let mut app = App::new();
|
||||
let mut app = App::new(config);
|
||||
|
||||
while running {
|
||||
// render tui
|
||||
@@ -163,12 +203,16 @@ pub async fn start(event_receiver: events::EventReceiver) -> Result<()> {
|
||||
match event_receiver.recv().await {
|
||||
Some(events::Event::Timestamp(t)) => app.timestamp = t,
|
||||
Some(events::Event::MachineUpdate(data)) => {
|
||||
for machine in &mut app.machines {
|
||||
if machine.name == data.name {
|
||||
machine.voltage = data.voltage;
|
||||
machine.current = data.current;
|
||||
machine.last_updated = data.last_updated;
|
||||
}
|
||||
let name = data.topic.clone();
|
||||
let current = data.current;
|
||||
|
||||
app.machines.insert(name.clone(), data);
|
||||
|
||||
let history = app.history.entry(name).or_default();
|
||||
let x = history.len() as f64;
|
||||
history.push_back((x, current as f64));
|
||||
if history.len() > HISTORY_LEN {
|
||||
history.pop_front();
|
||||
}
|
||||
}
|
||||
Some(events::Event::Exit) => running = false,
|
||||
|
||||
Reference in New Issue
Block a user