Compare commits

..

3 Commits

Author SHA1 Message Date
a0c13ff4f7 repove unuused 2026-04-11 23:01:58 +02:00
d1f9238b2a add services status 2026-04-11 21:11:38 +02:00
21fe914f18 add cpus and border info 2026-04-11 16:54:31 +02:00
9 changed files with 775 additions and 54 deletions

571
Cargo.lock generated
View File

@@ -179,6 +179,12 @@ dependencies = [
"bytemuck", "bytemuck",
] ]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.0" version = "1.5.0"
@@ -319,6 +325,49 @@ dependencies = [
"cipher 0.4.4", "cipher 0.4.4",
] ]
[[package]]
name = "bollard"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4"
dependencies = [
"base64",
"bollard-stubs",
"bytes",
"futures-core",
"futures-util",
"hex",
"http",
"http-body-util",
"hyper",
"hyper-named-pipe",
"hyper-util",
"hyperlocal",
"log",
"pin-project-lite",
"serde",
"serde_derive",
"serde_json",
"serde_urlencoded",
"thiserror 2.0.18",
"tokio",
"tokio-util",
"tower-service",
"url",
"winapi",
]
[[package]]
name = "bollard-stubs"
version = "1.52.1-rc.29.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0a8ca8799131c1837d1282c3f81f31e76ceb0ce426e04a7fe1ccee3287c066"
dependencies = [
"serde",
"serde_json",
"serde_repr",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.20.2" version = "3.20.2"
@@ -809,6 +858,17 @@ dependencies = [
"ctutils", "ctutils",
] ]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]] [[package]]
name = "document-features" name = "document-features"
version = "0.2.12" version = "0.2.12"
@@ -1027,6 +1087,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]] [[package]]
name = "fs_extra" name = "fs_extra"
version = "1.3.0" version = "1.3.0"
@@ -1271,6 +1340,51 @@ dependencies = [
"digest 0.11.2", "digest 0.11.2",
] ]
[[package]]
name = "http"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hybrid-array" name = "hybrid-array"
version = "0.4.10" version = "0.4.10"
@@ -1283,6 +1397,77 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "hyper"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
dependencies = [
"atomic-waker",
"bytes",
"futures-channel",
"futures-core",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"smallvec",
"tokio",
"want",
]
[[package]]
name = "hyper-named-pipe"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278"
dependencies = [
"hex",
"hyper",
"hyper-util",
"pin-project-lite",
"tokio",
"tower-service",
"winapi",
]
[[package]]
name = "hyper-util"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http",
"http-body",
"hyper",
"libc",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
]
[[package]]
name = "hyperlocal"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7"
dependencies = [
"hex",
"http-body-util",
"hyper",
"hyper-util",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.65" version = "0.1.65"
@@ -1307,6 +1492,88 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "icu_collections"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
[[package]]
name = "icu_properties"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
dependencies = [
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
[[package]]
name = "icu_provider"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]] [[package]]
name = "id-arena" name = "id-arena"
version = "2.3.0" version = "2.3.0"
@@ -1319,6 +1586,27 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.14.0" version = "2.14.0"
@@ -1560,6 +1848,12 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
[[package]] [[package]]
name = "litrs" name = "litrs"
version = "1.0.0" version = "1.0.0"
@@ -1972,6 +2266,12 @@ dependencies = [
"base64ct", "base64ct",
] ]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.8.6" version = "2.8.6"
@@ -2161,6 +2461,15 @@ dependencies = [
"portable-atomic", "portable-atomic",
] ]
[[package]]
name = "potential_utf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
dependencies = [
"zerovec",
]
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
@@ -2674,6 +2983,38 @@ dependencies = [
"zmij", "zmij",
] ]
[[package]]
name = "serde_repr"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[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 = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "serdect" name = "serdect"
version = "0.4.2" version = "0.4.2"
@@ -2869,17 +3210,27 @@ name = "ssh-status"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bollard",
"crossterm", "crossterm",
"env_logger", "env_logger",
"futures",
"log", "log",
"rand 0.10.0", "rand 0.10.0",
"ratatui", "ratatui",
"russh", "russh",
"serde",
"sysinfo", "sysinfo",
"termios", "termios",
"tokio", "tokio",
"toml",
] ]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@@ -2941,6 +3292,17 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "synstructure"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.38.4" version = "0.38.4"
@@ -3079,6 +3441,16 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "tinystr"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.51.1" version = "1.51.1"
@@ -3105,6 +3477,89 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "tokio-util"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "toml"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
dependencies = [
"indexmap",
"serde_core",
"serde_spanned",
"toml_datetime",
"toml_parser",
"toml_writer",
"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.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.19.0"
@@ -3178,6 +3633,24 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@@ -3211,6 +3684,15 @@ dependencies = [
"utf8parse", "utf8parse",
] ]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.1+wasi-snapshot-preview1" version = "0.11.1+wasi-snapshot-preview1"
@@ -3537,6 +4019,12 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "winnow"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.51.0" version = "0.51.0"
@@ -3625,6 +4113,35 @@ dependencies = [
"wasmparser", "wasmparser",
] ]
[[package]]
name = "writeable"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
[[package]]
name = "yoke"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"synstructure",
]
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.48" version = "0.8.48"
@@ -3645,12 +4162,66 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "zerofrom"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"synstructure",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.8.2" version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]]
name = "zerotrie"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]] [[package]]
name = "zmij" name = "zmij"
version = "1.0.21" version = "1.0.21"

View File

@@ -5,12 +5,16 @@ edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.102" anyhow = "1.0.102"
bollard = "0.20.2"
crossterm = "0.29.0" crossterm = "0.29.0"
env_logger = "0.11.10" env_logger = "0.11.10"
futures = "0.3.32"
log = "0.4.29" log = "0.4.29"
rand = "0.10.0" rand = "0.10.0"
ratatui = "0.30.0" ratatui = "0.30.0"
russh = "0.60.0" russh = "0.60.0"
serde = {version= "1.0.228",features = ["derive"]}
sysinfo = "0.38.4" sysinfo = "0.38.4"
termios = "0.3.3" termios = "0.3.3"
tokio = "1.51.1" tokio = "1.51.1"
toml = "1.1.2"

View File

@@ -1,60 +1,120 @@
use ratatui::layout::Rect; use ratatui::layout::Rect;
use ratatui::prelude::*; use ratatui::prelude::*;
use ratatui::style::{Color, Style}; use ratatui::style::Style;
use ratatui::widgets::{Block, Borders, Gauge}; use ratatui::widgets::{Block, Borders, Gauge, Paragraph};
use sysinfo::{Components, Disk, Disks, Networks, System}; use sysinfo::{Disks, System};
use crate::config::{Config, load};
use crate::docker;
use std::path::Path;
pub struct App { pub struct App {
sys: System, sys: System,
config: Config,
services: Vec<bool>,
} }
impl Default for App { impl Default for App {
fn default() -> Self { fn default() -> Self {
App { App {
sys: System::new_all(), sys: System::new_all(),
config: load("server.toml").unwrap(),
services: Default::default(),
} }
} }
} }
impl App { impl App {
pub fn update_info(&mut self) { pub async fn update_info(&mut self) {
self.sys.refresh_all(); self.sys.refresh_all();
self.services = docker::running_services(&self.config.services.clone())
.await
.unwrap();
} }
pub fn draw(&self, frame: &mut Frame) { pub fn draw(&self, frame: &mut Frame) {
let block = Block::default()
.title_top(Line::from("Server status").centered().bold())
.title_bottom(Line::from("press 'q' to exit").right_aligned().italic());
frame.render_widget(block, frame.area());
let layout = Layout::default() let layout = Layout::default()
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.margin(1)
.constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)]) .constraints(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
.split(frame.area()); .split(frame.area());
let style = Style::default().fg(Color::Red);
let block = Block::default().title("Services").borders(Borders::ALL); let block = Block::default().title("Services").borders(Borders::ALL);
self.draw_services(frame, layout[0]);
frame.render_widget(block, layout[0]); frame.render_widget(block, layout[0]);
let disks_gauges = self.disks(); let disks_gauges = self.disks();
let memory_gauges = self.memory();
let cpus_gauges = self.cpus();
let layout_system = Layout::vertical([ let layout_system = Layout::vertical([
Constraint::Length(6), Constraint::Length((memory_gauges.len() * 2 + 2) as u16),
Constraint::Length((disks_gauges.len() * 2 + 2) as u16), Constraint::Length((disks_gauges.len() * 2 + 2) as u16),
Constraint::Length((cpus_gauges.len() + 2) as u16),
]) ])
.split(layout[1]); .split(layout[1]);
self.draw_memory(frame, layout_system[0]); self.draw_gauges(frame, layout_system[0], memory_gauges, "Memory");
self.draw_disks(frame, layout_system[1], disks_gauges); self.draw_gauges(frame, layout_system[1], disks_gauges, "Disks");
self.draw_gauges(frame, layout_system[2], cpus_gauges, "CPU");
} }
fn disks(&self) -> Vec<Gauge> { fn memory(&self) -> Vec<Gauge<'_>> {
let mut gauges: Vec<Gauge<'_>> = Default::default();
let mem_total: f64 = ((self.sys.total_memory() >> 20) as f64) / 1024.0;
let mem_used: f64 = ((self.sys.used_memory() >> 20) as f64) / 1024.0;
let mem = Gauge::default()
.block(Block::default().title("RAM usage:"))
.gauge_style(Style::new().white().on_black().italic())
.label(format!("{mem_used:.2}/{mem_total:.2}Go"))
.ratio(mem_used / mem_total);
gauges.push(mem);
let swap_total: f64 = ((self.sys.total_swap() >> 20) as f64) / 1024.0;
let swap_used: f64 = ((self.sys.used_swap() >> 20) as f64) / 1024.0;
if swap_total <= 0.0 {
return gauges;
}
let swap = Gauge::default()
.block(Block::default().title("SWAP usage:"))
.gauge_style(Style::new().white().on_black().italic())
.label(format!("{swap_used:.2}/{swap_total:.2}Go"))
.ratio(swap_used / swap_total);
gauges.push(swap);
gauges
}
fn disks(&self) -> Vec<Gauge<'_>> {
let mut gauges: Vec<Gauge> = Default::default(); let mut gauges: Vec<Gauge> = Default::default();
for disk in &Disks::new_with_refreshed_list() { for disk in &Disks::new_with_refreshed_list() {
if disk.mount_point().starts_with("/boot/") || disk.mount_point().starts_with("/tmp/") { let total = ((disk.total_space() >> 20) as f64) / 1024.0;
let used = total - ((disk.available_space() >> 20) as f64) / 1024.0;
if self.config.disks.iter().all(|config_disk| {
disk.mount_point() != AsRef::<Path>::as_ref(config_disk.mount_point.as_str())
}) || total <= 0.0
{
continue; continue;
} }
let total = ((disk.total_space() >> 20) as f64) / 1024.0;
let used = total - ((disk.available_space() >> 20) as f64) / 1024.0;
let gauge = Gauge::default() let gauge = Gauge::default()
.block(Block::default().title(format!( .block(Block::default().title(format!(
"{:?} ({:?})", "{:?} ({:?})",
@@ -71,8 +131,46 @@ impl App {
gauges gauges
} }
fn draw_disks(&self, frame: &mut Frame, area: Rect, gauges: Vec<Gauge>) { fn cpus(&self) -> Vec<Gauge<'_>> {
let block = Block::default().title("Disks").borders(Borders::ALL); let mut gauges: Vec<Gauge> = Default::default();
for cpu in self.sys.cpus() {
let usage = cpu.cpu_usage() as f64;
let gauge = Gauge::default()
.gauge_style(Style::new().white().on_black().italic())
.label(format!("{usage:>4.1} %"))
.ratio(usage / 100.0);
gauges.push(gauge);
}
gauges
}
fn draw_services(&self, frame: &mut Frame, area: Rect) {
let layout = Layout::vertical(vec![Constraint::Length(2); self.config.services.len()])
.margin(1)
.split(area);
for (idx, (service, status)) in self
.config
.services
.iter()
.zip(self.services.iter())
.enumerate()
{
let display = Paragraph::new(service.description.clone()).block(
Block::default()
.title_top(Line::from(service.name.clone()).bold())
.title_top(Line::from(format!("(running: {status})")).right_aligned()),
);
frame.render_widget(display, layout[idx]);
}
}
fn draw_gauges(&self, frame: &mut Frame, area: Rect, gauges: Vec<Gauge>, name: &str) {
let block = Block::default().title(name).borders(Borders::ALL);
frame.render_widget(block, area); frame.render_widget(block, area);
@@ -84,36 +182,4 @@ impl App {
frame.render_widget(gauge, layout[idx]); frame.render_widget(gauge, layout[idx]);
} }
} }
fn draw_memory(&self, frame: &mut Frame, area: Rect) {
let block = Block::default().title("Memory").borders(Borders::ALL);
frame.render_widget(block, area);
let layout = Layout::vertical([Constraint::Length(2), Constraint::Length(2)])
.margin(1)
.split(area);
let mem_total: f64 = ((self.sys.total_memory() >> 20) as f64) / 1024.0;
let mem_used: f64 = ((self.sys.used_memory() >> 20) as f64) / 1024.0;
let mem_gauge = Gauge::default()
.block(Block::default().title("RAM usage:"))
.gauge_style(Style::new().white().on_black().italic())
.label(format!("{mem_used:.2}/{mem_total:.2}Go"))
.ratio(mem_used / mem_total);
frame.render_widget(mem_gauge, layout[0]);
let swap_total: f64 = ((self.sys.total_swap() >> 20) as f64) / 1024.0;
let swap_used: f64 = ((self.sys.used_swap() >> 20) as f64) / 1024.0;
let swap_gauge = Gauge::default()
.block(Block::default().title("SWAP usage:"))
.gauge_style(Style::new().white().on_black().italic())
.label(format!("{swap_used:.2}/{swap_total:.2}Go"))
.ratio(swap_used / swap_total);
frame.render_widget(swap_gauge, layout[1]);
}
} }

View File

@@ -1,5 +1,6 @@
//extern crate termios; //extern crate termios;
use ssh_status::runner::{Action, Runner}; use ssh_status::runner::{Action, Runner};
use std::io::{self, Write}; use std::io::{self, Write};
use std::time::Duration; use std::time::Duration;
@@ -7,7 +8,8 @@ use crossterm::cursor;
use crossterm::event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode}; use crossterm::event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode};
use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen}; use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen};
fn main() { #[tokio::main]
async fn main() {
let mut stdout = io::stdout(); let mut stdout = io::stdout();
crossterm::terminal::enable_raw_mode().unwrap(); crossterm::terminal::enable_raw_mode().unwrap();
crossterm::execute!( crossterm::execute!(
@@ -21,10 +23,10 @@ fn main() {
let mut app = Runner::new(stdout).unwrap(); let mut app = Runner::new(stdout).unwrap();
let (w, h) = crossterm::terminal::size().unwrap(); let (w, h) = crossterm::terminal::size().unwrap();
app.resize(w as u32, h as u32).unwrap(); app.resize(w as u32, h as u32).unwrap();
app.update(); app.update().await;
loop { loop {
if crossterm::event::poll(Duration::from_millis(100)).unwrap() { if crossterm::event::poll(Duration::from_millis(1000)).unwrap() {
match crossterm::event::read().unwrap() { match crossterm::event::read().unwrap() {
Event::Key(key) => match key.code { Event::Key(key) => match key.code {
KeyCode::Char(c) => { KeyCode::Char(c) => {
@@ -41,7 +43,7 @@ fn main() {
} }
}; };
app.update(); app.update().await;
} }
let mut stdout = io::stdout(); let mut stdout = io::stdout();

30
src/config.rs Normal file
View File

@@ -0,0 +1,30 @@
use std::path::Path;
use std::{fs, io};
use serde::Deserialize;
use toml;
#[derive(Deserialize, Debug, Clone)]
pub struct Config {
pub name: String,
pub disks: Vec<Disk>,
pub services: Vec<Service>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct Service {
pub name: String,
pub description: String,
pub containers: Vec<String>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct Disk {
pub name: String,
pub mount_point: String,
}
pub fn load<P: AsRef<Path>>(path: P) -> io::Result<Config> {
let config_str = fs::read_to_string(path)?;
Ok(toml::from_str(&config_str).unwrap())
}

46
src/docker.rs Normal file
View File

@@ -0,0 +1,46 @@
use bollard::{Docker, errors::Error};
use crate::config::Service;
use std::collections::HashMap;
use std::default::Default;
pub async fn running_containers() -> Result<Vec<String>, Error> {
let mut names: Vec<String> = Default::default();
let docker = Docker::connect_with_socket_defaults()?;
let mut list_container_filters = HashMap::new();
list_container_filters.insert(String::from("status"), vec![String::from("running")]);
let containers = &docker
.list_containers(Some(
bollard::query_parameters::ListContainersOptionsBuilder::default()
.all(true)
.filters(&list_container_filters)
.build(),
))
.await?;
for c in containers {
if let Some(c_names) = &c.names {
for name in c_names {
names.push(name.clone());
}
}
}
Ok(names)
}
pub async fn running_services(services: &Vec<Service>) -> Result<Vec<bool>, Error> {
let running = running_containers().await?;
let mut status: Vec<bool> = Default::default();
for service in services.iter() {
let service_status: bool = service.containers.iter().all(|name| running.contains(name));
status.push(service_status);
}
Ok(status)
}

View File

@@ -1,3 +1,5 @@
pub mod app; pub mod app;
pub mod config;
pub mod docker;
pub mod runner; pub mod runner;
pub mod server; pub mod server;

View File

@@ -39,8 +39,8 @@ impl<W: std::io::Write> Runner<W> {
} }
} }
pub fn update(&mut self) { pub async fn update(&mut self) {
self.app.update_info(); self.app.update_info().await;
self.terminal.draw(|frame| self.app.draw(frame)).unwrap(); self.terminal.draw(|frame| self.app.draw(frame)).unwrap();
} }

View File

@@ -27,10 +27,10 @@ impl AppServer {
let clients = self.clients.clone(); let clients = self.clients.clone();
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
for (_, app) in clients.lock().await.iter_mut() { for (_, app) in clients.lock().await.iter_mut() {
app.update(); app.update().await;
} }
} }
}); });