mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 19:06:34 +00:00
fix(kiosk): complete hot/warm/cooling/cold state machine
Add recompute_pool_states + expire_cooling_pipelines + recompute_global_state and PipelineEntry struct so warm pool entries carry warmth state + cooling deadline. Drop the incomplete tuple-shape from the previous push.
This commit is contained in:
parent
887db013ef
commit
bfb5028001
2 changed files with 491 additions and 75 deletions
349
kiosk/Cargo.lock
generated
349
kiosk/Cargo.lock
generated
|
|
@ -67,6 +67,8 @@ name = "betterframe-kiosk"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"futures-util",
|
||||
"gpiod",
|
||||
"gst-plugin-gtk4",
|
||||
"gstreamer",
|
||||
"gstreamer-video",
|
||||
|
|
@ -76,22 +78,46 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"webkit6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.1"
|
||||
|
|
@ -104,7 +130,7 @@ version = "0.20.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e3bd0f4e25afa9cabc157908d14eeef9067d6448c49414d17b3fb55f0eadd0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"libc",
|
||||
|
|
@ -193,12 +219,47 @@ version = "0.8.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
|
|
@ -495,6 +556,16 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
|
|
@ -555,7 +626,7 @@ version = "0.20.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
|
|
@ -604,6 +675,24 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpiod"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f851b1c607b36b4a493448ef80d8693bf74145712074c667a008a58264f8da49"
|
||||
dependencies = [
|
||||
"gpiod-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpiod-core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15a60e3beb5444643d049a3f8769b47ce246ec1f57e6cd1aed1e417d57a47110"
|
||||
dependencies = [
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "graphene-rs"
|
||||
version = "0.20.10"
|
||||
|
|
@ -708,7 +797,7 @@ dependencies = [
|
|||
"paste",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -794,7 +883,7 @@ dependencies = [
|
|||
"gstreamer-video-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1196,6 +1285,29 @@ version = "1.0.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "javascriptcore6"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b28ed9c7c08f906b2a51bc2365eae2ba5e7db1249b89892f7ae4cbd602d1f4"
|
||||
dependencies = [
|
||||
"glib",
|
||||
"javascriptcore6-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "javascriptcore6-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4741e2a31c2145050dd4971f8dd51e92c840d5839a7124cc68a33c7325523a12"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.98"
|
||||
|
|
@ -1317,6 +1429,17 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
|
|
@ -1366,7 +1489,7 @@ version = "0.10.79"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
|
@ -1481,6 +1604,15 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
|
|
@ -1524,6 +1656,36 @@ version = "6.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
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.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
|
|
@ -1532,7 +1694,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
|||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1623,7 +1785,7 @@ version = "1.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
|
@ -1690,7 +1852,7 @@ version = "3.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
|
|
@ -1777,6 +1939,17 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
@ -1814,6 +1987,32 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soup3"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84ccd1f4aee0854a16b0b489ba843798e2eb4cdcddd4a61248f7db9ce8b6df1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"gio",
|
||||
"glib",
|
||||
"libc",
|
||||
"soup3-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soup3-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8869997193d52a61a1db48627bdaa57343f76e2c5132ee6d351245a6ab30631e"
|
||||
dependencies = [
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
|
|
@ -1863,7 +2062,7 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
|
@ -1910,13 +2109,33 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1995,6 +2214,20 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.18"
|
||||
|
|
@ -2101,7 +2334,7 @@ version = "0.6.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
|
|
@ -2192,6 +2425,31 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand",
|
||||
"sha1",
|
||||
"thiserror 1.0.69",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
|
|
@ -2222,6 +2480,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
|
|
@ -2246,6 +2510,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
|
|
@ -2362,7 +2632,7 @@ version = "0.244.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
|
|
@ -2378,6 +2648,39 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit6"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c359ef247305dcade3363c281c505b943e0e6162a42eac76ff76ed8e7cebfbd"
|
||||
dependencies = [
|
||||
"gdk4",
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk4",
|
||||
"javascriptcore6",
|
||||
"libc",
|
||||
"soup3",
|
||||
"webkit6-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit6-sys"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96284c5280af5984dbdae8dae3cfeea11b44b214f9bd42b35c0ca75903bccce2"
|
||||
dependencies = [
|
||||
"gdk4-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk4-sys",
|
||||
"javascriptcore6-sys",
|
||||
"libc",
|
||||
"soup3-sys",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
|
|
@ -2695,7 +2998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"bitflags 2.11.1",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
|
|
@ -2754,6 +3057,26 @@ dependencies = [
|
|||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.7"
|
||||
|
|
|
|||
217
kiosk/src/ui.rs
217
kiosk/src/ui.rs
|
|
@ -265,6 +265,9 @@ fn install_idle_watchdog() {
|
|||
if WATCHDOG_INSTALLED.with(|c| c.get()) { return; }
|
||||
WATCHDOG_INSTALLED.with(|c| c.set(true));
|
||||
gtk::glib::timeout_add_local(Duration::from_secs(1), move || {
|
||||
// Drop any pipelines whose cooling window has elapsed.
|
||||
expire_cooling_pipelines();
|
||||
|
||||
let bundle = CURRENT_BUNDLE.with(|b| b.borrow().clone());
|
||||
let Some(bundle) = bundle else { return gtk::glib::ControlFlow::Continue };
|
||||
|
||||
|
|
@ -412,41 +415,10 @@ fn render_bundle(
|
|||
}
|
||||
}
|
||||
|
||||
// Compute warm vs hot camera sets per the CLAUDE.md model.
|
||||
// Warm = cameras in the currently-active layout (cells + preload) of any display.
|
||||
// Hot = cameras referenced by ANY layout with priority=hot (kept warm always).
|
||||
// Anything previously cached but in neither set transitions to Cooling.
|
||||
let mut warm_set: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
let mut hot_set: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
let mut max_cooling_secs: u32 = 0;
|
||||
for (i, bd) in displays.iter().enumerate() {
|
||||
let target_id = pick_initial_layout(bd);
|
||||
if let Some(target_id) = target_id {
|
||||
if let Some(layout) = bd.layouts.iter().find(|l| l.id == target_id) {
|
||||
for cell in &layout.cells {
|
||||
if cell.content_type == "camera" {
|
||||
if let Some(id) = cell.camera_id { warm_set.insert(id); }
|
||||
}
|
||||
}
|
||||
for id in &layout.preload_camera_ids { warm_set.insert(*id); }
|
||||
if let Some(t) = layout.cooling_timeout_seconds { max_cooling_secs = max_cooling_secs.max(t); }
|
||||
}
|
||||
}
|
||||
// Hot layouts keep their cameras warm even when not active.
|
||||
for layout in &bd.layouts {
|
||||
if layout.priority == "hot" {
|
||||
for cell in &layout.cells {
|
||||
if cell.content_type == "camera" {
|
||||
if let Some(id) = cell.camera_id { hot_set.insert(id); }
|
||||
}
|
||||
}
|
||||
for id in &layout.preload_camera_ids { hot_set.insert(*id); }
|
||||
}
|
||||
}
|
||||
let _ = gdk_monitors.get(i);
|
||||
}
|
||||
|
||||
recompute_pool_states(&warm_set, &hot_set, max_cooling_secs);
|
||||
// Note: hot/warm/cooling pool recompute is deferred to the per-display
|
||||
// render_layout() calls below — each one calls recompute_global_state()
|
||||
// after installing its current_layout_id, so the union across all
|
||||
// displays is correct once the loop finishes.
|
||||
|
||||
// Build/reuse window per bundle display, then render its initial layout.
|
||||
let mut new_state: HashMap<u32, DisplayState> = HashMap::new();
|
||||
|
|
@ -578,7 +550,7 @@ fn render_layout(display_id: u32, layout_id: u32) {
|
|||
|
||||
if layout.cells.is_empty() {
|
||||
warn!("layout has no cells");
|
||||
recompute_warm_cameras(&bundle);
|
||||
recompute_global_state();
|
||||
DISPLAYS.with(|ds| {
|
||||
if let Some(st) = ds.borrow_mut().get_mut(&display_id) {
|
||||
show_logo(&st.window);
|
||||
|
|
@ -587,9 +559,10 @@ fn render_layout(display_id: u32, layout_id: u32) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Recompute warm-camera set across ALL displays (the union), then drop
|
||||
// pipelines no longer needed anywhere.
|
||||
recompute_warm_cameras(&bundle);
|
||||
// Recompute hot/warm/cooling pool state across ALL displays' current
|
||||
// layouts. Pipelines no longer needed transition to Cooling and are
|
||||
// dropped by the watchdog tick after cooling_timeout_seconds.
|
||||
recompute_global_state();
|
||||
|
||||
let server_url = server_url.as_str();
|
||||
let kiosk_key = kiosk_key.as_str();
|
||||
|
|
@ -695,34 +668,138 @@ fn render_layout(display_id: u32, layout_id: u32) {
|
|||
});
|
||||
}
|
||||
|
||||
/// Compute the union of cameras needed across all displays' current layouts +
|
||||
/// preload sets, then drop any warm pipelines outside that set.
|
||||
fn recompute_warm_cameras(bundle: &KioskBundle) {
|
||||
let mut needed: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
/// Default cooling timeout when a layout doesn't specify one (or specifies 0).
|
||||
const DEFAULT_COOLING_SECS: u32 = 30;
|
||||
|
||||
/// Walk all displays' currently-active layouts (plus any priority=hot layouts)
|
||||
/// and recompute the warm/hot pool. Cameras dropped from active layouts
|
||||
/// transition to Cooling; new entries are NOT added here — `ensure_warm` does
|
||||
/// that when the layout actually renders.
|
||||
fn recompute_global_state() {
|
||||
let bundle = CURRENT_BUNDLE.with(|b| b.borrow().clone());
|
||||
let Some(bundle) = bundle else { return };
|
||||
let displays = bundle.normalized_displays();
|
||||
DISPLAYS.with(|ds| {
|
||||
for (display_id, st) in ds.borrow().iter() {
|
||||
let Some(bd) = displays.iter().find(|d| d.id == *display_id) else { continue };
|
||||
let Some(cur_id) = st.current_layout_id else { continue };
|
||||
let Some(layout) = bd.layouts.iter().find(|l| l.id == cur_id) else { continue };
|
||||
for cell in &layout.cells {
|
||||
if cell.content_type == "camera" {
|
||||
if let Some(id) = cell.camera_id { needed.insert(id); }
|
||||
}
|
||||
}
|
||||
for id in &layout.preload_camera_ids { needed.insert(*id); }
|
||||
}
|
||||
|
||||
let mut warm_set: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
let mut hot_set: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
let mut max_cooling_secs: u32 = 0;
|
||||
|
||||
// Snapshot per-display active layout id outside any borrow of WARM_CAMERAS.
|
||||
let active: Vec<(u32, Option<u32>)> = DISPLAYS.with(|ds| {
|
||||
ds.borrow().iter().map(|(id, st)| (*id, st.current_layout_id)).collect()
|
||||
});
|
||||
|
||||
for bd in &displays {
|
||||
// Find this display's active layout (if any) and harvest its cameras.
|
||||
let active_id = active.iter().find(|(id, _)| *id == bd.id).and_then(|(_, l)| *l);
|
||||
if let Some(cur_id) = active_id {
|
||||
if let Some(layout) = bd.layouts.iter().find(|l| l.id == cur_id) {
|
||||
for cell in &layout.cells {
|
||||
if cell.content_type == "camera" {
|
||||
if let Some(id) = cell.camera_id { warm_set.insert(id); }
|
||||
}
|
||||
}
|
||||
for id in &layout.preload_camera_ids { warm_set.insert(*id); }
|
||||
let t = layout.cooling_timeout_seconds.unwrap_or(0);
|
||||
let t = if t == 0 { DEFAULT_COOLING_SECS } else { t };
|
||||
max_cooling_secs = max_cooling_secs.max(t);
|
||||
}
|
||||
}
|
||||
// Hot layouts keep their cameras warm even when not active.
|
||||
for layout in &bd.layouts {
|
||||
if layout.priority == "hot" {
|
||||
for cell in &layout.cells {
|
||||
if cell.content_type == "camera" {
|
||||
if let Some(id) = cell.camera_id { hot_set.insert(id); }
|
||||
}
|
||||
}
|
||||
for id in &layout.preload_camera_ids { hot_set.insert(*id); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if max_cooling_secs == 0 { max_cooling_secs = DEFAULT_COOLING_SECS; }
|
||||
recompute_pool_states(&warm_set, &hot_set, max_cooling_secs);
|
||||
}
|
||||
|
||||
/// Apply the hot/warm/cooling/cold state machine to the existing WARM_CAMERAS
|
||||
/// pool. Does NOT create new entries — `ensure_warm` handles that.
|
||||
///
|
||||
/// - cam in hot_set → Hot (clear cooling)
|
||||
/// - cam in warm_set → Warm (clear cooling)
|
||||
/// - cam in neither & was Cooling → keep cooling_until unchanged
|
||||
/// - cam in neither & not yet cooling → transition to Cooling
|
||||
/// - if max_cooling_secs == 0, remove immediately (Cold)
|
||||
fn recompute_pool_states(
|
||||
warm_set: &std::collections::HashSet<u32>,
|
||||
hot_set: &std::collections::HashSet<u32>,
|
||||
max_cooling_secs: u32,
|
||||
) {
|
||||
let mut to_remove: Vec<u32> = Vec::new();
|
||||
let mut to_stop: Vec<gstreamer::Pipeline> = Vec::new();
|
||||
|
||||
WARM_CAMERAS.with(|w| {
|
||||
let mut warm = w.borrow_mut();
|
||||
let stale: Vec<u32> = warm.keys().filter(|id| !needed.contains(id)).copied().collect();
|
||||
for id in stale {
|
||||
if let Some((pipe, _, _)) = warm.remove(&id) {
|
||||
info!("stopping pipeline for camera {id} (no longer needed)");
|
||||
pipeline::stop(&pipe);
|
||||
for (cam_id, entry) in warm.iter_mut() {
|
||||
if hot_set.contains(cam_id) {
|
||||
entry.state = WarmthState::Hot;
|
||||
entry.cooling_until = None;
|
||||
} else if warm_set.contains(cam_id) {
|
||||
entry.state = WarmthState::Warm;
|
||||
entry.cooling_until = None;
|
||||
} else {
|
||||
// Was hot/warm, no longer needed.
|
||||
if entry.state == WarmthState::Cooling {
|
||||
// Already cooling — leave cooling_until alone.
|
||||
continue;
|
||||
}
|
||||
if max_cooling_secs == 0 {
|
||||
to_remove.push(*cam_id);
|
||||
to_stop.push(entry.pipeline.clone());
|
||||
} else {
|
||||
entry.state = WarmthState::Cooling;
|
||||
entry.cooling_until = Some(
|
||||
Instant::now() + Duration::from_secs(max_cooling_secs as u64),
|
||||
);
|
||||
info!(
|
||||
"camera {cam_id}: cooling for {max_cooling_secs}s before drop"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
for id in &to_remove { warm.remove(id); }
|
||||
});
|
||||
|
||||
for pipe in to_stop {
|
||||
pipeline::stop(&pipe);
|
||||
}
|
||||
}
|
||||
|
||||
/// Drop any Cooling entries whose timer has expired. Called from the
|
||||
/// 1s watchdog tick.
|
||||
fn expire_cooling_pipelines() {
|
||||
let now = Instant::now();
|
||||
let mut expired: Vec<(u32, gstreamer::Pipeline)> = Vec::new();
|
||||
WARM_CAMERAS.with(|w| {
|
||||
let mut warm = w.borrow_mut();
|
||||
let ids: Vec<u32> = warm
|
||||
.iter()
|
||||
.filter(|(_, e)| {
|
||||
e.state == WarmthState::Cooling
|
||||
&& e.cooling_until.is_some_and(|t| now >= t)
|
||||
})
|
||||
.map(|(id, _)| *id)
|
||||
.collect();
|
||||
for id in ids {
|
||||
if let Some(e) = warm.remove(&id) {
|
||||
expired.push((id, e.pipeline));
|
||||
}
|
||||
}
|
||||
});
|
||||
for (id, pipe) in expired {
|
||||
info!("camera {id}: cooling expired → stopping pipeline");
|
||||
pipeline::stop(&pipe);
|
||||
}
|
||||
}
|
||||
|
||||
fn load_webview_url(webview: &webkit6::WebView, url: &str, server_url: &str, kiosk_key: &str) {
|
||||
|
|
@ -764,10 +841,20 @@ fn ensure_warm(
|
|||
let (uri, desired_badge) = cam.pick_stream(selector, area_fraction)?;
|
||||
|
||||
let cached = WARM_CAMERAS.with(|w| {
|
||||
w.borrow().get(&cam_id).map(|(p, paint, b)| (p.clone(), paint.clone(), *b))
|
||||
w.borrow().get(&cam_id).map(|e| (e.pipeline.clone(), e.paintable.clone(), e.badge))
|
||||
});
|
||||
if let Some((pipe, paintable, badge)) = cached {
|
||||
if badge == desired_badge {
|
||||
// Promote out of Cooling if we're rendering it again.
|
||||
WARM_CAMERAS.with(|w| {
|
||||
if let Some(e) = w.borrow_mut().get_mut(&cam_id) {
|
||||
if e.state == WarmthState::Cooling {
|
||||
info!("camera {cam_id}: rescued from cooling → warm");
|
||||
e.state = WarmthState::Warm;
|
||||
e.cooling_until = None;
|
||||
}
|
||||
}
|
||||
});
|
||||
return Some((paintable, badge));
|
||||
}
|
||||
info!("camera {cam_id}: stream change {badge} → {desired_badge}, swapping");
|
||||
|
|
@ -779,7 +866,13 @@ fn ensure_warm(
|
|||
let paintable = sink.property::<gtk::gdk::Paintable>("paintable");
|
||||
pipeline::play(&pipe);
|
||||
WARM_CAMERAS.with(|w| {
|
||||
w.borrow_mut().insert(cam_id, (pipe, paintable.clone(), desired_badge));
|
||||
w.borrow_mut().insert(cam_id, PipelineEntry {
|
||||
pipeline: pipe,
|
||||
paintable: paintable.clone(),
|
||||
badge: desired_badge,
|
||||
state: WarmthState::Warm,
|
||||
cooling_until: None,
|
||||
});
|
||||
});
|
||||
info!("warmed pipeline for camera {cam_id} (stream: {desired_badge})");
|
||||
Some((paintable, desired_badge))
|
||||
|
|
|
|||
Loading…
Reference in a new issue