From 11b3e8a0164c8b304efbeda5245f4ab6ec48d298 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Wed, 13 Nov 2024 11:54:40 -0500 Subject: [PATCH] New improved realms daemon implementation --- Cargo.lock | 677 ++++++++++++++++++-------- data/com.subgraph.realms.Manager.conf | 2 + libcitadel/src/realm/events.rs | 4 + libcitadel/src/realm/manager.rs | 15 +- libcitadel/src/realm/realm.rs | 14 + realm-config-ui/Cargo.toml | 4 +- realm-config-ui/src/realmsd.rs | 14 +- realmsd/Cargo.toml | 7 +- realmsd/src/events.rs | 38 +- realmsd/src/main.rs | 57 ++- realmsd/src/next/config.rs | 201 ++++++++ realmsd/src/next/manager.rs | 103 ++++ realmsd/src/next/mod.rs | 8 + realmsd/src/next/realm.rs | 374 ++++++++++++++ realmsd/src/next/realmfs.rs | 120 +++++ realmsd/src/realms_manager.rs | 121 +++-- 16 files changed, 1446 insertions(+), 313 deletions(-) create mode 100644 realmsd/src/next/config.rs create mode 100644 realmsd/src/next/manager.rs create mode 100644 realmsd/src/next/mod.rs create mode 100644 realmsd/src/next/realm.rs create mode 100644 realmsd/src/next/realmfs.rs diff --git a/Cargo.lock b/Cargo.lock index 1ae5668..7504105 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,15 +26,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - [[package]] name = "anstream" version = "0.6.15" @@ -98,73 +89,147 @@ checksum = "06e97b4e522f9e55523001238ac59d13a8603af57f69980de5d8de4bbbe8ada6" [[package]] name = "async-broadcast" -version = "0.3.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "easy-parallel", "event-listener", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-channel" -version = "1.6.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.4.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand", + "fastrand 2.1.1", "futures-lite", - "once_cell", "slab", ] +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + [[package]] name = "async-io" -version = "1.6.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ + "async-lock", + "cfg-if 1.0.0", "concurrent-queue", + "futures-io", "futures-lite", - "libc", - "log", - "once_cell", "parking", "polling", + "rustix", "slab", - "socket2", - "waker-fn", - "winapi", + "tracing", + "windows-sys 0.59.0", ] [[package]] name = "async-lock" -version = "2.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a07789659a4d385b79b18b9127fc27e1a59e1e89117c78c5ea3b806f016374" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.77", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if 1.0.0", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", ] [[package]] name = "async-task" -version = "4.2.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.77", +] [[package]] name = "atk" @@ -173,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.2.1", "glib 0.14.8", "libc", ] @@ -190,6 +255,12 @@ dependencies = [ "system-deps 3.2.0", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -226,6 +297,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "block-buffer" version = "0.9.0" @@ -235,6 +312,28 @@ dependencies = [ "generic-array", ] +[[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 = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "blowfish" version = "0.7.0" @@ -252,19 +351,13 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - [[package]] name = "cairo-rs" version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b5725979db0c586d98abad2193cdb612dd40ef95cd26bd99851bf93b3cb482" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cairo-sys-rs", "glib 0.14.8", "libc", @@ -309,6 +402,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.19" @@ -426,11 +525,11 @@ checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "cache-padded", + "crossbeam-utils 0.8.20", ] [[package]] @@ -457,7 +556,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" dependencies = [ - "crossbeam-utils", + "crossbeam-utils 0.6.6", ] [[package]] @@ -470,6 +569,22 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.10.1" @@ -523,17 +638,6 @@ dependencies = [ "libdbus-sys", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.95", -] - [[package]] name = "digest" version = "0.9.0" @@ -543,18 +647,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + [[package]] name = "dtoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" -[[package]] -name = "easy-parallel" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" - [[package]] name = "ed25519" version = "1.5.2" @@ -570,6 +678,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enum-map" version = "0.5.0" @@ -602,9 +716,9 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.6.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", "serde", @@ -612,13 +726,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.6.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.95", + "syn 2.0.77", ] [[package]] @@ -649,10 +763,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "event-listener" -version = "2.5.2" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] [[package]] name = "failure" @@ -685,13 +824,19 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "field-offset" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" dependencies = [ - "memoffset", + "memoffset 0.6.5", "rustc_version", ] @@ -716,9 +861,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" @@ -733,58 +878,58 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" -version = "1.12.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand", + "fastrand 2.1.1", "futures-core", "futures-io", - "memchr", "parking", "pin-project-lite", - "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.95", + "syn 2.0.77", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-io", "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -796,7 +941,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d749dcfc00d8de0d7c3a289e04a04293eb5ba3d8a4e64d64911d481fa9933b" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -881,7 +1026,7 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711c3632b3ebd095578a9c091418d10fed492da9443f58ebc8f45efbeb215cb0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "futures-channel", "futures-core", "futures-io", @@ -911,7 +1056,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" dependencies = [ - "bitflags", + "bitflags 1.2.1", "futures-channel", "futures-core", "futures-executor", @@ -930,7 +1075,7 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4" dependencies = [ - "bitflags", + "bitflags 1.2.1", "futures-channel", "futures-core", "futures-executor", @@ -1023,7 +1168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb51122dd3317e9327ec1e4faa151d1fa0d95664cd8fb8dcfacf4d4d29ac70c" dependencies = [ "atk", - "bitflags", + "bitflags 1.2.1", "cairo-rs", "field-offset", "futures-channel", @@ -1093,6 +1238,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1106,7 +1257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ "crypto-mac", - "digest", + "digest 0.9.0", ] [[package]] @@ -1125,7 +1276,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46dd0a94b393c730779ccfd2a872b67b1eb67be3fc33082e733bdb38b5fde4d4" dependencies = [ - "bitflags", + "bitflags 1.2.1", "inotify-sys", "libc", ] @@ -1194,9 +1345,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libcitadel" @@ -1241,6 +1392,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "log" version = "0.4.17" @@ -1256,8 +1413,8 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.9.0", + "digest 0.9.0", "opaque-debug", ] @@ -1276,6 +1433,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.5.1" @@ -1291,7 +1457,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" dependencies = [ - "bitflags", + "bitflags 1.2.1", "cc", "cfg-if 0.1.10", "libc", @@ -1300,15 +1466,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.21.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d9f3521ea8e0641a153b3cddaf008dcbf26acd4ed739a2517295e0760d12c7" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", - "cc", + "bitflags 2.6.0", "cfg-if 1.0.0", + "cfg_aliases", "libc", - "memoffset", + "memoffset 0.9.1", ] [[package]] @@ -1401,9 +1567,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1411,6 +1577,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "owning_ref" version = "0.4.1" @@ -1426,7 +1602,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438" dependencies = [ - "bitflags", + "bitflags 1.2.1", "glib 0.10.3", "glib-sys 0.10.1", "gobject-sys 0.10.0", @@ -1441,7 +1617,7 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546fd59801e5ca735af82839007edd226fe7d3bb06433ec48072be4439c28581" dependencies = [ - "bitflags", + "bitflags 1.2.1", "glib 0.14.8", "libc", "once_cell", @@ -1474,9 +1650,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.0.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pest" @@ -1489,9 +1665,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1499,6 +1675,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.1.1", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.25" @@ -1507,15 +1694,17 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "polling" -version = "2.2.0" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", ] [[package]] @@ -1553,6 +1742,15 @@ dependencies = [ "toml 0.5.9", ] +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1601,7 +1799,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0941606b9934e2d98a3677759a971756eb821f75764d0e0d26946d08e74d9104" dependencies = [ - "bitflags", + "bitflags 1.2.1", "byteorder", "chrono", "flate2", @@ -1689,6 +1887,9 @@ dependencies = [ name = "realmsd" version = "0.1.0" dependencies = [ + "async-io", + "blocking", + "event-listener", "libcitadel", "serde", "serde_repr", @@ -1702,7 +1903,7 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1714,23 +1915,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "regex" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1776,6 +1960,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "same-file" version = "1.0.6" @@ -1785,12 +1982,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "semver" version = "0.11.0" @@ -1843,13 +2034,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.95", + "syn 2.0.77", ] [[package]] @@ -1867,38 +2058,34 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] [[package]] name = "sha1" -version = "0.6.1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "sha1_smol", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] @@ -1929,17 +2116,11 @@ checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" [[package]] name = "slab" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" - -[[package]] -name = "slotmap" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "version_check", + "autocfg", ] [[package]] @@ -1948,16 +2129,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "sodiumoxide" version = "0.2.7" @@ -2115,7 +2286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", - "fastrand", + "fastrand 1.7.0", "libc", "redox_syscall", "remove_dir_all", @@ -2216,6 +2387,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.77", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.15.0" @@ -2228,6 +2430,17 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset 0.9.1", + "tempfile", + "winapi", +] + [[package]] name = "unicode-ident" version = "1.0.0" @@ -2288,12 +2501,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "walkdir" version = "2.3.2" @@ -2311,15 +2518,6 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2369,6 +2567,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2499,6 +2706,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "xi-unicode" version = "0.1.0" @@ -2507,58 +2724,74 @@ checksum = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1" [[package]] name = "zbus" -version = "2.0.0-beta.5" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45f4720326304c291f96f66b6c1131f16964bba6bffe216ac85de2e48321a10" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" dependencies = [ "async-broadcast", - "async-channel", "async-executor", + "async-fs", "async-io", "async-lock", + "async-process", + "async-recursion", "async-task", - "byteorder", - "derivative", + "async-trait", + "blocking", "enumflags2", + "event-listener", "futures-core", "futures-sink", "futures-util", "hex", - "nix 0.21.2", - "once_cell", + "nix 0.29.0", + "ordered-stream", "rand", - "scoped-tls", "serde", "serde_repr", "sha1", - "slotmap", "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", "zbus_macros", + "zbus_names", "zvariant", ] [[package]] name = "zbus_macros" -version = "2.0.0-beta.5" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf0fa91321143695013cb3fa62a6395dbe14eafd97ab58c2ba73f61d5035b1d9" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.2.0", "proc-macro2 1.0.86", "quote 1.0.37", - "regex", - "syn 1.0.95", + "syn 2.0.77", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant", ] [[package]] name = "zvariant" -version = "2.10.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" dependencies = [ - "byteorder", + "endi", "enumflags2", - "libc", "serde", "static_assertions", "zvariant_derive", @@ -2566,12 +2799,24 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "2.10.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ca5e22593eb4212382d60d26350065bf2a02c34b85bc850474a74b589a3de9" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.2.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 1.0.95", + "syn 2.0.77", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.77", ] diff --git a/data/com.subgraph.realms.Manager.conf b/data/com.subgraph.realms.Manager.conf index 49d9287..377304a 100644 --- a/data/com.subgraph.realms.Manager.conf +++ b/data/com.subgraph.realms.Manager.conf @@ -7,10 +7,12 @@ + + fmt::Result { match self { + RealmEvent::Starting(ref realm) => write!(f, "RealmStarting({})", realm.name()), RealmEvent::Started(ref realm) => write!(f, "RealmStarted({})", realm.name()), + RealmEvent::Stopping(ref realm) => write!(f, "RealmStopping({})", realm.name()), RealmEvent::Stopped(ref realm) => write!(f, "RealmStopped({})", realm.name()), RealmEvent::New(ref realm) => write!(f, "RealmNew({})", realm.name()), RealmEvent::Removed(ref realm) => write!(f, "RealmRemoved({})", realm.name()), diff --git a/libcitadel/src/realm/manager.rs b/libcitadel/src/realm/manager.rs index 54e77cb..55ed041 100644 --- a/libcitadel/src/realm/manager.rs +++ b/libcitadel/src/realm/manager.rs @@ -194,7 +194,13 @@ impl RealmManager { return Ok(()); } info!("Starting realm {}", realm.name()); - self._start_realm(realm, &mut HashSet::new())?; + self.inner().events.send_event(RealmEvent::Starting(realm.clone())); + if let Err(err) = self._start_realm(realm, &mut HashSet::new()) { + self.inner().events.send_event(RealmEvent::Stopped(realm.clone())); + return Err(err); + } + + self.inner().events.send_event(RealmEvent::Started(realm.clone())); if !Realms::is_some_realm_current() { self.inner_mut().realms.set_realm_current(realm) @@ -292,6 +298,7 @@ impl RealmManager { } info!("Stopping realm {}", realm.name()); + self.inner().events.send_event(RealmEvent::Stopping(realm.clone())); if realm.config().flatpak() { if let Err(err) = self.stop_gnome_software_sandbox(realm) { @@ -300,8 +307,12 @@ impl RealmManager { } realm.set_active(false); - self.systemd.stop_realm(realm)?; + if let Err(err) = self.systemd.stop_realm(realm) { + self.inner().events.send_event(RealmEvent::Stopped(realm.clone())); + return Err(err); + } realm.cleanup_rootfs(); + self.inner().events.send_event(RealmEvent::Stopped(realm.clone())); if realm.is_current() { self.choose_some_current_realm(); diff --git a/libcitadel/src/realm/realm.rs b/libcitadel/src/realm/realm.rs index 2f7f048..ad60d4b 100644 --- a/libcitadel/src/realm/realm.rs +++ b/libcitadel/src/realm/realm.rs @@ -169,6 +169,20 @@ impl Realm { self.inner.write().unwrap() } + + pub fn start(&self) -> Result<()> { + warn!("Realm({})::start()", self.name()); + self.manager().start_realm(self) + } + + pub fn stop(&self) -> Result<()> { + self.manager().stop_realm(self) + } + + pub fn set_current(&self) -> Result<()> { + self.manager().set_current_realm(self) + } + pub fn is_active(&self) -> bool { self.inner_mut().is_active() } diff --git a/realm-config-ui/Cargo.toml b/realm-config-ui/Cargo.toml index 084f342..9ea95b0 100644 --- a/realm-config-ui/Cargo.toml +++ b/realm-config-ui/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://subgraph.com" [dependencies] libcitadel = { path = "../libcitadel" } rand = "0.8" -zvariant = "2.7.0" +zvariant = "4.2.0" serde = { version = "1.0", features = ["derive"] } -zbus = "=2.0.0-beta.5" +zbus = "4.4.0" gtk = { version = "0.14.0", features = ["v3_24"] } diff --git a/realm-config-ui/src/realmsd.rs b/realm-config-ui/src/realmsd.rs index 710678e..44ec226 100644 --- a/realm-config-ui/src/realmsd.rs +++ b/realm-config-ui/src/realmsd.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::rc::Rc; -use zbus::dbus_proxy; -use zvariant::derive::Type; +use zvariant::Type; use serde::{Serialize,Deserialize}; - +use zbus::proxy; +use zbus::blocking::Connection; use crate::error::{Error, Result}; #[derive(Deserialize,Serialize,Type)] @@ -85,10 +85,12 @@ impl RealmConfig { } } -#[dbus_proxy( +#[proxy( default_service = "com.subgraph.realms", interface = "com.subgraph.realms.Manager", -default_path = "/com/subgraph/realms" +default_path = "/com/subgraph/realms", +gen_blocking = true, +gen_async = false, )] pub trait RealmsManager { fn get_current(&self) -> zbus::Result; @@ -102,7 +104,7 @@ pub trait RealmsManager { impl RealmsManagerProxy<'_> { pub fn connect() -> Result { - let connection = zbus::Connection::new_system()?; + let connection = Connection::system()?; let proxy = RealmsManagerProxy::new(&connection) .map_err(|_| Error::ManagerConnect)?; diff --git a/realmsd/Cargo.toml b/realmsd/Cargo.toml index a43574e..e832cf7 100644 --- a/realmsd/Cargo.toml +++ b/realmsd/Cargo.toml @@ -6,8 +6,11 @@ edition = "2018" [dependencies] libcitadel = { path = "../libcitadel" } -zbus = "=2.0.0-beta.5" -zvariant = "2.7.0" +async-io = "2.3.2" +blocking = "1.6.1" +event-listener = "5.3.1" +zbus = "4.4.0" +zvariant = "4.2.0" serde = { version = "1.0", features = ["derive"] } serde_repr = "0.1.8" diff --git a/realmsd/src/events.rs b/realmsd/src/events.rs index 20ff44d..91205d8 100644 --- a/realmsd/src/events.rs +++ b/realmsd/src/events.rs @@ -1,15 +1,16 @@ -use zbus::{Connection, ObjectServer}; +use async_io::block_on; +use zbus::blocking::Connection; +use zbus::SignalContext; use crate::realms_manager::{RealmsManagerServer, REALMS_SERVER_OBJECT_PATH, realm_status}; use libcitadel::{RealmEvent, Realm}; pub struct EventHandler { connection: Connection, - realms_server: RealmsManagerServer, } impl EventHandler { - pub fn new(connection: Connection, realms_server: RealmsManagerServer) -> Self { - EventHandler { connection, realms_server } + pub fn new(connection: Connection) -> Self { + EventHandler { connection } } pub fn handle_event(&self, ev: &RealmEvent) { @@ -25,44 +26,49 @@ impl EventHandler { RealmEvent::New(realm) => self.on_new(realm), RealmEvent::Removed(realm) => self.on_removed(realm), RealmEvent::Current(realm) => self.on_current(realm.as_ref()), + RealmEvent::Starting(_) => Ok(()), + RealmEvent::Stopping(_) => Ok(()), } } - fn with_server(&self, func: F) -> zbus::Result<()> + fn with_signal_context(&self, func: F) -> zbus::Result<()> where - F: Fn(&RealmsManagerServer) -> zbus::Result<()>, + F: Fn(&SignalContext) -> zbus::Result<()>, { - let mut object_server = ObjectServer::new(&self.connection); - object_server.at(REALMS_SERVER_OBJECT_PATH, self.realms_server.clone())?; - object_server.with(REALMS_SERVER_OBJECT_PATH, |iface: &RealmsManagerServer| func(iface)) + let object_server = self.connection.object_server(); + let iface = object_server.interface::<_, RealmsManagerServer>(REALMS_SERVER_OBJECT_PATH)?; + + let ctx = iface.signal_context(); + func(ctx) } fn on_started(&self, realm: &Realm) -> zbus::Result<()> { let pid_ns = realm.pid_ns().unwrap_or(0); let status = realm_status(realm); - self.with_server(|server| server.realm_started(realm.name(), pid_ns, status)) + self.with_signal_context(|ctx| block_on(RealmsManagerServer::realm_started(ctx, realm.name(), pid_ns, status))) } fn on_stopped(&self, realm: &Realm) -> zbus::Result<()> { let status = realm_status(realm); - self.with_server(|server| server.realm_stopped(realm.name(), status)) + self.with_signal_context(|ctx| block_on(RealmsManagerServer::realm_stopped(ctx, realm.name(), status))) } fn on_new(&self, realm: &Realm) -> zbus::Result<()> { let status = realm_status(realm); let description = realm.notes().unwrap_or(String::new()); - self.with_server(|server| server.realm_new(realm.name(), &description, status)) + self.with_signal_context(|ctx| block_on(RealmsManagerServer::realm_new(ctx, realm.name(), &description, status))) } fn on_removed(&self, realm: &Realm) -> zbus::Result<()> { - self.with_server(|server| server.realm_removed(realm.name())) + self.with_signal_context(|ctx| block_on(RealmsManagerServer::realm_removed(ctx, realm.name()))) } fn on_current(&self, realm: Option<&Realm>) -> zbus::Result<()> { - self.with_server(|server| { + self.with_signal_context(|ctx| { match realm { - Some(realm) => server.realm_current(realm.name(), realm_status(realm)), - None => server.realm_current("", 0), + Some(realm) => block_on(RealmsManagerServer::realm_current(ctx, realm.name(), realm_status(realm))), + None => block_on(RealmsManagerServer::realm_current(ctx, "", 0)), + } }) } diff --git a/realmsd/src/main.rs b/realmsd/src/main.rs index 5f81946..080e8c5 100644 --- a/realmsd/src/main.rs +++ b/realmsd/src/main.rs @@ -1,14 +1,18 @@ #[macro_use] extern crate libcitadel; -use zbus::{Connection, fdo}; - -use libcitadel::{Logger, LogLevel, Result}; - -use crate::realms_manager::RealmsManagerServer; +use std::env; +use std::sync::Arc; +use event_listener::{Event, Listener}; +use zbus::blocking::Connection; +use zbus::fdo::ObjectManager; +use libcitadel::{Logger, LogLevel, Result, RealmManager}; +use crate::next::{RealmsManagerServer2, REALMS2_SERVER_OBJECT_PATH}; +use crate::realms_manager::{RealmsManagerServer, REALMS_SERVER_OBJECT_PATH}; mod realms_manager; mod events; +mod next; fn main() { if let Err(e) = run_realm_manager() { @@ -16,24 +20,43 @@ fn main() { } } -fn create_system_connection() -> zbus::Result { - let connection = zbus::Connection::new_system()?; - fdo::DBusProxy::new(&connection)?.request_name("com.subgraph.realms", fdo::RequestNameFlags::AllowReplacement.into())?; - Ok(connection) +fn register_realms_manager_server(connection: &Connection, realm_manager: &Arc, quit_event: &Arc) -> Result<()> { + let server = RealmsManagerServer::load(&connection, realm_manager.clone(), quit_event.clone()) + .map_err(context!("Loading realms server"))?; + connection.object_server().at(REALMS_SERVER_OBJECT_PATH, server).map_err(context!("registering realms manager object"))?; + Ok(()) +} + +fn register_realms2_manager_server(connection: &Connection, realm_manager: &Arc, quit_event: &Arc) -> Result<()> { + let server2 = RealmsManagerServer2::load(&connection, realm_manager.clone(), quit_event.clone()) + .map_err(context!("Loading realms2 server"))?; + connection.object_server().at(REALMS2_SERVER_OBJECT_PATH, server2).map_err(context!("registering realms manager object"))?; + connection.object_server().at(REALMS2_SERVER_OBJECT_PATH, ObjectManager).map_err(context!("registering ObjectManager"))?; + Ok(()) } fn run_realm_manager() -> Result<()> { Logger::set_log_level(LogLevel::Verbose); - let connection = create_system_connection() - .map_err(context!("ZBus Connection error"))?; + let testing = env::args().skip(1).any(|s| s == "--testing"); - let mut object_server = RealmsManagerServer::register(&connection)?; + let connection = Connection::system() + .map_err(context!("ZBus Connection error"))?; - loop { - if let Err(err) = object_server.try_handle_next() { - warn!("Error handling DBus message: {}", err); - } - } + let realm_manager = RealmManager::load()?; + let quit_event = Arc::new(Event::new()); + + if testing { + register_realms2_manager_server(&connection, &realm_manager, &quit_event)?; + connection.request_name("com.subgraph.Realms2") + .map_err(context!("acquiring realms manager name"))?; + } else { + register_realms_manager_server(&connection, &realm_manager, &quit_event)?; + register_realms2_manager_server(&connection, &realm_manager, &quit_event)?; + connection.request_name("com.subgraph.realms") + .map_err(context!("acquiring realms manager name"))?; + }; + quit_event.listen().wait(); + Ok(()) } diff --git a/realmsd/src/next/config.rs b/realmsd/src/next/config.rs new file mode 100644 index 0000000..0099f06 --- /dev/null +++ b/realmsd/src/next/config.rs @@ -0,0 +1,201 @@ +use std::collections::HashMap; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use serde::{Deserialize, Serialize}; +use zbus::fdo; +use zvariant::Type; +use libcitadel::{OverlayType, Realm, GLOBAL_CONFIG}; +use libcitadel::terminal::Base16Scheme; +use crate::next::manager::failed; + +const BOOL_CONFIG_VARS: &[&str] = &[ + "use-gpu", "use-wayland", "use-x11", "use-sound", + "use-shared-dir", "use-network", "use-kvm", "use-ephemeral-home", + "use-media-dir", "use-fuse", "use-flatpak", "use-gpu-card0" +]; + +fn is_bool_config_variable(variable: &str) -> bool { + BOOL_CONFIG_VARS.iter().any(|&s| s == variable) +} + +#[derive(Deserialize,Serialize,Type)] +pub struct RealmConfigVars { + items: HashMap, +} + +impl RealmConfigVars { + fn new() -> Self { + RealmConfigVars { items: HashMap::new() } + } + + pub fn new_global() -> Self { + Self::new_from_config(&GLOBAL_CONFIG) + } + + fn new_from_realm(realm: &Realm) -> Self { + let config = realm.config(); + Self::new_from_config(&config) + } + + fn new_from_config(config: &libcitadel::RealmConfig) -> Self { + let mut vars = RealmConfigVars::new(); + vars.add_bool("use-gpu", config.gpu()); + vars.add_bool("use-gpu-card0", config.gpu_card0()); + vars.add_bool("use-wayland", config.wayland()); + vars.add_bool("use-x11", config.x11()); + vars.add_bool("use-sound", config.sound()); + vars.add_bool("use-shared-dir", config.shared_dir()); + vars.add_bool("use-network", config.network()); + vars.add_bool("use-kvm", config.kvm()); + vars.add_bool("use-ephemeral-home", config.ephemeral_home()); + vars.add_bool("use-media-dir", config.media_dir()); + vars.add_bool("use-fuse", config.fuse()); + vars.add_bool("use-flatpak", config.flatpak()); + + let overlay = match config.overlay() { + OverlayType::None => "none", + OverlayType::TmpFS => "tmpfs", + OverlayType::Storage => "storage", + }; + vars.add("overlay", overlay); + + let scheme = match config.terminal_scheme() { + Some(name) => name.to_string(), + None => String::new(), + }; + vars.add("terminal-scheme", scheme); + vars.add("realmfs", config.realmfs()); + vars + } + + fn add_bool(&mut self, name: &str, val: bool) { + let valstr = if val { "true".to_string() } else { "false".to_string() }; + self.add(name, valstr); + } + + fn add(&mut self, k: S, v: T) where S: Into, T: Into { + self.items.insert(k.into(), v.into()); + } +} + +#[derive(Clone)] +pub struct RealmConfig { + realm: Realm, + changed: Arc, +} + +impl RealmConfig { + pub fn new(realm: Realm) -> Self { + let changed = Arc::new(AtomicBool::new(false)); + RealmConfig { realm, changed } + } + + fn mark_changed(&self) { + self.changed.store(true, Ordering::Relaxed); + } + + fn is_changed(&self) -> bool { + self.changed.load(Ordering::Relaxed) + } + + pub fn config_vars(&self) -> RealmConfigVars { + RealmConfigVars::new_from_realm(&self.realm) + } + + fn set_bool_var(&mut self, var: &str, value: &str) -> fdo::Result<()> { + let v = match value { + "true" => true, + "false" => false, + _ => return failed(format!("Invalid boolean value '{}' for realm config variable '{}'", value, var)), + }; + + let mut has_changed = true; + self.realm.with_mut_config(|c| { + match var { + "use-gpu" if c.gpu() != v => c.use_gpu = Some(v), + _ => has_changed = false, + } + }); + if has_changed { + self.mark_changed(); + } + Ok(()) + } + + fn set_overlay(&mut self, value: &str) -> fdo::Result<()> { + let val = match value { + "tmpfs" => Some("tmpfs".to_string()), + "storage" => Some("storage".to_string()), + "none" => None, + _ => return failed(format!("Invalid value '{}' for overlay config", value)), + }; + if self.realm.config().overlay != val { + self.realm.with_mut_config(|c| { + c.overlay = Some(value.to_string()); + }); + self.mark_changed(); + } + Ok(()) + } + + fn set_terminal_scheme(&mut self, value: &str) -> fdo::Result<()> { + if Some(value) == self.realm.config().terminal_scheme() { + return Ok(()) + } + + let scheme = match Base16Scheme::by_name(value) { + Some(scheme) => scheme, + None => return failed(format!("Invalid terminal color scheme '{}'", value)), + }; + + let manager = self.realm.manager(); + if let Err(err) = scheme.apply_to_realm(&manager, &self.realm) { + return failed(format!("Error applying terminal color scheme: {}", err)); + } + + self.realm.with_mut_config(|c| { + c.terminal_scheme = Some(value.to_string()); + }); + self.mark_changed(); + Ok(()) + } + + fn set_realmfs(&mut self, value: &str) -> fdo::Result<()> { + let manager = self.realm.manager(); + if manager.realmfs_by_name(value).is_none() { + return failed(format!("Failed to set 'realmfs' config for realm-{}: RealmFS named '{}' does not exist", self.realm.name(), value)); + } + if self.realm.config().realmfs() != value { + self.realm.with_mut_config(|c| { + c.realmfs = Some(value.to_string()) + }); + self.mark_changed(); + } + Ok(()) + } + + pub fn save_config(&self) -> fdo::Result<()> { + if self.is_changed() { + self.realm.config() + .write() + .map_err(|err| fdo::Error::Failed(format!("Error writing config file for realm-{}: {}", self.realm.name(), err)))?; + + self.changed.store(false, Ordering::Relaxed); + } + Ok(()) + } + + pub fn set_var(&mut self, var: &str, value: &str) -> fdo::Result<()> { + if is_bool_config_variable(var) { + self.set_bool_var(var, value) + } else if var == "overlay" { + self.set_overlay(value) + } else if var == "terminal-scheme" { + self.set_terminal_scheme(value) + } else if var == "realmfs" { + self.set_realmfs(value) + } else { + failed(format!("Unknown realm configuration variable '{}'", var)) + } + } +} \ No newline at end of file diff --git a/realmsd/src/next/manager.rs b/realmsd/src/next/manager.rs new file mode 100644 index 0000000..35fbd8b --- /dev/null +++ b/realmsd/src/next/manager.rs @@ -0,0 +1,103 @@ +use std::sync::Arc; +use blocking::unblock; +use event_listener::{Event, EventListener}; +use serde::Serialize; +use serde_repr::Serialize_repr; +use zbus::blocking::Connection; +use zbus::{fdo, interface}; +use zvariant::Type; +use libcitadel::{PidLookupResult, RealmManager}; +use crate::next::config::RealmConfigVars; +use crate::next::realm::RealmItemState; +use crate::next::realmfs::RealmFSState; + +pub fn failed(message: String) -> fdo::Result { + Err(fdo::Error::Failed(message)) +} + +#[derive(Serialize_repr, Type, Debug, PartialEq)] +#[repr(u32)] +pub enum PidLookupResultCode { + Unknown = 1, + Realm = 2, + Citadel = 3, +} + +#[derive(Debug, Type, Serialize)] +pub struct RealmFromCitadelPid { + code: PidLookupResultCode, + realm: String, +} + +impl From for RealmFromCitadelPid { + fn from(result: PidLookupResult) -> Self { + match result { + PidLookupResult::Unknown => RealmFromCitadelPid { code: PidLookupResultCode::Unknown, realm: String::new() }, + PidLookupResult::Realm(realm) => RealmFromCitadelPid { code: PidLookupResultCode::Realm, realm: realm.name().to_string() }, + PidLookupResult::Citadel => RealmFromCitadelPid { code: PidLookupResultCode::Citadel, realm: String::new() }, + } + } +} + +pub struct RealmsManagerServer2 { + realms: RealmItemState, + realmfs_state: RealmFSState, + manager: Arc, + quit_event: Arc, +} + + +impl RealmsManagerServer2 { + + fn new(connection: Connection, manager: Arc, quit_event: Arc) -> Self { + let realms = RealmItemState::new(connection.clone()); + let realmfs_state = RealmFSState::new(connection.clone()); + RealmsManagerServer2 { + realms, + realmfs_state, + manager, + quit_event, + } + } + + pub fn load(connection: &Connection, manager: Arc, quit_event: Arc) -> zbus::Result { + let mut server = Self::new(connection.clone(), manager.clone(), quit_event); + server.realms.load_realms(&manager)?; + server.realmfs_state.load(&manager)?; + server.realms.populate_realmfs(&server.realmfs_state)?; + Ok(server) + } + +} + +#[interface(name = "com.subgraph.realms.Manager2")] +impl RealmsManagerServer2 { + + async fn get_current(&self) -> u32 { + + self.realms.get_current() + .map(|r| r.index()) + .unwrap_or(0) + } + + async fn realm_from_citadel_pid(&self, pid: u32) -> RealmFromCitadelPid { + let manager = self.manager.clone(); + unblock(move || { + manager.realm_by_pid(pid).into() + }).await + } + + async fn create_realm(&self, name: &str) -> fdo::Result<()> { + let manager = self.manager.clone(); + let name = name.to_string(); + unblock(move || { + let _ = manager.new_realm(&name).map_err(|err| fdo::Error::Failed(err.to_string()))?; + Ok(()) + }).await + } + + async fn get_global_config(&self) -> RealmConfigVars { + RealmConfigVars::new_global() + } + +} diff --git a/realmsd/src/next/mod.rs b/realmsd/src/next/mod.rs new file mode 100644 index 0000000..b564a0f --- /dev/null +++ b/realmsd/src/next/mod.rs @@ -0,0 +1,8 @@ + +mod manager; +mod config; +mod realm; +mod realmfs; + +pub use manager::RealmsManagerServer2; +pub const REALMS2_SERVER_OBJECT_PATH: &str = "/com/subgraph/Realms2"; diff --git a/realmsd/src/next/realm.rs b/realmsd/src/next/realm.rs new file mode 100644 index 0000000..3fca1e7 --- /dev/null +++ b/realmsd/src/next/realm.rs @@ -0,0 +1,374 @@ +use std::collections::HashMap; +use std::convert::TryInto; +use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU32, Ordering}; +use blocking::unblock; +use zbus::{interface, fdo}; +use zbus::blocking::Connection; +use zbus::names::{BusName, InterfaceName}; +use zvariant::{OwnedObjectPath, Value}; +use libcitadel::{Realm, RealmEvent, RealmManager, Result}; +use crate::next::config::{RealmConfig, RealmConfigVars}; +use crate::next::realmfs::RealmFSState; +use crate::next::REALMS2_SERVER_OBJECT_PATH; + +#[derive(Clone)] +pub struct RealmItem { + path: String, + index: u32, + realm: Realm, + config: RealmConfig, + in_run_transition: Arc, + realmfs_index: Arc, + last_timestamp: Arc, +} + +#[derive(Copy,Clone)] +#[repr(u32)] +enum RealmRunStatus { + Stopped = 0, + Starting, + Running, + Current, + Stopping, +} + +impl RealmRunStatus { + fn for_realm(realm: &Realm, in_transition: bool) -> Self { + if in_transition { + if realm.is_active() { Self::Stopping } else { Self::Starting } + } else if realm.is_active() { + if realm.is_current() { Self::Current } else {Self::Running } + } else { + Self::Stopped + } + } +} + +impl RealmItem { + pub(crate) fn new_from_realm(index: u32, realm: Realm) -> RealmItem { + let path = format!("{}/Realm{}", REALMS2_SERVER_OBJECT_PATH, index); + let in_run_transition = Arc::new(AtomicBool::new(false)); + let config = RealmConfig::new(realm.clone()); + let realmfs_index = Arc::new(AtomicU32::new(0)); + let last_timestamp = Arc::new(AtomicI64::new(realm.timestamp())); + RealmItem { path, index, realm, config, in_run_transition, realmfs_index, last_timestamp } + } + + pub fn path(&self) -> &str { + &self.path + } + + pub fn index(&self) -> u32 { + self.index + } + + fn in_run_transition(&self) -> bool { + self.in_run_transition.load(Ordering::Relaxed) + } + + fn get_run_status(&self) -> RealmRunStatus { + RealmRunStatus::for_realm(&self.realm, self.in_run_transition()) + } + + async fn do_start(&mut self) -> fdo::Result<()> { + if !self.realm.is_active() { + let realm = self.realm.clone(); + + let res = unblock(move || realm.start()).await; + + if let Err(err) = res { + return Err(fdo::Error::Failed(format!("Failed to start realm: {}", err))); + } + } + Ok(()) + } + + async fn do_stop(&mut self) -> fdo::Result<()> { + if self.realm.is_active() { + let realm = self.realm.clone(); + + let res = unblock(move || realm.stop()).await; + + if let Err(err) = res { + return Err(fdo::Error::Failed(format!("Failed to stop realm: {}", err))); + } + } + Ok(()) + } +} + +#[interface( + name = "com.subgraph.realms.Realm" +)] +impl RealmItem { + + async fn start( + &mut self, + ) -> fdo::Result<()> { + + self.do_start().await?; + Ok(()) + } + + async fn stop( + &mut self, + ) -> fdo::Result<()> { + self.do_stop().await?; + Ok(()) + } + + async fn restart( + &mut self, + ) -> fdo::Result<()> { + self.do_stop().await?; + self.do_start().await?; + Ok(()) + } + + async fn set_current(&mut self) -> fdo::Result<()> { + let realm = self.realm.clone(); + let res = unblock(move || realm.set_current()).await; + if let Err(err) = res { + return Err(fdo::Error::Failed(format!("Failed to set realm {} as current: {}", self.realm.name(), err))); + } + Ok(()) + } + + async fn get_config(&self) -> RealmConfigVars { + self.config.config_vars() + } + + async fn set_config(&mut self, vars: Vec<(String, String)>) -> fdo::Result<()> { + for (var, val) in &vars { + self.config.set_var(var, val)?; + } + let config = self.config.clone(); + unblock(move || config.save_config()).await + } + + #[zbus(property, name = "RunStatus")] + fn run_status(&self) -> u32 { + self.get_run_status() as u32 + } + + #[zbus(property, name="IsSystemRealm")] + fn is_system_realm(&self) -> bool { + self.realm.is_system() + } + + #[zbus(property, name = "Name")] + fn name(&self) -> &str { + self.realm.name() + } + + #[zbus(property, name = "Description")] + fn description(&self) -> String { + self.realm.notes() + .unwrap_or(String::new()) + } + + #[zbus(property, name = "PidNS")] + fn pid_ns(&self) -> u64 { + self.realm.pid_ns().unwrap_or_default() + } + + #[zbus(property, name = "RealmFS")] + fn realmfs(&self) -> u32 { + self.realmfs_index.load(Ordering::Relaxed) + } + + #[zbus(property, name = "Timestamp")] + fn timestamp(&self) -> u64 { + self.realm.timestamp() as u64 + } +} + + +#[derive(Clone)] +pub struct RealmItemState(Arc>); + +struct Inner { + connection: Connection, + next_index: u32, + realms: HashMap, + current_realm: Option, +} + +impl Inner { + fn new(connection: Connection) -> Self { + Inner { + connection, + next_index: 1, + realms:HashMap::new(), + current_realm: None, + } + } + + fn load_realms(&mut self, manager: &RealmManager) -> zbus::Result<()> { + for realm in manager.realm_list() { + self.add_realm(realm)?; + } + Ok(()) + } + pub fn populate_realmfs(&mut self, realmfs_state: &RealmFSState) -> zbus::Result<()> { + for item in self.realms.values_mut() { + if let Some(realmfs) = realmfs_state.realmfs_by_name(item.realm.config().realmfs()) { + item.realmfs_index.store(realmfs.index(), Ordering::Relaxed); + } + } + Ok(()) + } + + fn add_realm(&mut self, realm: Realm) -> zbus::Result<()> { + if self.realms.contains_key(realm.name()) { + warn!("Attempted to add duplicate realm '{}'", realm.name()); + return Ok(()) + } + + let key = realm.name().to_string(); + let item = RealmItem::new_from_realm(self.next_index, realm); + self.connection.object_server().at(item.path(), item.clone())?; + self.realms.insert(key, item); + self.next_index += 1; + Ok(()) + } + + fn remove_realm(&mut self, realm: &Realm) -> zbus::Result<()> { + if let Some(item) = self.realms.remove(realm.name()) { + self.connection.object_server().remove::(item.path())?; + } else { + warn!("Failed to find realm to remove with name '{}'", realm.name()); + } + Ok(()) + } + + fn emit_property_changed(&self, object_path: OwnedObjectPath, propname: &str, value: Value<'_>) -> zbus::Result<()> { + let iface_name = InterfaceName::from_str_unchecked("com.subgraph.realms.Realm"); + let changed = HashMap::from([(propname.to_string(), value)]); + let inval: &[&str] = &[]; + self.connection.emit_signal( + None::>, + &object_path, + "org.freedesktop.Dbus.Properties", + "PropertiesChanged", + &(iface_name, changed, inval))?; + Ok(()) + } + fn realm_status_changed(&self, realm: &Realm, transition: Option) -> zbus::Result<()> { + if let Some(realm) = self.realm_by_name(realm.name()) { + if let Some(transition) = transition { + realm.in_run_transition.store(transition, Ordering::Relaxed); + } + let object_path = realm.path().try_into().unwrap(); + self.emit_property_changed(object_path, "RunStatus", Value::U32(realm.get_run_status() as u32))?; + let timestamp = realm.realm.timestamp(); + if realm.last_timestamp.load(Ordering::Relaxed) != realm.realm.timestamp() { + realm.last_timestamp.store(timestamp, Ordering::Relaxed); + let object_path = realm.path().try_into().unwrap(); + self.emit_property_changed(object_path, "Timestamp", Value::U64(timestamp as u64))?; + } + } + Ok(()) + } + + fn realm_by_name(&self, name: &str) -> Option<&RealmItem> { + let res = self.realms.get(name); + + if res.is_none() { + warn!("Failed to find realm with name '{}'", name); + } + res + } + + fn on_starting(&self, realm: &Realm) -> zbus::Result<()>{ + self.realm_status_changed(realm, Some(true))?; + Ok(()) + } + + fn on_started(&self, realm: &Realm) -> zbus::Result<()>{ + self.realm_status_changed(realm, Some(false)) + } + + fn on_stopping(&self, realm: &Realm) -> zbus::Result<()> { + self.realm_status_changed(realm, Some(true)) + } + + fn on_stopped(&self, realm: &Realm) -> zbus::Result<()> { + self.realm_status_changed(realm, Some(false)) + } + + fn on_new(&mut self, realm: &Realm) -> zbus::Result<()> { + self.add_realm(realm.clone())?; + Ok(()) + } + + fn on_removed(&mut self, realm: &Realm) -> zbus::Result<()> { + self.remove_realm(&realm)?; + Ok(()) + } + + fn on_current(&mut self, realm: Option<&Realm>) -> zbus::Result<()> { + + if let Some(r) = self.current_realm.take() { + self.realm_status_changed(&r.realm, None)?; + } + + if let Some(realm) = realm { + self.realm_status_changed(realm, None)?; + if let Some(item) = self.realm_by_name(realm.name()) { + self.current_realm = Some(item.clone()); + } + } + Ok(()) + } +} + +impl RealmItemState { + pub fn new(connection: Connection) -> Self { + RealmItemState(Arc::new(Mutex::new(Inner::new(connection)))) + } + + pub fn load_realms(&self, manager: &RealmManager) -> zbus::Result<()> { + self.inner().load_realms(manager)?; + self.add_event_handler(manager) + .map_err(|err| zbus::Error::Failure(err.to_string()))?; + Ok(()) + } + + pub fn populate_realmfs(&self, realmfs_state: &RealmFSState) -> zbus::Result<()> { + self.inner().populate_realmfs(realmfs_state) + } + + pub fn get_current(&self) -> Option { + self.inner().current_realm.clone() + } + + fn inner(&self) -> MutexGuard { + self.0.lock().unwrap() + } + + fn add_event_handler(&self, manager: &RealmManager) -> Result<()> { + let state = self.clone(); + manager.add_event_handler(move |ev| { + if let Err(err) = state.handle_event(ev) { + warn!("Error handling {}: {}", ev, err); + } + }); + manager.start_event_task()?; + Ok(()) + } + + fn handle_event(&self, ev: &RealmEvent) -> zbus::Result<()> { + match ev { + RealmEvent::Started(realm) => self.inner().on_started(realm)?, + RealmEvent::Stopped(realm) => self.inner().on_stopped(realm)?, + RealmEvent::New(realm) => self.inner().on_new(realm)?, + RealmEvent::Removed(realm) => self.inner().on_removed(realm)?, + RealmEvent::Current(realm) => self.inner().on_current(realm.as_ref())?, + RealmEvent::Starting(realm) => self.inner().on_starting(realm)?, + RealmEvent::Stopping(realm) => self.inner().on_stopping(realm)?, + }; + Ok(()) + } +} \ No newline at end of file diff --git a/realmsd/src/next/realmfs.rs b/realmsd/src/next/realmfs.rs new file mode 100644 index 0000000..38a2371 --- /dev/null +++ b/realmsd/src/next/realmfs.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; +use std::convert::TryInto; +use zbus::blocking::Connection; +use zbus::{fdo, interface}; +use zvariant::{ObjectPath, OwnedObjectPath}; +use libcitadel::{RealmFS, RealmManager}; +use crate::next::REALMS2_SERVER_OBJECT_PATH; + +const BLOCK_SIZE: u64 = 4096; +#[derive(Clone)] +pub struct RealmFSItem { + object_path: OwnedObjectPath, + index: u32, + realmfs: RealmFS, +} +impl RealmFSItem { + pub(crate) fn new_from_realmfs(index: u32, realmfs: RealmFS) -> RealmFSItem { + let object_path = format!("{}/RealmFS{}", REALMS2_SERVER_OBJECT_PATH, index).try_into().unwrap(); + RealmFSItem { + object_path, + index, + realmfs, + } + } + + pub fn index(&self) -> u32 { + self.index + } + + pub fn object_path(&self) -> ObjectPath { + self.object_path.as_ref() + } +} + +#[interface( + name = "com.subgraph.realms.RealmFS" +)] +impl RealmFSItem { + + #[zbus(property, name = "Name")] + fn name(&self) -> &str { + self.realmfs.name() + } + + #[zbus(property, name = "Activated")] + fn activated(&self) -> bool { + self.realmfs.is_activated() + } + + #[zbus(property, name = "InUse")] + fn in_use(&self) -> bool { + self.realmfs.is_activated() + } + #[zbus(property, name = "Mountpoint")] + fn mountpoint(&self) -> String { + self.realmfs.mountpoint().to_string() + } + + #[zbus(property, name = "Path")] + fn path(&self) -> String { + format!("{}", self.realmfs.path().display()) + } + + #[zbus(property, name = "FreeSpace")] + fn free_space(&self) -> fdo::Result { + let blocks = self.realmfs.free_size_blocks() + .map_err(|err| fdo::Error::Failed(err.to_string()))?; + Ok(blocks as u64 * BLOCK_SIZE) + } + + #[zbus(property, name = "AllocatedSpace")] + fn allocated_space(&self) -> fdo::Result { + let blocks = self.realmfs.allocated_size_blocks() + .map_err(|err| fdo::Error::Failed(err.to_string()))?; + Ok(blocks as u64 * BLOCK_SIZE) + } +} + +pub struct RealmFSState { + connection: Connection, + next_index: u32, + items: HashMap, +} + +impl RealmFSState { + pub fn new(connection: Connection) -> Self { + RealmFSState { + connection, + next_index: 1, + items: HashMap::new(), + } + } + + pub fn load(&mut self, manager: &RealmManager) -> zbus::Result<()> { + for realmfs in manager.realmfs_list() { + self.add_realmfs(realmfs)?; + } + Ok(()) + } + + fn add_realmfs(&mut self, realmfs: RealmFS) -> zbus::Result<()> { + if !self.items.contains_key(realmfs.name()) { + let name = realmfs.name().to_string(); + let item = RealmFSItem::new_from_realmfs(self.next_index, realmfs); + self.connection.object_server().at(item.object_path(), item.clone())?; + self.items.insert(name, item); + self.next_index += 1; + } else { + warn!("Attempted to add duplicate realmfs '{}'", realmfs.name()); + } + Ok(()) + } + pub fn realmfs_by_name(&self, name: &str) -> Option<&RealmFSItem> { + let res = self.items.get(name); + if res.is_none() { + warn!("Failed to find RealmFS with name '{}'", name); + } + res + } +} diff --git a/realmsd/src/realms_manager.rs b/realmsd/src/realms_manager.rs index be2ce02..bd3a2da 100644 --- a/realmsd/src/realms_manager.rs +++ b/realmsd/src/realms_manager.rs @@ -1,11 +1,14 @@ use libcitadel::{RealmManager, Realm, OverlayType, Result, PidLookupResult}; use std::sync::Arc; -use zbus::{dbus_interface, ObjectServer,Connection}; -use zvariant::derive::Type; +use zbus::blocking::Connection; +use zvariant::Type; use std::thread; use std::collections::HashMap; -use serde::{Serialize,Deserialize}; +use blocking::unblock; +use event_listener::{Event, EventListener}; +use serde::{Serialize, Deserialize}; use serde_repr::Serialize_repr; +use zbus::{interface, SignalContext}; use crate::events::EventHandler; use libcitadel::terminal::Base16Scheme; @@ -39,6 +42,7 @@ impl From for RealmFromCitadelPid { #[derive(Clone)] pub struct RealmsManagerServer { manager: Arc, + quit_event: Arc, } const BOOL_CONFIG_VARS: &[&str] = &[ @@ -121,40 +125,40 @@ fn configure_realm(manager: &RealmManager, realm: &Realm, variable: &str, value: impl RealmsManagerServer { - fn register_events(&self, connection: &Connection) -> Result<()> { - let events = EventHandler::new(connection.clone(), self.clone()); - self.manager.add_event_handler(move |ev| events.handle_event(ev)); - self.manager.start_event_task() + pub fn load(connection: &Connection, manager: Arc, quit_event: Arc) -> Result { + let server = RealmsManagerServer { manager, quit_event }; + let events = EventHandler::new(connection.clone()); + server.manager.add_event_handler(move |ev| events.handle_event(ev)); + server.manager.start_event_task()?; + Ok(server) } - - pub fn register(connection: &Connection) -> Result { - let manager = RealmManager::load()?; - let iface = RealmsManagerServer { manager }; - iface.register_events(connection)?; - let mut object_server = ObjectServer::new(connection); - object_server.at(REALMS_SERVER_OBJECT_PATH, iface).map_err(context!("ZBus error"))?; - Ok(object_server) - } - } -#[dbus_interface(name = "com.subgraph.realms.Manager")] +#[interface(name = "com.subgraph.realms.Manager")] impl RealmsManagerServer { - fn set_current(&self, name: &str) { - if let Some(realm) = self.manager.realm_by_name(name) { - if let Err(err) = self.manager.set_current_realm(&realm) { - warn!("set_current_realm({}) failed: {}", name, err); + async fn set_current(&self, name: &str) { + + let manager = self.manager.clone(); + let name = name.to_string(); + unblock(move || { + if let Some(realm) = manager.realm_by_name(&name) { + if let Err(err) = manager.set_current_realm(&realm) { + warn!("set_current_realm({}) failed: {}", name, err); + } } - } + }).await } - fn get_current(&self) -> String { - match self.manager.current_realm() { - Some(realm) => realm.name().to_string(), - None => String::new(), - } + async fn get_current(&self) -> String { + let manager = self.manager.clone(); + unblock(move || { + match manager.current_realm() { + Some(realm) => realm.name().to_string(), + None => String::new(), + } + }).await } fn list(&self) -> Vec { @@ -249,8 +253,12 @@ impl RealmsManagerServer { }); } - fn realm_from_citadel_pid(&self, pid: u32) -> RealmFromCitadelPid { - self.manager.realm_by_pid(pid).into() + async fn realm_from_citadel_pid(&self, pid: u32) -> RealmFromCitadelPid { + let manager = self.manager.clone(); + unblock(move || { + manager.realm_by_pid(pid).into() + + }).await } fn realm_config(&self, name: &str) -> RealmConfig { @@ -261,7 +269,7 @@ impl RealmsManagerServer { RealmConfig::new_from_realm(&realm) } - fn realm_set_config(&self, name: &str, vars: Vec<(String,String)>) { + async fn realm_set_config(&self, name: &str, vars: Vec<(String,String)>) { let realm = match self.manager.realm_by_name(name) { Some(r) => r, None => { @@ -270,8 +278,12 @@ impl RealmsManagerServer { }, }; - for var in &vars { - configure_realm(&self.manager, &realm, &var.0, &var.1); + for var in vars { + let manager = self.manager.clone(); + let realm = realm.clone(); + unblock( move || { + configure_realm(&manager, &realm, &var.0, &var.1); + }).await; } } @@ -279,13 +291,18 @@ impl RealmsManagerServer { Realm::is_valid_name(name) && self.manager.realm_by_name(name).is_some() } - fn create_realm(&self, name: &str) -> bool { - if let Err(err) = self.manager.new_realm(name) { - warn!("Error creating realm ({}): {}", name, err); - false - } else { - true - } + async fn create_realm(&self, name: &str) -> bool { + + let manager = self.manager.clone(); + let name = name.to_string(); + unblock(move || { + if let Err(err) = manager.new_realm(&name) { + warn!("Error creating realm ({}): {}", name, err); + false + } else { + true + } + }).await } fn list_realm_f_s(&self) -> Vec { @@ -299,23 +316,23 @@ impl RealmsManagerServer { } - #[dbus_interface(signal)] - pub fn realm_started(&self, realm: &str, pid_ns: u64, status: u8) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn realm_started(ctx: &SignalContext<'_>, realm: &str, pid_ns: u64, status: u8) -> zbus::Result<()>; - #[dbus_interface(signal)] - pub fn realm_stopped(&self, realm: &str, status: u8) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn realm_stopped(ctx: &SignalContext<'_>, realm: &str, status: u8) -> zbus::Result<()>; - #[dbus_interface(signal)] - pub fn realm_new(&self, realm: &str, description: &str, status: u8) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn realm_new(ctx: &SignalContext<'_>, realm: &str, description: &str, status: u8) -> zbus::Result<()>; - #[dbus_interface(signal)] - pub fn realm_removed(&self, realm: &str) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn realm_removed(ctx: &SignalContext<'_>, realm: &str) -> zbus::Result<()>; - #[dbus_interface(signal)] - pub fn realm_current(&self, realm: &str, status: u8) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn realm_current(ctx: &SignalContext<'_>, realm: &str, status: u8) -> zbus::Result<()>; - #[dbus_interface(signal)] - pub fn service_started(&self) -> zbus::Result<()> { Ok(()) } + #[zbus(signal)] + pub async fn service_started(ctx: &SignalContext<'_>) -> zbus::Result<()>; }