diff --git a/core/Cargo.lock b/core/Cargo.lock index 9965db378..d0b6f1426 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -440,7 +440,7 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ - "concurrent-queue 2.5.0", + "concurrent-queue", "event-listener 2.5.3", "futures-core", ] @@ -451,7 +451,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ - "concurrent-queue 2.5.0", + "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -478,7 +478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", - "concurrent-queue 2.5.0", + "concurrent-queue", "fastrand", "futures-lite", "pin-project-lite", @@ -508,7 +508,7 @@ checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ "autocfg", "cfg-if", - "concurrent-queue 2.5.0", + "concurrent-queue", "futures-io", "futures-lite", "parking", @@ -741,40 +741,13 @@ dependencies = [ "fs_extra", ] -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core 0.4.5", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "itoa", - "matchit 0.7.3", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" dependencies = [ - "axum-core 0.5.5", + "axum-core", "base64 0.22.1", "bytes", "form_urlencoded", @@ -785,7 +758,7 @@ dependencies = [ "hyper", "hyper-util", "itoa", - "matchit 0.8.4", + "matchit", "memchr", "mime", "percent-encoding", @@ -798,32 +771,12 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-tungstenite 0.28.0", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.5.5" @@ -843,23 +796,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-server" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1df331683d982a0b9492b38127151e6453639cd34926eb9c07d4cd8c6d22bfc" -dependencies = [ - "bytes", - "either", - "fs-err", - "http", - "http-body", - "hyper", - "hyper-util", - "tokio", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.76" @@ -895,17 +831,6 @@ dependencies = [ "nix 0.23.2", ] -[[package]] -name = "barrage" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5951c75bdabb58753d140dd5802f12ff3a483cb2e16fb5276e111b94b19e87" -dependencies = [ - "concurrent-queue 1.2.4", - "event-listener 2.5.3", - "spin", -] - [[package]] name = "base16ct" version = "0.2.0" @@ -1077,7 +1002,7 @@ checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" dependencies = [ "arrayref", "arrayvec 0.7.6", - "constant_time_eq", + "constant_time_eq 0.3.1", ] [[package]] @@ -1090,7 +1015,7 @@ dependencies = [ "arrayvec 0.7.6", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.3.1", "memmap2 0.9.9", "rayon-core", ] @@ -1224,12 +1149,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" -[[package]] -name = "cache-padded" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" - [[package]] name = "caret" version = "0.5.3" @@ -1492,15 +1411,6 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1512,35 +1422,36 @@ dependencies = [ [[package]] name = "console" -version = "0.15.11" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" dependencies = [ "encode_unicode", "libc", "once_cell", "unicode-width 0.2.2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "console-api" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8030735ecb0d128428b64cd379809817e620a40e5001c54465b99ec5feec2857" +checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3" dependencies = [ "futures-core", "prost", "prost-types", "tonic", + "tonic-prost", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6539aa9c6a4cd31f4b1c040f860a1eac9aa80e7df6b05d506a6e7179936d6a01" +checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592" dependencies = [ "console-api", "crossbeam-channel", @@ -1594,6 +1505,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "convert_case" version = "0.4.0" @@ -1638,24 +1555,6 @@ dependencies = [ "futures", ] -[[package]] -name = "cookie_store" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" -dependencies = [ - "cookie", - "document-features", - "idna", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - [[package]] name = "cookie_store" version = "0.22.0" @@ -2357,13 +2256,13 @@ dependencies = [ [[package]] name = "dns-lookup" -version = "2.1.1" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5597a4b7fe5275fc9dcf88ce26326bc8e4cb87d0130f33752d4c5f717793cf" +checksum = "6e39034cee21a2f5bbb66ba0e3689819c4bb5d00382a282006e802a7ffa6c41d" dependencies = [ "cfg-if", "libc", - "socket2 0.6.1", + "socket2", "windows-sys 0.60.2", ] @@ -2667,17 +2566,6 @@ dependencies = [ "visibility", ] -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - [[package]] name = "errno" version = "0.3.14" @@ -2688,16 +2576,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "etcetera" version = "0.8.0" @@ -2721,7 +2599,7 @@ version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ - "concurrent-queue 2.5.0", + "concurrent-queue", "parking", "pin-project-lite", ] @@ -2928,16 +2806,6 @@ dependencies = [ "itertools 0.8.2", ] -[[package]] -name = "fs-err" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824f08d01d0f496b3eca4f001a13cf17690a6ee930043d20817f547455fd98f8" -dependencies = [ - "autocfg", - "tokio", -] - [[package]] name = "fs-mistrust" version = "0.10.0" @@ -3420,23 +3288,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "helpers" -version = "0.1.0" -dependencies = [ - "color-eyre", - "futures", - "lazy_async_pool", - "models", - "pin-project", - "rpc-toolkit 0.3.2 (git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master)", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tracing", -] - [[package]] name = "hermit-abi" version = "0.5.2" @@ -3725,7 +3576,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2", "system-configuration", "tokio", "tower-service", @@ -3997,15 +3848,15 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.11" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" dependencies = [ "console", - "number_prefix", "portable-atomic", "tokio", "unicode-width 0.2.2", + "unit-prefix", "web-time", ] @@ -4446,7 +4297,7 @@ dependencies = [ "quoted_printable", "rustls 0.23.35", "rustls-platform-verifier", - "socket2 0.6.1", + "socket2", "tokio", "tokio-rustls 0.26.4", "url", @@ -4621,12 +4472,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "matchit" version = "0.8.4" @@ -4783,44 +4628,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "models" -version = "0.1.0" -dependencies = [ - "arti-client", - "axum 0.8.7", - "base64 0.22.1", - "color-eyre", - "ed25519-dalek 2.2.0", - "exver", - "gpt", - "hyper", - "ipnet", - "lazy_static", - "lettre", - "mbrman", - "miette", - "num_enum", - "openssl", - "patch-db", - "rand 0.9.2", - "regex", - "reqwest", - "rpc-toolkit 0.3.2 (git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master)", - "rustls 0.23.35", - "serde", - "serde_json", - "ssh-key", - "thiserror 2.0.17", - "tokio", - "torut", - "tracing", - "ts-rs", - "typeid", - "yasi", - "zbus", -] - [[package]] name = "moxcms" version = "0.7.11" @@ -5124,12 +4931,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "numtoa" version = "0.2.4" @@ -5489,7 +5290,7 @@ dependencies = [ "nix 0.30.1", "patch-db-macro", "serde", - "serde_cbor 0.11.1", + "serde_cbor", "thiserror 2.0.17", "tokio", "tracing", @@ -5812,7 +5613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", - "concurrent-queue 2.5.0", + "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix 1.1.2", @@ -5987,23 +5788,22 @@ dependencies = [ [[package]] name = "procfs" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" +checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" dependencies = [ "bitflags 2.10.0", "chrono", "flate2", - "hex", "procfs-core", - "rustix 0.38.44", + "rustix 1.1.2", ] [[package]] name = "procfs-core" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" +checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" dependencies = [ "bitflags 2.10.0", "chrono", @@ -6031,9 +5831,9 @@ dependencies = [ [[package]] name = "proptest-derive" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" +checksum = "fb6dc647500e84a25a85b100e76c85b8ace114c209432dc174f20aac11d4ed6c" dependencies = [ "proc-macro2", "quote", @@ -6042,9 +5842,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -6052,9 +5852,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools 0.14.0", @@ -6065,9 +5865,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ "prost", ] @@ -6165,7 +5965,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.35", - "socket2 0.6.1", + "socket2", "thiserror 2.0.17", "tokio", "tracing", @@ -6202,7 +6002,7 @@ dependencies = [ "cfg_aliases 0.2.1", "libc", "once_cell", - "socket2 0.6.1", + "socket2", "tracing", "windows-sys 0.60.2", ] @@ -6469,12 +6269,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.16" @@ -6588,7 +6382,7 @@ dependencies = [ "base64 0.22.1", "bytes", "cookie", - "cookie_store 0.22.0", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -6617,7 +6411,7 @@ dependencies = [ "tokio-native-tls", "tokio-rustls 0.26.4", "tokio-util", - "tower 0.5.2", + "tower", "tower-http", "tower-service", "url", @@ -6630,12 +6424,12 @@ dependencies = [ [[package]] name = "reqwest_cookie_store" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2314c325724fea278d44c13a525ebf60074e33c05f13b4345c076eb65b2446b3" +checksum = "5e75bc88d954b228850d19e3685cedb38c030a17da34aa01c307f95d6e33de34" dependencies = [ "bytes", - "cookie_store 0.21.1", + "cookie_store", "reqwest", "url", ] @@ -6680,36 +6474,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rpc-toolkit" -version = "0.3.2" -source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#2dd2832e043eb5380c91cf80f3e78a700d204be3" -dependencies = [ - "async-stream", - "async-trait", - "axum 0.8.7", - "clap", - "futures", - "http", - "http-body-util", - "imbl-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.14.0", - "lazy_format", - "lazy_static", - "openssl", - "pin-project", - "reqwest", - "serde", - "serde_cbor 0.11.2", - "serde_json", - "thiserror 2.0.17", - "tokio", - "tokio-stream", - "ts-rs", - "url", - "yajrc", -] - [[package]] name = "rpc-toolkit" version = "0.3.2" @@ -6717,7 +6481,7 @@ source = "git+https://github.com/Start9Labs/rpc-toolkit.git?rev=068db90#068db905 dependencies = [ "async-stream", "async-trait", - "axum 0.8.7", + "axum", "clap", "futures", "http", @@ -6786,13 +6550,14 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9848531d60c9cbbcf9d166c885316c24bc0e2a9d3eba0956bb6cbbd79bc6e8" +checksum = "8ae76b7506744d254fd0eb2c0ff5c5d108201ccbb083111ac04a44eeda105680" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "blake2b_simd", - "constant_time_eq", + "constant_time_eq 0.4.2", + "crossbeam-utils", ] [[package]] @@ -6832,7 +6597,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags 2.10.0", - "errno 0.3.14", + "errno", "libc", "linux-raw-sys 0.4.15", "windows-sys 0.59.0", @@ -6845,7 +6610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags 2.10.0", - "errno 0.3.14", + "errno", "libc", "linux-raw-sys 0.11.0", "windows-sys 0.61.2", @@ -7168,16 +6933,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half 1.8.3", - "serde", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -7511,17 +7266,6 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c11532d9d241904f095185f35dcdaf930b1427a94d5b01d7002d74ba19b44cc4" -[[package]] -name = "simple-logging" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00d48e85675326bb182a2286ea7c1a0b264333ae10f27a937a72be08628b542" -dependencies = [ - "lazy_static", - "log", - "thread-id", -] - [[package]] name = "siphasher" version = "1.0.1" @@ -7625,16 +7369,6 @@ dependencies = [ "wayland-client", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.1" @@ -7892,10 +7626,8 @@ dependencies = [ "async-compression", "async-stream", "async-trait", - "axum 0.8.7", - "axum-server", + "axum", "backtrace-on-stack-overflow", - "barrage", "base32 0.5.1", "base64 0.22.1", "base64ct", @@ -7910,7 +7642,7 @@ dependencies = [ "console-subscriber", "const_format", "cookie", - "cookie_store 0.21.1", + "cookie_store", "curve25519-dalek 4.1.3", "der", "digest 0.10.7", @@ -7924,7 +7656,6 @@ dependencies = [ "form_urlencoded", "futures", "gpt", - "helpers", "hex", "hickory-client", "hickory-server", @@ -7958,7 +7689,6 @@ dependencies = [ "mbrman", "miette", "mio", - "models", "new_mime_guess", "nix 0.30.1", "nom 8.0.0", @@ -7985,21 +7715,17 @@ dependencies = [ "reqwest", "reqwest_cookie_store", "rpassword", - "rpc-toolkit 0.3.2 (git+https://github.com/Start9Labs/rpc-toolkit.git?rev=068db90)", + "rpc-toolkit", "rust-argon2", "safelog", "semver", "serde", "serde_json", - "serde_urlencoded", - "serde_with", "serde_yml", "sha-crypt", "sha2 0.10.9", - "shell-words", "signal-hook", - "simple-logging", - "socket2 0.6.1", + "socket2", "socks5-impl", "sqlx", "sscanf", @@ -8014,7 +7740,7 @@ dependencies = [ "tokio-tar", "tokio-tungstenite 0.26.2", "tokio-util", - "toml 0.8.23", + "toml 0.9.9+spec-1.0.0", "tor-cell", "tor-hscrypto", "tor-hsservice", @@ -8026,19 +7752,15 @@ dependencies = [ "tower-service", "tracing", "tracing-error", - "tracing-futures", "tracing-journald", "tracing-subscriber", "ts-rs", "typed-builder", - "unix-named-pipe", "url", - "urlencoding", "uuid", "visit-rs", "x25519-dalek", "zbus", - "zeroize", ] [[package]] @@ -8367,17 +8089,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "thread-id" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" -dependencies = [ - "libc", - "redox_syscall 0.1.57", - "winapi", -] - [[package]] name = "thread_local" version = "1.1.9" @@ -8475,7 +8186,7 @@ dependencies = [ "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -8692,13 +8403,12 @@ checksum = "a9cd6190959dce0994aa8970cd32ab116d1851ead27e866039acaf2524ce44fa" [[package]] name = "tonic" -version = "0.12.3" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" dependencies = [ - "async-stream", "async-trait", - "axum 0.7.9", + "axum", "base64 0.22.1", "bytes", "h2", @@ -8710,16 +8420,27 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", - "socket2 0.5.10", + "socket2", + "sync_wrapper", "tokio", "tokio-stream", - "tower 0.4.13", + "tower", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tor-async-utils" version = "0.33.0" @@ -9715,26 +9436,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.2" @@ -9743,9 +9444,12 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap 2.12.1", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -9764,7 +9468,7 @@ dependencies = [ "http-body", "iri-string", "pin-project-lite", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", ] @@ -9836,16 +9540,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-journald" version = "0.3.2" @@ -9973,18 +9667,18 @@ dependencies = [ [[package]] name = "typed-builder" -version = "0.21.2" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.21.2" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" dependencies = [ "proc-macro2", "quote", @@ -10001,12 +9695,6 @@ dependencies = [ "serde", ] -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - [[package]] name = "typenum" version = "1.19.0" @@ -10109,14 +9797,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "unix-named-pipe" -version = "0.2.0" +name = "unit-prefix" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad653da8f36ac5825ba06642b5a3cce14a4e52c6a5fab4a8928d53f4426dae2" -dependencies = [ - "errno 0.2.8", - "libc", -] +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] name = "untrusted" @@ -10142,12 +9826,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf-8" version = "0.7.6" diff --git a/core/Cargo.toml b/core/Cargo.toml index 5b6823df2..f03252ecc 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["helpers", "models", "startos"] +members = ["startos"] diff --git a/core/build-cli.sh b/core/build-cli.sh index 02418978b..22bdb79e3 100755 --- a/core/build-cli.sh +++ b/core/build-cli.sh @@ -69,7 +69,7 @@ fi echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-zig-builder cargo zigbuild --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features=docker,$FEATURES --locked --bin start-cli --target=$TARGET +rust-zig-builder cargo zigbuild --manifest-path=./core/Cargo.toml $BUILD_FLAGS --features=$FEATURES --locked --bin start-cli --target=$TARGET if [ "$(ls -nd "core/target/$TARGET/$PROFILE/start-cli" | awk '{ print $3 }')" != "$UID" ]; then rust-zig-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /usr/local/cargo" fi diff --git a/core/helpers/Cargo.toml b/core/helpers/Cargo.toml deleted file mode 100644 index caf4b3eef..000000000 --- a/core/helpers/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "helpers" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -color-eyre = "0.6.2" -futures = "0.3.28" -lazy_async_pool = "0.3.3" -models = { path = "../models" } -pin-project = "1.1.3" -rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git", branch = "master" } -serde = { version = "1.0", features = ["derive", "rc"] } -serde_json = "1.0" -tokio = { version = "1", features = ["full"] } -tokio-stream = { version = "0.1.14", features = ["io-util", "sync"] } -tracing = "0.1.39" diff --git a/core/helpers/src/byte_replacement_reader.rs b/core/helpers/src/byte_replacement_reader.rs deleted file mode 100644 index d50c272ad..000000000 --- a/core/helpers/src/byte_replacement_reader.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::task::Poll; - -use tokio::io::{AsyncRead, ReadBuf}; - -#[pin_project::pin_project] -pub struct ByteReplacementReader { - pub replace: u8, - pub with: u8, - #[pin] - pub inner: R, -} -impl AsyncRead for ByteReplacementReader { - fn poll_read( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> std::task::Poll> { - let this = self.project(); - match this.inner.poll_read(cx, buf) { - Poll::Ready(Ok(())) => { - for idx in 0..buf.filled().len() { - if buf.filled()[idx] == *this.replace { - buf.filled_mut()[idx] = *this.with; - } - } - Poll::Ready(Ok(())) - } - a => a, - } - } -} diff --git a/core/helpers/src/lib.rs b/core/helpers/src/lib.rs deleted file mode 100644 index a9df58ece..000000000 --- a/core/helpers/src/lib.rs +++ /dev/null @@ -1,262 +0,0 @@ -use std::future::Future; -use std::ops::{Deref, DerefMut}; -use std::path::{Path, PathBuf}; -use std::time::Duration; - -use color_eyre::eyre::{eyre, Context, Error}; -use futures::future::BoxFuture; -use futures::FutureExt; -use models::ResultExt; -use tokio::fs::File; -use tokio::sync::oneshot; -use tokio::task::{JoinError, JoinHandle, LocalSet}; - -mod byte_replacement_reader; -mod rsync; -mod script_dir; -pub use byte_replacement_reader::*; -pub use rsync::*; -pub use script_dir::*; - -pub fn const_true() -> bool { - true -} - -pub fn to_tmp_path(path: impl AsRef) -> Result { - let path = path.as_ref(); - if let (Some(parent), Some(file_name)) = - (path.parent(), path.file_name().and_then(|f| f.to_str())) - { - Ok(parent.join(format!(".{}.tmp", file_name))) - } else { - Err(eyre!("invalid path: {}", path.display())) - } -} - -pub async fn canonicalize( - path: impl AsRef + Send + Sync, - create_parent: bool, -) -> Result { - fn create_canonical_folder<'a>( - path: impl AsRef + Send + Sync + 'a, - ) -> BoxFuture<'a, Result> { - async move { - let path = canonicalize(path, true).await?; - tokio::fs::create_dir(&path) - .await - .with_context(|| path.display().to_string())?; - Ok(path) - } - .boxed() - } - let path = path.as_ref(); - if tokio::fs::metadata(path).await.is_err() { - let parent = path.parent().unwrap_or(Path::new(".")); - if let Some(file_name) = path.file_name() { - if create_parent && tokio::fs::metadata(parent).await.is_err() { - return Ok(create_canonical_folder(parent).await?.join(file_name)); - } else { - return Ok(tokio::fs::canonicalize(parent) - .await - .with_context(|| parent.display().to_string())? - .join(file_name)); - } - } - } - tokio::fs::canonicalize(&path) - .await - .with_context(|| path.display().to_string()) -} - -#[pin_project::pin_project(PinnedDrop)] -pub struct NonDetachingJoinHandle(#[pin] JoinHandle); -impl NonDetachingJoinHandle { - pub async fn wait_for_abort(self) -> Result { - self.abort(); - self.await - } -} -impl From> for NonDetachingJoinHandle { - fn from(t: JoinHandle) -> Self { - NonDetachingJoinHandle(t) - } -} - -impl Deref for NonDetachingJoinHandle { - type Target = JoinHandle; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for NonDetachingJoinHandle { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -#[pin_project::pinned_drop] -impl PinnedDrop for NonDetachingJoinHandle { - fn drop(self: std::pin::Pin<&mut Self>) { - let this = self.project(); - this.0.into_ref().get_ref().abort() - } -} -impl Future for NonDetachingJoinHandle { - type Output = Result; - fn poll( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll { - let this = self.project(); - this.0.poll(cx) - } -} - -pub struct AtomicFile { - tmp_path: PathBuf, - path: PathBuf, - file: Option, -} -impl AtomicFile { - pub async fn new( - path: impl AsRef + Send + Sync, - tmp_path: Option + Send + Sync>, - ) -> Result { - let path = canonicalize(&path, true).await?; - let tmp_path = if let Some(tmp_path) = tmp_path { - canonicalize(&tmp_path, true).await? - } else { - to_tmp_path(&path)? - }; - let file = File::create(&tmp_path) - .await - .with_context(|| tmp_path.display().to_string())?; - Ok(Self { - tmp_path, - path, - file: Some(file), - }) - } - - pub async fn rollback(mut self) -> Result<(), Error> { - drop(self.file.take()); - tokio::fs::remove_file(&self.tmp_path) - .await - .with_context(|| format!("rm {}", self.tmp_path.display()))?; - Ok(()) - } - - pub async fn save(mut self) -> Result<(), Error> { - use tokio::io::AsyncWriteExt; - if let Some(file) = self.file.as_mut() { - file.flush().await?; - file.shutdown().await?; - file.sync_all().await?; - } - drop(self.file.take()); - tokio::fs::rename(&self.tmp_path, &self.path) - .await - .with_context(|| { - format!("mv {} -> {}", self.tmp_path.display(), self.path.display()) - })?; - Ok(()) - } -} -impl std::ops::Deref for AtomicFile { - type Target = File; - fn deref(&self) -> &Self::Target { - self.file.as_ref().unwrap() - } -} -impl std::ops::DerefMut for AtomicFile { - fn deref_mut(&mut self) -> &mut Self::Target { - self.file.as_mut().unwrap() - } -} -impl Drop for AtomicFile { - fn drop(&mut self) { - if let Some(file) = self.file.take() { - drop(file); - let path = std::mem::take(&mut self.tmp_path); - tokio::spawn(async move { tokio::fs::remove_file(path).await.log_err() }); - } - } -} - -pub struct TimedResource { - handle: NonDetachingJoinHandle>, - ready: oneshot::Sender<()>, -} -impl TimedResource { - pub fn new(resource: T, timer: Duration) -> Self { - let (send, recv) = oneshot::channel(); - let handle = tokio::spawn(async move { - tokio::select! { - _ = tokio::time::sleep(timer) => { - drop(resource); - None - }, - _ = recv => Some(resource), - } - }); - Self { - handle: handle.into(), - ready: send, - } - } - - pub fn new_with_destructor< - Fn: FnOnce(T) -> Fut + Send + 'static, - Fut: Future + Send, - >( - resource: T, - timer: Duration, - destructor: Fn, - ) -> Self { - let (send, recv) = oneshot::channel(); - let handle = tokio::spawn(async move { - tokio::select! { - _ = tokio::time::sleep(timer) => { - destructor(resource).await; - None - }, - _ = recv => Some(resource), - } - }); - Self { - handle: handle.into(), - ready: send, - } - } - - pub async fn get(self) -> Option { - let _ = self.ready.send(()); - self.handle.await.unwrap() - } - - pub fn is_timed_out(&self) -> bool { - self.ready.is_closed() - } -} - -pub async fn spawn_local< - T: 'static + Send, - F: FnOnce() -> Fut + Send + 'static, - Fut: Future + 'static, ->( - fut: F, -) -> NonDetachingJoinHandle { - let (send, recv) = tokio::sync::oneshot::channel(); - std::thread::spawn(move || { - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(async move { - let set = LocalSet::new(); - send.send(set.spawn_local(fut()).into()) - .unwrap_or_else(|_| unreachable!()); - set.await - }) - }); - recv.await.unwrap() -} diff --git a/core/helpers/src/os_api.rs b/core/helpers/src/os_api.rs deleted file mode 100644 index 1ade88a34..000000000 --- a/core/helpers/src/os_api.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::sync::Arc; - -use color_eyre::Report; -use models::InterfaceId; -use models::PackageId; -use serde_json::Value; -use tokio::sync::mpsc; - -pub struct RuntimeDropped; - -pub struct Callback { - id: Arc, - sender: mpsc::UnboundedSender<(Arc, Vec)>, -} -impl Callback { - pub fn new(id: String, sender: mpsc::UnboundedSender<(Arc, Vec)>) -> Self { - Self { - id: Arc::new(id), - sender, - } - } - pub fn is_listening(&self) -> bool { - self.sender.is_closed() - } - pub fn call(&self, args: Vec) -> Result<(), RuntimeDropped> { - self.sender - .send((self.id.clone(), args)) - .map_err(|_| RuntimeDropped) - } -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct AddressSchemaOnion { - pub id: InterfaceId, - pub external_port: u16, -} -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct AddressSchemaLocal { - pub id: InterfaceId, - pub external_port: u16, -} - -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct Address(pub String); -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct Domain; -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct Name; - -#[async_trait::async_trait] -#[allow(unused_variables)] -pub trait OsApi: Send + Sync + 'static { - async fn get_service_config( - &self, - id: PackageId, - path: &str, - callback: Option, - ) -> Result, Report>; - - async fn bind_local( - &self, - internal_port: u16, - address_schema: AddressSchemaLocal, - ) -> Result; - async fn bind_onion( - &self, - internal_port: u16, - address_schema: AddressSchemaOnion, - ) -> Result; - - async fn unbind_local(&self, id: InterfaceId, external: u16) -> Result<(), Report>; - async fn unbind_onion(&self, id: InterfaceId, external: u16) -> Result<(), Report>; - fn set_started(&self) -> Result<(), Report>; - async fn restart(&self) -> Result<(), Report>; - async fn start(&self) -> Result<(), Report>; - async fn stop(&self) -> Result<(), Report>; -} diff --git a/core/helpers/src/script_dir.rs b/core/helpers/src/script_dir.rs deleted file mode 100644 index 5cedd419f..000000000 --- a/core/helpers/src/script_dir.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::path::{Path, PathBuf}; - -use models::{PackageId, VersionString}; - -pub const PKG_SCRIPT_DIR: &str = "package-data/scripts"; - -pub fn script_dir>( - datadir: P, - pkg_id: &PackageId, - version: &VersionString, -) -> PathBuf { - datadir - .as_ref() - .join(&*PKG_SCRIPT_DIR) - .join(pkg_id) - .join(version.as_str()) -} diff --git a/core/models/Cargo.toml b/core/models/Cargo.toml deleted file mode 100644 index 1646af245..000000000 --- a/core/models/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -edition = "2021" -name = "models" -version = "0.1.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -arti = ["arti-client"] - -[dependencies] -arti-client = { version = "0.33", default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } -axum = "0.8.4" -base64 = "0.22.1" -color-eyre = "0.6.2" -ed25519-dalek = { version = "2.0.0", features = ["serde"] } -exver = { version = "0.2.0", git = "https://github.com/Start9Labs/exver-rs.git", features = [ - "serde", -] } -gpt = "4.1.0" -ipnet = "2.8.0" -lazy_static = "1.4" -lettre = { version = "0.11", default-features = false } -mbrman = "0.6.0" -miette = "7.6.0" -num_enum = "0.7.1" -openssl = { version = "0.10.57", features = ["vendored"] } -patch-db = { version = "*", path = "../../patch-db/patch-db", features = [ - "trace", -] } -rand = "0.9.1" -regex = "1.10.2" -reqwest = "0.12" -rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git", branch = "master" } -rustls = "0.23" -serde = { version = "1.0", features = ["derive", "rc"] } -serde_json = "1.0" -ssh-key = "0.6.2" -hyper = "1.8.1" -thiserror = "2.0" -tokio = { version = "1", features = ["full"] } -torut = "0.2.1" -tracing = "0.1.39" -ts-rs = "9" -typeid = "1" -yasi = { version = "0.1.6", features = ["serde", "ts-rs"] } -zbus = "5" diff --git a/core/models/bindings/ServiceInterfaceId.ts b/core/models/bindings/ServiceInterfaceId.ts deleted file mode 100644 index 55315ab60..000000000 --- a/core/models/bindings/ServiceInterfaceId.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. - -export type ServiceInterfaceId = string; diff --git a/core/models/src/errors.rs b/core/models/src/errors.rs deleted file mode 100644 index ab7eea954..000000000 --- a/core/models/src/errors.rs +++ /dev/null @@ -1,675 +0,0 @@ -use std::fmt::{Debug, Display}; - -use axum::http::uri::InvalidUri; -use axum::http::StatusCode; -use color_eyre::eyre::eyre; -use num_enum::TryFromPrimitive; -use patch_db::Revision; -use rpc_toolkit::reqwest; -use rpc_toolkit::yajrc::{ - RpcError, INVALID_PARAMS_ERROR, INVALID_REQUEST_ERROR, METHOD_NOT_FOUND_ERROR, PARSE_ERROR, -}; -use serde::{Deserialize, Serialize}; -use tokio::task::JoinHandle; -use ts_rs::TS; - -use crate::InvalidId; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)] -#[repr(i32)] -pub enum ErrorKind { - Unknown = 1, - Filesystem = 2, - Docker = 3, - ConfigSpecViolation = 4, - ConfigRulesViolation = 5, - NotFound = 6, - IncorrectPassword = 7, - VersionIncompatible = 8, - Network = 9, - Registry = 10, - Serialization = 11, - Deserialization = 12, - Utf8 = 13, - ParseVersion = 14, - IncorrectDisk = 15, - // Nginx = 16, - Dependency = 17, - ParseS9pk = 18, - ParseUrl = 19, - DiskNotAvailable = 20, - BlockDevice = 21, - InvalidOnionAddress = 22, - Pack = 23, - ValidateS9pk = 24, - DiskCorrupted = 25, // Remove - Tor = 26, - ConfigGen = 27, - ParseNumber = 28, - Database = 29, - InvalidId = 30, - InvalidSignature = 31, - Backup = 32, - Restore = 33, - Authorization = 34, - AutoConfigure = 35, - Action = 36, - RateLimited = 37, - InvalidRequest = 38, - MigrationFailed = 39, - Uninitialized = 40, - ParseNetAddress = 41, - ParseSshKey = 42, - SoundError = 43, - ParseTimestamp = 44, - ParseSysInfo = 45, - Wifi = 46, - Journald = 47, - DiskManagement = 48, - OpenSsl = 49, - PasswordHashGeneration = 50, - DiagnosticMode = 51, - ParseDbField = 52, - Duplicate = 53, - MultipleErrors = 54, - Incoherent = 55, - InvalidBackupTargetId = 56, - ProductKeyMismatch = 57, - LanPortConflict = 58, - Javascript = 59, - Pem = 60, - TLSInit = 61, - Ascii = 62, - MissingHeader = 63, - Grub = 64, - Systemd = 65, - OpenSsh = 66, - Zram = 67, - Lshw = 68, - CpuSettings = 69, - Firmware = 70, - Timeout = 71, - Lxc = 72, - Cancelled = 73, - Git = 74, - DBus = 75, - InstallFailed = 76, - UpdateFailed = 77, - Smtp = 78, -} -impl ErrorKind { - pub fn as_str(&self) -> &'static str { - use ErrorKind::*; - match self { - Unknown => "Unknown Error", - Filesystem => "Filesystem I/O Error", - Docker => "Docker Error", - ConfigSpecViolation => "Config Spec Violation", - ConfigRulesViolation => "Config Rules Violation", - NotFound => "Not Found", - IncorrectPassword => "Incorrect Password", - VersionIncompatible => "Version Incompatible", - Network => "Network Error", - Registry => "Registry Error", - Serialization => "Serialization Error", - Deserialization => "Deserialization Error", - Utf8 => "UTF-8 Parse Error", - ParseVersion => "Version Parsing Error", - IncorrectDisk => "Incorrect Disk", - // Nginx => "Nginx Error", - Dependency => "Dependency Error", - ParseS9pk => "S9PK Parsing Error", - ParseUrl => "URL Parsing Error", - DiskNotAvailable => "Disk Not Available", - BlockDevice => "Block Device Error", - InvalidOnionAddress => "Invalid Onion Address", - Pack => "Pack Error", - ValidateS9pk => "S9PK Validation Error", - DiskCorrupted => "Disk Corrupted", // Remove - Tor => "Tor Daemon Error", - ConfigGen => "Config Generation Error", - ParseNumber => "Number Parsing Error", - Database => "Database Error", - InvalidId => "Invalid ID", - InvalidSignature => "Invalid Signature", - Backup => "Backup Error", - Restore => "Restore Error", - Authorization => "Unauthorized", - AutoConfigure => "Auto-Configure Error", - Action => "Action Failed", - RateLimited => "Rate Limited", - InvalidRequest => "Invalid Request", - MigrationFailed => "Migration Failed", - Uninitialized => "Uninitialized", - ParseNetAddress => "Net Address Parsing Error", - ParseSshKey => "SSH Key Parsing Error", - SoundError => "Sound Interface Error", - ParseTimestamp => "Timestamp Parsing Error", - ParseSysInfo => "System Info Parsing Error", - Wifi => "WiFi Internal Error", - Journald => "Journald Error", - DiskManagement => "Disk Management Error", - OpenSsl => "OpenSSL Internal Error", - PasswordHashGeneration => "Password Hash Generation Error", - DiagnosticMode => "Server is in Diagnostic Mode", - ParseDbField => "Database Field Parse Error", - Duplicate => "Duplication Error", - MultipleErrors => "Multiple Errors", - Incoherent => "Incoherent", - InvalidBackupTargetId => "Invalid Backup Target ID", - ProductKeyMismatch => "Incompatible Product Keys", - LanPortConflict => "Incompatible LAN Port Configuration", - Javascript => "Javascript Engine Error", - Pem => "PEM Encoding Error", - TLSInit => "TLS Backend Initialization Error", - Ascii => "ASCII Parse Error", - MissingHeader => "Missing Header", - Grub => "Grub Error", - Systemd => "Systemd Error", - OpenSsh => "OpenSSH Error", - Zram => "Zram Error", - Lshw => "LSHW Error", - CpuSettings => "CPU Settings Error", - Firmware => "Firmware Error", - Timeout => "Timeout Error", - Lxc => "LXC Error", - Cancelled => "Cancelled", - Git => "Git Error", - DBus => "DBus Error", - InstallFailed => "Install Failed", - UpdateFailed => "Update Failed", - Smtp => "SMTP Error", - } - } -} -impl Display for ErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -pub struct Error { - pub source: color_eyre::eyre::Error, - pub debug: Option, - pub kind: ErrorKind, - pub revision: Option, - pub task: Option>, -} - -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {:#}", self.kind.as_str(), self.source) - } -} -impl Debug for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}: {:?}", - self.kind.as_str(), - self.debug.as_ref().unwrap_or(&self.source) - ) - } -} -impl Error { - pub fn new + std::fmt::Debug + 'static>( - source: E, - kind: ErrorKind, - ) -> Self { - let debug = (typeid::of::() == typeid::of::()) - .then(|| eyre!("{source:?}")); - Error { - source: source.into(), - debug, - kind, - revision: None, - task: None, - } - } - pub fn clone_output(&self) -> Self { - Error { - source: eyre!("{}", self.source), - debug: self.debug.as_ref().map(|e| eyre!("{e}")), - kind: self.kind, - revision: self.revision.clone(), - task: None, - } - } - pub fn with_task(mut self, task: JoinHandle<()>) -> Self { - self.task = Some(task); - self - } - pub async fn wait(mut self) -> Self { - if let Some(task) = &mut self.task { - task.await.log_err(); - } - self.task.take(); - self - } -} -impl axum::response::IntoResponse for Error { - fn into_response(self) -> axum::response::Response { - let mut res = axum::Json(RpcError::from(self)).into_response(); - *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - res - } -} -impl From for Error { - fn from(value: std::convert::Infallible) -> Self { - match value {} - } -} -impl From for Error { - fn from(err: InvalidId) -> Self { - Error::new(err, ErrorKind::InvalidId) - } -} -impl From for Error { - fn from(e: std::io::Error) -> Self { - Error::new(e, ErrorKind::Filesystem) - } -} -impl From for Error { - fn from(e: std::str::Utf8Error) -> Self { - Error::new(e, ErrorKind::Utf8) - } -} -impl From for Error { - fn from(e: std::string::FromUtf8Error) -> Self { - Error::new(e, ErrorKind::Utf8) - } -} -impl From for Error { - fn from(e: exver::ParseError) -> Self { - Error::new(e, ErrorKind::ParseVersion) - } -} -impl From for Error { - fn from(e: rpc_toolkit::url::ParseError) -> Self { - Error::new(e, ErrorKind::ParseUrl) - } -} -impl From for Error { - fn from(e: std::num::ParseIntError) -> Self { - Error::new(e, ErrorKind::ParseNumber) - } -} -impl From for Error { - fn from(e: std::num::ParseFloatError) -> Self { - Error::new(e, ErrorKind::ParseNumber) - } -} -impl From for Error { - fn from(e: patch_db::Error) -> Self { - Error::new(e, ErrorKind::Database) - } -} -impl From for Error { - fn from(e: ed25519_dalek::SignatureError) -> Self { - Error::new(e, ErrorKind::InvalidSignature) - } -} -impl From for Error { - fn from(e: std::net::AddrParseError) -> Self { - Error::new(e, ErrorKind::ParseNetAddress) - } -} -impl From for Error { - fn from(e: ipnet::AddrParseError) -> Self { - Error::new(e, ErrorKind::ParseNetAddress) - } -} -impl From for Error { - fn from(e: openssl::error::ErrorStack) -> Self { - Error::new(eyre!("{}", e), ErrorKind::OpenSsl) - } -} -impl From for Error { - fn from(e: mbrman::Error) -> Self { - Error::new(e, ErrorKind::DiskManagement) - } -} -impl From for Error { - fn from(e: gpt::GptError) -> Self { - Error::new(e, ErrorKind::DiskManagement) - } -} -impl From for Error { - fn from(e: gpt::mbr::MBRError) -> Self { - Error::new(e, ErrorKind::DiskManagement) - } -} -impl From for Error { - fn from(e: InvalidUri) -> Self { - Error::new(eyre!("{}", e), ErrorKind::ParseUrl) - } -} -impl From for Error { - fn from(e: ssh_key::Error) -> Self { - Error::new(e, ErrorKind::OpenSsh) - } -} -impl From for Error { - fn from(e: reqwest::Error) -> Self { - let kind = match e { - _ if e.is_builder() => ErrorKind::ParseUrl, - _ if e.is_decode() => ErrorKind::Deserialization, - _ => ErrorKind::Network, - }; - Error::new(e, kind) - } -} -#[cfg(feature = "arti")] -impl From for Error { - fn from(e: arti_client::Error) -> Self { - Error::new(e, ErrorKind::Tor) - } -} -impl From for Error { - fn from(e: torut::control::ConnError) -> Self { - Error::new(e, ErrorKind::Tor) - } -} -impl From for Error { - fn from(e: zbus::Error) -> Self { - Error::new(e, ErrorKind::DBus) - } -} -impl From for Error { - fn from(e: rustls::Error) -> Self { - Error::new(e, ErrorKind::OpenSsl) - } -} -impl From for Error { - fn from(e: lettre::error::Error) -> Self { - Error::new(e, ErrorKind::Smtp) - } -} -impl From for Error { - fn from(e: lettre::transport::smtp::Error) -> Self { - Error::new(e, ErrorKind::Smtp) - } -} -impl From for Error { - fn from(e: lettre::address::AddressError) -> Self { - Error::new(e, ErrorKind::Smtp) - } -} -impl From for Error { - fn from(e: hyper::Error) -> Self { - Error::new(e, ErrorKind::Network) - } -} -impl From for Error { - fn from(value: patch_db::value::Error) -> Self { - match value.kind { - patch_db::value::ErrorKind::Serialization => { - Error::new(value.source, ErrorKind::Serialization) - } - patch_db::value::ErrorKind::Deserialization => { - Error::new(value.source, ErrorKind::Deserialization) - } - } - } -} - -#[derive(Clone, Deserialize, Serialize, TS)] -pub struct ErrorData { - pub details: String, - pub debug: String, -} -impl Display for ErrorData { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(&self.details, f) - } -} -impl Debug for ErrorData { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(&self.debug, f) - } -} -impl std::error::Error for ErrorData {} -impl From for ErrorData { - fn from(value: Error) -> Self { - Self { - details: value.to_string(), - debug: format!("{:?}", value), - } - } -} -impl From<&RpcError> for ErrorData { - fn from(value: &RpcError) -> Self { - Self { - details: value - .data - .as_ref() - .and_then(|d| { - d.as_object() - .and_then(|d| { - d.get("details") - .and_then(|d| d.as_str().map(|s| s.to_owned())) - }) - .or_else(|| d.as_str().map(|s| s.to_owned())) - }) - .unwrap_or_else(|| value.message.clone().into_owned()), - debug: value - .data - .as_ref() - .and_then(|d| { - d.as_object() - .and_then(|d| { - d.get("debug") - .and_then(|d| d.as_str().map(|s| s.to_owned())) - }) - .or_else(|| d.as_str().map(|s| s.to_owned())) - }) - .unwrap_or_else(|| value.message.clone().into_owned()), - } - } -} - -impl From for RpcError { - fn from(e: Error) -> Self { - let mut data_object = serde_json::Map::with_capacity(3); - data_object.insert("details".to_owned(), format!("{}", e.source).into()); - data_object.insert("debug".to_owned(), format!("{:?}", e.source).into()); - data_object.insert( - "revision".to_owned(), - match serde_json::to_value(&e.revision) { - Ok(a) => a, - Err(e) => { - tracing::warn!("Error serializing revision for Error object: {}", e); - serde_json::Value::Null - } - }, - ); - RpcError { - code: e.kind as i32, - message: e.kind.as_str().into(), - data: Some( - match serde_json::to_value(&ErrorData { - details: format!("{}", e.source), - debug: format!("{:?}", e.source), - }) { - Ok(a) => a, - Err(e) => { - tracing::warn!("Error serializing revision for Error object: {}", e); - serde_json::Value::Null - } - }, - ), - } - } -} -impl From for Error { - fn from(e: RpcError) -> Self { - Error::new( - ErrorData::from(&e), - if let Ok(kind) = e.code.try_into() { - kind - } else if e.code == METHOD_NOT_FOUND_ERROR.code { - ErrorKind::NotFound - } else if e.code == PARSE_ERROR.code - || e.code == INVALID_PARAMS_ERROR.code - || e.code == INVALID_REQUEST_ERROR.code - { - ErrorKind::Deserialization - } else { - ErrorKind::Unknown - }, - ) - } -} - -#[derive(Debug, Default)] -pub struct ErrorCollection(Vec); -impl ErrorCollection { - pub fn new() -> Self { - Self::default() - } - - pub fn handle>(&mut self, result: Result) -> Option { - match result { - Ok(a) => Some(a), - Err(e) => { - self.0.push(e.into()); - None - } - } - } - - pub fn into_result(self) -> Result<(), Error> { - if self.0.is_empty() { - Ok(()) - } else { - Err(Error::new(eyre!("{}", self), ErrorKind::MultipleErrors)) - } - } -} -impl From for Result<(), Error> { - fn from(e: ErrorCollection) -> Self { - e.into_result() - } -} -impl> Extend> for ErrorCollection { - fn extend>>(&mut self, iter: I) { - for item in iter { - self.handle(item); - } - } -} -impl std::fmt::Display for ErrorCollection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (idx, e) in self.0.iter().enumerate() { - if idx > 0 { - write!(f, "; ")?; - } - write!(f, "{}", e)?; - } - Ok(()) - } -} - -pub trait ResultExt -where - Self: Sized, -{ - fn with_kind(self, kind: ErrorKind) -> Result; - fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result; - fn log_err(self) -> Option; -} -impl ResultExt for Result -where - color_eyre::eyre::Error: From, - E: std::fmt::Debug + 'static, -{ - fn with_kind(self, kind: ErrorKind) -> Result { - self.map_err(|e| Error::new(e, kind)) - } - - fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result { - self.map_err(|e| { - let (kind, ctx) = f(&e); - let debug = (typeid::of::() == typeid::of::()) - .then(|| eyre!("{ctx}: {e:?}")); - let source = color_eyre::eyre::Error::from(e); - let with_ctx = format!("{ctx}: {source}"); - let source = source.wrap_err(with_ctx); - Error { - kind, - source, - debug, - revision: None, - task: None, - } - }) - } - - fn log_err(self) -> Option { - match self { - Ok(a) => Some(a), - Err(e) => { - let e: color_eyre::eyre::Error = e.into(); - tracing::error!("{e}"); - tracing::debug!("{e:?}"); - None - } - } - } -} -impl ResultExt for Result { - fn with_kind(self, kind: ErrorKind) -> Result { - self.map_err(|e| Error { kind, ..e }) - } - - fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result { - self.map_err(|e| { - let (kind, ctx) = f(&e); - let source = e.source; - let with_ctx = format!("{ctx}: {source}"); - let source = source.wrap_err(with_ctx); - let debug = e.debug.map(|e| { - let with_ctx = format!("{ctx}: {e}"); - e.wrap_err(with_ctx) - }); - Error { - kind, - source, - debug, - ..e - } - }) - } - - fn log_err(self) -> Option { - match self { - Ok(a) => Some(a), - Err(e) => { - tracing::error!("{e}"); - tracing::debug!("{e:?}"); - None - } - } - } -} - -pub trait OptionExt -where - Self: Sized, -{ - fn or_not_found(self, message: impl std::fmt::Display) -> Result; -} -impl OptionExt for Option { - fn or_not_found(self, message: impl std::fmt::Display) -> Result { - self.ok_or_else(|| Error::new(eyre!("{}", message), ErrorKind::NotFound)) - } -} - -#[macro_export] -macro_rules! ensure_code { - ($x:expr, $c:expr, $fmt:expr $(, $arg:expr)*) => { - if !($x) { - return Err(Error::new(color_eyre::eyre::eyre!($fmt, $($arg, )*), $c)); - } - }; -} diff --git a/core/models/src/lib.rs b/core/models/src/lib.rs deleted file mode 100644 index 304ac87c5..000000000 --- a/core/models/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod clap; -mod data_url; -mod errors; -mod id; -mod mime; -mod procedure_name; -mod version; - -pub use clap::*; -pub use data_url::*; -pub use errors::*; -pub use id::*; -pub use mime::*; -pub use procedure_name::*; -pub use version::*; diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index a1cc8eee7..b5cc4120d 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -44,7 +44,6 @@ path = "src/main/tunnelbox.rs" [features] arti = [ "arti-client", - "models/arti", "safelog", "tor-cell", "tor-hscrypto", @@ -55,9 +54,8 @@ arti = [ "tor-rtcompat", ] console = ["console-subscriber", "tokio/tracing"] -default = ["procfs", "pty-process"] -dev = ["backtrace-on-stack-overflow"] -docker = [] +default = [] +dev = [] test = [] unstable = ["backtrace-on-stack-overflow"] @@ -86,9 +84,7 @@ async-compression = { version = "0.4.32", features = [ async-stream = "0.3.5" async-trait = "0.1.74" axum = { version = "0.8.4", features = ["ws", "http2"] } -axum-server = "0.8.0" backtrace-on-stack-overflow = { version = "0.3.0", optional = true } -barrage = "0.2.3" base32 = "0.5.0" base64 = "0.22.1" base64ct = "1.6.0" @@ -98,16 +94,16 @@ bytes = "1" chrono = { version = "0.4.31", features = ["serde"] } clap = { version = "4.4.12", features = ["string"] } color-eyre = "0.6.2" -console = "0.15.7" -console-subscriber = { version = "0.4.1", optional = true } +console = "0.16.2" +console-subscriber = { version = "0.5.0", optional = true } const_format = "0.2.34" cookie = "0.18.0" -cookie_store = "0.21.0" +cookie_store = "0.22.0" curve25519-dalek = "4.1.3" der = { version = "0.7.9", features = ["derive", "pem"] } digest = "0.10.7" divrem = "1.0.0" -dns-lookup = "2.1.0" +dns-lookup = "3.0.1" ed25519 = { version = "2.2.3", features = ["alloc", "pem", "pkcs8"] } ed25519-dalek = { version = "2.2.0", features = [ "digest", @@ -125,7 +121,6 @@ fd-lock-rs = "0.1.4" form_urlencoded = "1.2.1" futures = "0.3.28" gpt = "4.1.0" -helpers = { path = "../helpers" } hex = "0.4.3" hickory-client = "0.25.2" hickory-server = "0.25.2" @@ -151,7 +146,7 @@ imbl = { version = "6", features = ["serde", "small-chunks"] } imbl-value = { version = "0.4.3", features = ["ts-rs"] } include_dir = { version = "0.7.3", features = ["metadata"] } indexmap = { version = "2.0.2", features = ["serde"] } -indicatif = { version = "0.17.7", features = ["tokio"] } +indicatif = { version = "0.18.3", features = ["tokio"] } inotify = "0.11.0" integer-encoding = { version = "4.0.0", features = ["tokio_async"] } ipnet = { version = "2.8.0", features = ["serde"] } @@ -178,7 +173,6 @@ log = "0.4.20" mbrman = "0.6.0" miette = { version = "7.6.0", features = ["fancy"] } mio = "1" -models = { version = "*", path = "../models" } new_mime_guess = "4" nix = { version = "0.30.1", features = [ "fs", @@ -204,10 +198,8 @@ pbkdf2 = "0.12.2" pin-project = "1.1.3" pkcs8 = { version = "0.10.2", features = ["std"] } prettytable-rs = "0.10.0" -procfs = { version = "0.17.0", optional = true } proptest = "1.3.1" -proptest-derive = "0.5.0" -pty-process = { version = "0.5.1", optional = true } +proptest-derive = "0.7.0" qrcode = "0.14.1" r3bl_tui = "0.7.6" rand = "0.9.2" @@ -218,24 +210,20 @@ reqwest = { version = "0.12.25", features = [ "stream", "http2", ] } -reqwest_cookie_store = "0.8.0" +reqwest_cookie_store = "0.9.0" rpassword = "7.2.0" rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git", rev = "068db90" } -rust-argon2 = "2.0.0" +rust-argon2 = "3.0.0" safelog = { version = "0.4.8", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } semver = { version = "1.0.20", features = ["serde"] } serde = { version = "1.0", features = ["derive", "rc"] } serde_cbor = { package = "ciborium", version = "0.2.1" } serde_json = "1.0" -serde_toml = { package = "toml", version = "0.8.2" } -serde_urlencoded = "0.7" -serde_with = { version = "3.4.0", features = ["json", "macros"] } +serde_toml = { package = "toml", version = "0.9.9+spec-1.0.0" } serde_yaml = { package = "serde_yml", version = "0.0.12" } sha-crypt = "0.5.0" sha2 = "0.10.2" -shell-words = "1" signal-hook = "0.3.17" -simple-logging = "2.0.2" socket2 = { version = "0.6.0", features = ["all"] } socks5-impl = { version = "0.7.2", features = ["client", "server"] } sqlx = { version = "0.8.6", features = [ @@ -274,19 +262,19 @@ torut = "0.2.1" tower-service = "0.3.3" tracing = "0.1.39" tracing-error = "0.2.0" -tracing-futures = "0.2.5" tracing-journald = "0.3.0" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } ts-rs = "9.0.1" -typed-builder = "0.21.0" -unix-named-pipe = "0.2.0" +typed-builder = "0.23.2" url = { version = "2.4.1", features = ["serde"] } -urlencoding = "2.1.3" uuid = { version = "1.4.1", features = ["v4"] } visit-rs = "0.1.1" x25519-dalek = { version = "2.0.1", features = ["static_secrets"] } zbus = "5.1.1" -zeroize = "1.6.0" + +[target.'cfg(target_os = "linux")'.dependencies] +procfs = "0.18.0" +pty-process = "0.5.1" [profile.test] opt-level = 3 diff --git a/core/startos/src/action.rs b/core/startos/src/action.rs index aac044bb9..d9b5ba2d8 100644 --- a/core/startos/src/action.rs +++ b/core/startos/src/action.rs @@ -1,8 +1,8 @@ use std::fmt; use clap::{CommandFactory, FromArgMatches, Parser}; -pub use models::ActionId; -use models::{PackageId, ReplayId}; +pub use crate::ActionId; +use crate::{PackageId, ReplayId}; use qrcode::QrCode; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/backup/backup_bulk.rs b/core/startos/src/backup/backup_bulk.rs index 1a57319fd..b2795e0a4 100644 --- a/core/startos/src/backup/backup_bulk.rs +++ b/core/startos/src/backup/backup_bulk.rs @@ -5,9 +5,8 @@ use std::sync::Arc; use chrono::Utc; use clap::Parser; use color_eyre::eyre::eyre; -use helpers::AtomicFile; use imbl::OrdSet; -use models::PackageId; +use crate::PackageId; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; use tracing::instrument; @@ -26,7 +25,7 @@ use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard}; use crate::middleware::auth::AuthContext; use crate::notifications::{NotificationLevel, notify}; use crate::prelude::*; -use crate::util::io::dir_copy; +use crate::util::io::{AtomicFile, dir_copy}; use crate::util::serde::IoFormat; use crate::version::VersionT; @@ -312,19 +311,14 @@ async fn perform_backup( let ui = ctx.db.peek().await.into_public().into_ui().de()?; let mut os_backup_file = - AtomicFile::new(backup_guard.path().join("os-backup.json"), None::) - .await - .with_kind(ErrorKind::Filesystem)?; + AtomicFile::new(backup_guard.path().join("os-backup.json"), None::).await?; os_backup_file .write_all(&IoFormat::Json.to_vec(&OsBackup { account: ctx.account.peek(|a| a.clone()), ui, })?) .await?; - os_backup_file - .save() - .await - .with_kind(ErrorKind::Filesystem)?; + os_backup_file.save().await?; let luks_folder_old = backup_guard.path().join("luks.old"); if tokio::fs::metadata(&luks_folder_old).await.is_ok() { diff --git a/core/startos/src/backup/mod.rs b/core/startos/src/backup/mod.rs index 697c81576..3ca0b583c 100644 --- a/core/startos/src/backup/mod.rs +++ b/core/startos/src/backup/mod.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use models::PackageId; +use crate::PackageId; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/backup/restore.rs b/core/startos/src/backup/restore.rs index d8d536aea..f06e86d45 100644 --- a/core/startos/src/backup/restore.rs +++ b/core/startos/src/backup/restore.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use clap::Parser; use futures::{StreamExt, stream}; -use models::PackageId; +use crate::PackageId; use patch_db::json_ptr::ROOT; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; diff --git a/core/startos/src/backup/target/mod.rs b/core/startos/src/backup/target/mod.rs index f6373542d..eaeee2e7a 100644 --- a/core/startos/src/backup/target/mod.rs +++ b/core/startos/src/backup/target/mod.rs @@ -9,7 +9,8 @@ use digest::OutputSizeUser; use digest::generic_array::GenericArray; use exver::Version; use imbl_value::InternedString; -use models::{FromStrParser, PackageId}; +use crate::util::FromStrParser; +use crate::PackageId; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use sha2::Sha256; diff --git a/core/startos/src/bins/tunnel.rs b/core/startos/src/bins/tunnel.rs index 66921c28f..0687493ac 100644 --- a/core/startos/src/bins/tunnel.rs +++ b/core/startos/src/bins/tunnel.rs @@ -5,7 +5,7 @@ use std::time::Duration; use clap::Parser; use futures::FutureExt; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use rpc_toolkit::CliApp; use tokio::signal::unix::signal; use tracing::instrument; diff --git a/core/startos/src/config/hook.rs b/core/startos/src/config/hook.rs index 4738a54f0..d22896945 100644 --- a/core/startos/src/config/hook.rs +++ b/core/startos/src/config/hook.rs @@ -1,7 +1,7 @@ use helpers::Callback; use itertools::Itertools; use jsonpath_lib::Compiled; -use models::PackageId; +use crate::PackageId; use serde_json::Value; use crate::context::RpcContext; diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index 6dda9fc7e..4095a9e6c 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -8,12 +8,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; use chrono::{TimeDelta, Utc}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::OrdMap; use imbl_value::InternedString; use itertools::Itertools; use josekit::jwk::Jwk; -use models::{ActionId, PackageId}; +use crate::{ActionId, PackageId}; use reqwest::{Client, Proxy}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{CallRemote, Context, Empty}; diff --git a/core/startos/src/context/setup.rs b/core/startos/src/context/setup.rs index a00b092ed..3c65eeedc 100644 --- a/core/startos/src/context/setup.rs +++ b/core/startos/src/context/setup.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::time::Duration; use futures::{Future, StreamExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl_value::InternedString; use josekit::jwk::Jwk; use patch_db::PatchDb; diff --git a/core/startos/src/control.rs b/core/startos/src/control.rs index d7ad123fa..fe4a3bd30 100644 --- a/core/startos/src/control.rs +++ b/core/startos/src/control.rs @@ -1,5 +1,5 @@ use clap::Parser; -use models::PackageId; +use crate::PackageId; use serde::{Deserialize, Serialize}; use tracing::instrument; use ts_rs::TS; diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index 9cebae9bf..073a30e14 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -4,7 +4,8 @@ use std::path::PathBuf; use chrono::{DateTime, Utc}; use exver::VersionRange; use imbl_value::InternedString; -use models::{ActionId, DataUrl, HealthCheckId, HostId, PackageId, ReplayId, ServiceInterfaceId}; +use crate::util::DataUrl; +use crate::{ActionId, HealthCheckId, HostId, PackageId, ReplayId, ServiceInterfaceId}; use patch_db::HasModel; use patch_db::json_ptr::JsonPointer; use reqwest::Url; diff --git a/core/startos/src/db/model/private.rs b/core/startos/src/db/model/private.rs index 47de5093a..6e7e8fb03 100644 --- a/core/startos/src/db/model/private.rs +++ b/core/startos/src/db/model/private.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, HashSet}; -use models::PackageId; +use crate::PackageId; use patch_db::{HasModel, Value}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index 46b25f389..dfc104101 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -9,7 +9,7 @@ use imbl_value::InternedString; use ipnet::IpNet; use isocountry::CountryCode; use itertools::Itertools; -use models::{GatewayId, PackageId}; +use crate::{GatewayId, PackageId}; use openssl::hash::MessageDigest; use patch_db::{HasModel, Value}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/dependencies.rs b/core/startos/src/dependencies.rs index 375b6c67d..f322a298e 100644 --- a/core/startos/src/dependencies.rs +++ b/core/startos/src/dependencies.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::path::Path; use imbl_value::InternedString; -use models::PackageId; +use crate::PackageId; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/disk/mount/backup.rs b/core/startos/src/disk/mount/backup.rs index 5fadba407..d79e303f3 100644 --- a/core/startos/src/disk/mount/backup.rs +++ b/core/startos/src/disk/mount/backup.rs @@ -2,8 +2,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use color_eyre::eyre::eyre; -use helpers::AtomicFile; -use models::PackageId; +use crate::PackageId; use tokio::io::AsyncWriteExt; use tracing::instrument; @@ -14,9 +13,10 @@ use crate::disk::mount::filesystem::ReadWrite; use crate::disk::mount::filesystem::backupfs::BackupFS; use crate::disk::mount::guard::SubPath; use crate::disk::util::StartOsRecoveryInfo; +use crate::prelude::*; use crate::util::crypto::{decrypt_slice, encrypt_slice}; +use crate::util::io::AtomicFile; use crate::util::serde::IoFormat; -use crate::{Error, ErrorKind, ResultExt}; #[derive(Clone, Debug)] pub struct BackupMountGuard { @@ -184,18 +184,14 @@ impl BackupMountGuard { #[instrument(skip_all)] pub async fn save(&self) -> Result<(), Error> { let metadata_path = self.path().join("metadata.json"); - let mut file = AtomicFile::new(&metadata_path, None::) - .await - .with_kind(ErrorKind::Filesystem)?; + let mut file = AtomicFile::new(&metadata_path, None::).await?; file.write_all(&IoFormat::Json.to_vec(&self.metadata)?) .await?; - file.save().await.with_kind(ErrorKind::Filesystem)?; - let mut file = AtomicFile::new(&self.unencrypted_metadata_path, None::) - .await - .with_kind(ErrorKind::Filesystem)?; + file.save().await?; + let mut file = AtomicFile::new(&self.unencrypted_metadata_path, None::).await?; file.write_all(&IoFormat::Json.to_vec(&self.unencrypted_metadata)?) .await?; - file.save().await.with_kind(ErrorKind::Filesystem)?; + file.save().await?; Ok(()) } diff --git a/core/startos/src/disk/mount/filesystem/idmapped.rs b/core/startos/src/disk/mount/filesystem/idmapped.rs index 7b0dbd77c..3e92351b7 100644 --- a/core/startos/src/disk/mount/filesystem/idmapped.rs +++ b/core/startos/src/disk/mount/filesystem/idmapped.rs @@ -8,7 +8,7 @@ use clap::Parser; use clap::builder::ValueParserFactory; use digest::generic_array::GenericArray; use digest::{Digest, OutputSizeUser}; -use models::FromStrParser; +use crate::util::FromStrParser; use serde::{Deserialize, Serialize}; use sha2::Sha256; use tokio::process::Command; diff --git a/core/startos/src/disk/mount/guard.rs b/core/startos/src/disk/mount/guard.rs index 980e4daa5..e806b4150 100644 --- a/core/startos/src/disk/mount/guard.rs +++ b/core/startos/src/disk/mount/guard.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, Weak}; use futures::Future; use lazy_static::lazy_static; -use models::ResultExt; +use crate::ResultExt; use tokio::sync::Mutex; use tracing::instrument; diff --git a/core/startos/src/error.rs b/core/startos/src/error.rs index a0ca5707c..279ba1e6b 100644 --- a/core/startos/src/error.rs +++ b/core/startos/src/error.rs @@ -1,4 +1,526 @@ -pub use models::{Error, ErrorKind, OptionExt, ResultExt}; +use std::fmt::{Debug, Display}; + +use axum::http::StatusCode; +use tokio_rustls::rustls; +use axum::http::uri::InvalidUri; +use color_eyre::eyre::eyre; +use num_enum::TryFromPrimitive; +use patch_db::Revision; +use rpc_toolkit::reqwest; +use rpc_toolkit::yajrc::{ + INVALID_PARAMS_ERROR, INVALID_REQUEST_ERROR, METHOD_NOT_FOUND_ERROR, PARSE_ERROR, RpcError, +}; +use serde::{Deserialize, Serialize}; +use tokio::task::JoinHandle; +use ts_rs::TS; + +use crate::InvalidId; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)] +#[repr(i32)] +pub enum ErrorKind { + Unknown = 1, + Filesystem = 2, + Docker = 3, + ConfigSpecViolation = 4, + ConfigRulesViolation = 5, + NotFound = 6, + IncorrectPassword = 7, + VersionIncompatible = 8, + Network = 9, + Registry = 10, + Serialization = 11, + Deserialization = 12, + Utf8 = 13, + ParseVersion = 14, + IncorrectDisk = 15, + // Nginx = 16, + Dependency = 17, + ParseS9pk = 18, + ParseUrl = 19, + DiskNotAvailable = 20, + BlockDevice = 21, + InvalidOnionAddress = 22, + Pack = 23, + ValidateS9pk = 24, + DiskCorrupted = 25, // Remove + Tor = 26, + ConfigGen = 27, + ParseNumber = 28, + Database = 29, + InvalidId = 30, + InvalidSignature = 31, + Backup = 32, + Restore = 33, + Authorization = 34, + AutoConfigure = 35, + Action = 36, + RateLimited = 37, + InvalidRequest = 38, + MigrationFailed = 39, + Uninitialized = 40, + ParseNetAddress = 41, + ParseSshKey = 42, + SoundError = 43, + ParseTimestamp = 44, + ParseSysInfo = 45, + Wifi = 46, + Journald = 47, + DiskManagement = 48, + OpenSsl = 49, + PasswordHashGeneration = 50, + DiagnosticMode = 51, + ParseDbField = 52, + Duplicate = 53, + MultipleErrors = 54, + Incoherent = 55, + InvalidBackupTargetId = 56, + ProductKeyMismatch = 57, + LanPortConflict = 58, + Javascript = 59, + Pem = 60, + TLSInit = 61, + Ascii = 62, + MissingHeader = 63, + Grub = 64, + Systemd = 65, + OpenSsh = 66, + Zram = 67, + Lshw = 68, + CpuSettings = 69, + Firmware = 70, + Timeout = 71, + Lxc = 72, + Cancelled = 73, + Git = 74, + DBus = 75, + InstallFailed = 76, + UpdateFailed = 77, + Smtp = 78, +} +impl ErrorKind { + pub fn as_str(&self) -> &'static str { + use ErrorKind::*; + match self { + Unknown => "Unknown Error", + Filesystem => "Filesystem I/O Error", + Docker => "Docker Error", + ConfigSpecViolation => "Config Spec Violation", + ConfigRulesViolation => "Config Rules Violation", + NotFound => "Not Found", + IncorrectPassword => "Incorrect Password", + VersionIncompatible => "Version Incompatible", + Network => "Network Error", + Registry => "Registry Error", + Serialization => "Serialization Error", + Deserialization => "Deserialization Error", + Utf8 => "UTF-8 Parse Error", + ParseVersion => "Version Parsing Error", + IncorrectDisk => "Incorrect Disk", + // Nginx => "Nginx Error", + Dependency => "Dependency Error", + ParseS9pk => "S9PK Parsing Error", + ParseUrl => "URL Parsing Error", + DiskNotAvailable => "Disk Not Available", + BlockDevice => "Block Device Error", + InvalidOnionAddress => "Invalid Onion Address", + Pack => "Pack Error", + ValidateS9pk => "S9PK Validation Error", + DiskCorrupted => "Disk Corrupted", // Remove + Tor => "Tor Daemon Error", + ConfigGen => "Config Generation Error", + ParseNumber => "Number Parsing Error", + Database => "Database Error", + InvalidId => "Invalid ID", + InvalidSignature => "Invalid Signature", + Backup => "Backup Error", + Restore => "Restore Error", + Authorization => "Unauthorized", + AutoConfigure => "Auto-Configure Error", + Action => "Action Failed", + RateLimited => "Rate Limited", + InvalidRequest => "Invalid Request", + MigrationFailed => "Migration Failed", + Uninitialized => "Uninitialized", + ParseNetAddress => "Net Address Parsing Error", + ParseSshKey => "SSH Key Parsing Error", + SoundError => "Sound Interface Error", + ParseTimestamp => "Timestamp Parsing Error", + ParseSysInfo => "System Info Parsing Error", + Wifi => "WiFi Internal Error", + Journald => "Journald Error", + DiskManagement => "Disk Management Error", + OpenSsl => "OpenSSL Internal Error", + PasswordHashGeneration => "Password Hash Generation Error", + DiagnosticMode => "Server is in Diagnostic Mode", + ParseDbField => "Database Field Parse Error", + Duplicate => "Duplication Error", + MultipleErrors => "Multiple Errors", + Incoherent => "Incoherent", + InvalidBackupTargetId => "Invalid Backup Target ID", + ProductKeyMismatch => "Incompatible Product Keys", + LanPortConflict => "Incompatible LAN Port Configuration", + Javascript => "Javascript Engine Error", + Pem => "PEM Encoding Error", + TLSInit => "TLS Backend Initialization Error", + Ascii => "ASCII Parse Error", + MissingHeader => "Missing Header", + Grub => "Grub Error", + Systemd => "Systemd Error", + OpenSsh => "OpenSSH Error", + Zram => "Zram Error", + Lshw => "LSHW Error", + CpuSettings => "CPU Settings Error", + Firmware => "Firmware Error", + Timeout => "Timeout Error", + Lxc => "LXC Error", + Cancelled => "Cancelled", + Git => "Git Error", + DBus => "DBus Error", + InstallFailed => "Install Failed", + UpdateFailed => "Update Failed", + Smtp => "SMTP Error", + } + } +} +impl Display for ErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +pub struct Error { + pub source: color_eyre::eyre::Error, + pub debug: Option, + pub kind: ErrorKind, + pub revision: Option, + pub task: Option>, +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {:#}", self.kind.as_str(), self.source) + } +} +impl Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}: {:?}", + self.kind.as_str(), + self.debug.as_ref().unwrap_or(&self.source) + ) + } +} +impl Error { + pub fn new + std::fmt::Debug + 'static>( + source: E, + kind: ErrorKind, + ) -> Self { + let debug = (std::any::TypeId::of::() == std::any::TypeId::of::()) + .then(|| eyre!("{source:?}")); + Error { + source: source.into(), + debug, + kind, + revision: None, + task: None, + } + } + pub fn clone_output(&self) -> Self { + Error { + source: eyre!("{}", self.source), + debug: self.debug.as_ref().map(|e| eyre!("{e}")), + kind: self.kind, + revision: self.revision.clone(), + task: None, + } + } + pub fn with_task(mut self, task: JoinHandle<()>) -> Self { + self.task = Some(task); + self + } + pub async fn wait(mut self) -> Self { + if let Some(task) = &mut self.task { + task.await.log_err(); + } + self.task.take(); + self + } +} +impl axum::response::IntoResponse for Error { + fn into_response(self) -> axum::response::Response { + let mut res = axum::Json(RpcError::from(self)).into_response(); + *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + res + } +} +impl From for Error { + fn from(value: std::convert::Infallible) -> Self { + match value {} + } +} +impl From for Error { + fn from(err: InvalidId) -> Self { + Error::new(err, ErrorKind::InvalidId) + } +} +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::new(e, ErrorKind::Filesystem) + } +} +impl From for Error { + fn from(e: std::str::Utf8Error) -> Self { + Error::new(e, ErrorKind::Utf8) + } +} +impl From for Error { + fn from(e: std::string::FromUtf8Error) -> Self { + Error::new(e, ErrorKind::Utf8) + } +} +impl From for Error { + fn from(e: exver::ParseError) -> Self { + Error::new(e, ErrorKind::ParseVersion) + } +} +impl From for Error { + fn from(e: rpc_toolkit::url::ParseError) -> Self { + Error::new(e, ErrorKind::ParseUrl) + } +} +impl From for Error { + fn from(e: std::num::ParseIntError) -> Self { + Error::new(e, ErrorKind::ParseNumber) + } +} +impl From for Error { + fn from(e: std::num::ParseFloatError) -> Self { + Error::new(e, ErrorKind::ParseNumber) + } +} +impl From for Error { + fn from(e: patch_db::Error) -> Self { + Error::new(e, ErrorKind::Database) + } +} +impl From for Error { + fn from(e: ed25519_dalek::SignatureError) -> Self { + Error::new(e, ErrorKind::InvalidSignature) + } +} +impl From for Error { + fn from(e: std::net::AddrParseError) -> Self { + Error::new(e, ErrorKind::ParseNetAddress) + } +} +impl From for Error { + fn from(e: ipnet::AddrParseError) -> Self { + Error::new(e, ErrorKind::ParseNetAddress) + } +} +impl From for Error { + fn from(e: openssl::error::ErrorStack) -> Self { + Error::new(eyre!("{}", e), ErrorKind::OpenSsl) + } +} +impl From for Error { + fn from(e: mbrman::Error) -> Self { + Error::new(e, ErrorKind::DiskManagement) + } +} +impl From for Error { + fn from(e: gpt::GptError) -> Self { + Error::new(e, ErrorKind::DiskManagement) + } +} +impl From for Error { + fn from(e: gpt::mbr::MBRError) -> Self { + Error::new(e, ErrorKind::DiskManagement) + } +} +impl From for Error { + fn from(e: InvalidUri) -> Self { + Error::new(eyre!("{}", e), ErrorKind::ParseUrl) + } +} +impl From for Error { + fn from(e: ssh_key::Error) -> Self { + Error::new(e, ErrorKind::OpenSsh) + } +} +impl From for Error { + fn from(e: reqwest::Error) -> Self { + let kind = match e { + _ if e.is_builder() => ErrorKind::ParseUrl, + _ if e.is_decode() => ErrorKind::Deserialization, + _ => ErrorKind::Network, + }; + Error::new(e, kind) + } +} +#[cfg(feature = "arti")] +impl From for Error { + fn from(e: arti_client::Error) -> Self { + Error::new(e, ErrorKind::Tor) + } +} +impl From for Error { + fn from(e: torut::control::ConnError) -> Self { + Error::new(e, ErrorKind::Tor) + } +} +impl From for Error { + fn from(e: zbus::Error) -> Self { + Error::new(e, ErrorKind::DBus) + } +} +impl From for Error { + fn from(e: rustls::Error) -> Self { + Error::new(e, ErrorKind::OpenSsl) + } +} +impl From for Error { + fn from(e: lettre::error::Error) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} +impl From for Error { + fn from(e: lettre::transport::smtp::Error) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} +impl From for Error { + fn from(e: lettre::address::AddressError) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} +impl From for Error { + fn from(e: hyper::Error) -> Self { + Error::new(e, ErrorKind::Network) + } +} +impl From for Error { + fn from(value: patch_db::value::Error) -> Self { + match value.kind { + patch_db::value::ErrorKind::Serialization => { + Error::new(value.source, ErrorKind::Serialization) + } + patch_db::value::ErrorKind::Deserialization => { + Error::new(value.source, ErrorKind::Deserialization) + } + } + } +} + +#[derive(Clone, Deserialize, Serialize, TS)] +pub struct ErrorData { + pub details: String, + pub debug: String, +} +impl Display for ErrorData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&self.details, f) + } +} +impl Debug for ErrorData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&self.debug, f) + } +} +impl std::error::Error for ErrorData {} +impl From for ErrorData { + fn from(value: Error) -> Self { + Self { + details: value.to_string(), + debug: format!("{:?}", value), + } + } +} +impl From<&RpcError> for ErrorData { + fn from(value: &RpcError) -> Self { + Self { + details: value + .data + .as_ref() + .and_then(|d| { + d.as_object() + .and_then(|d| { + d.get("details") + .and_then(|d| d.as_str().map(|s| s.to_owned())) + }) + .or_else(|| d.as_str().map(|s| s.to_owned())) + }) + .unwrap_or_else(|| value.message.clone().into_owned()), + debug: value + .data + .as_ref() + .and_then(|d| { + d.as_object() + .and_then(|d| { + d.get("debug") + .and_then(|d| d.as_str().map(|s| s.to_owned())) + }) + .or_else(|| d.as_str().map(|s| s.to_owned())) + }) + .unwrap_or_else(|| value.message.clone().into_owned()), + } + } +} + +impl From for RpcError { + fn from(e: Error) -> Self { + let mut data_object = serde_json::Map::with_capacity(3); + data_object.insert("details".to_owned(), format!("{}", e.source).into()); + data_object.insert("debug".to_owned(), format!("{:?}", e.source).into()); + data_object.insert( + "revision".to_owned(), + match serde_json::to_value(&e.revision) { + Ok(a) => a, + Err(e) => { + tracing::warn!("Error serializing revision for Error object: {}", e); + serde_json::Value::Null + } + }, + ); + RpcError { + code: e.kind as i32, + message: e.kind.as_str().into(), + data: Some( + match serde_json::to_value(&ErrorData { + details: format!("{}", e.source), + debug: format!("{:?}", e.source), + }) { + Ok(a) => a, + Err(e) => { + tracing::warn!("Error serializing revision for Error object: {}", e); + serde_json::Value::Null + } + }, + ), + } + } +} +impl From for Error { + fn from(e: RpcError) -> Self { + Error::new( + ErrorData::from(&e), + if let Ok(kind) = e.code.try_into() { + kind + } else if e.code == METHOD_NOT_FOUND_ERROR.code { + ErrorKind::NotFound + } else if e.code == PARSE_ERROR.code + || e.code == INVALID_PARAMS_ERROR.code + || e.code == INVALID_REQUEST_ERROR.code + { + ErrorKind::Deserialization + } else { + ErrorKind::Unknown + }, + ) + } +} #[derive(Debug, Default)] pub struct ErrorCollection(Vec); @@ -17,15 +539,11 @@ impl ErrorCollection { } } - pub fn into_result(mut self) -> Result<(), Error> { - if self.0.len() <= 1 { - if let Some(err) = self.0.pop() { - Err(err) - } else { - Ok(()) - } + pub fn into_result(self) -> Result<(), Error> { + if self.0.is_empty() { + Ok(()) } else { - Err(Error::new(self, ErrorKind::MultipleErrors)) + Err(Error::new(eyre!("{}", self), ErrorKind::MultipleErrors)) } } } @@ -52,13 +570,107 @@ impl std::fmt::Display for ErrorCollection { Ok(()) } } -impl std::error::Error for ErrorCollection {} + +pub trait ResultExt +where + Self: Sized, +{ + fn with_kind(self, kind: ErrorKind) -> Result; + fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result; + fn log_err(self) -> Option; +} +impl ResultExt for Result +where + color_eyre::eyre::Error: From, + E: std::fmt::Debug + 'static, +{ + fn with_kind(self, kind: ErrorKind) -> Result { + self.map_err(|e| Error::new(e, kind)) + } + + fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result { + self.map_err(|e| { + let (kind, ctx) = f(&e); + let debug = (std::any::TypeId::of::() == std::any::TypeId::of::()) + .then(|| eyre!("{ctx}: {e:?}")); + let source = color_eyre::eyre::Error::from(e); + let with_ctx = format!("{ctx}: {source}"); + let source = source.wrap_err(with_ctx); + Error { + kind, + source, + debug, + revision: None, + task: None, + } + }) + } + + fn log_err(self) -> Option { + match self { + Ok(a) => Some(a), + Err(e) => { + let e: color_eyre::eyre::Error = e.into(); + tracing::error!("{e}"); + tracing::debug!("{e:?}"); + None + } + } + } +} +impl ResultExt for Result { + fn with_kind(self, kind: ErrorKind) -> Result { + self.map_err(|e| Error { kind, ..e }) + } + + fn with_ctx (ErrorKind, D), D: Display>(self, f: F) -> Result { + self.map_err(|e| { + let (kind, ctx) = f(&e); + let source = e.source; + let with_ctx = format!("{ctx}: {source}"); + let source = source.wrap_err(with_ctx); + let debug = e.debug.map(|e| { + let with_ctx = format!("{ctx}: {e}"); + e.wrap_err(with_ctx) + }); + Error { + kind, + source, + debug, + ..e + } + }) + } + + fn log_err(self) -> Option { + match self { + Ok(a) => Some(a), + Err(e) => { + tracing::error!("{e}"); + tracing::debug!("{e:?}"); + None + } + } + } +} + +pub trait OptionExt +where + Self: Sized, +{ + fn or_not_found(self, message: impl std::fmt::Display) -> Result; +} +impl OptionExt for Option { + fn or_not_found(self, message: impl std::fmt::Display) -> Result { + self.ok_or_else(|| Error::new(eyre!("{}", message), ErrorKind::NotFound)) + } +} #[macro_export] macro_rules! ensure_code { ($x:expr, $c:expr, $fmt:expr $(, $arg:expr)*) => { if !($x) { - Err::<(), _>(crate::error::Error::new(color_eyre::eyre::eyre!($fmt, $($arg, )*), $c))?; + return Err(Error::new(color_eyre::eyre::eyre!($fmt, $($arg, )*), $c)); } }; } diff --git a/core/models/src/id/action.rs b/core/startos/src/id/action.rs similarity index 100% rename from core/models/src/id/action.rs rename to core/startos/src/id/action.rs diff --git a/core/models/src/id/gateway.rs b/core/startos/src/id/gateway.rs similarity index 97% rename from core/models/src/id/gateway.rs rename to core/startos/src/id/gateway.rs index f005147a7..215f91a15 100644 --- a/core/models/src/id/gateway.rs +++ b/core/startos/src/id/gateway.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; use ts_rs::TS; -use yasi::InternedString; +use imbl_value::InternedString; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] #[ts(type = "string")] diff --git a/core/models/src/id/health_check.rs b/core/startos/src/id/health_check.rs similarity index 100% rename from core/models/src/id/health_check.rs rename to core/startos/src/id/health_check.rs diff --git a/core/models/src/id/host.rs b/core/startos/src/id/host.rs similarity index 97% rename from core/models/src/id/host.rs rename to core/startos/src/id/host.rs index 58d7eb027..67b512f08 100644 --- a/core/models/src/id/host.rs +++ b/core/startos/src/id/host.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize}; use ts_rs::TS; -use yasi::InternedString; +use imbl_value::InternedString; use crate::{Id, InvalidId}; diff --git a/core/models/src/id/image.rs b/core/startos/src/id/image.rs similarity index 94% rename from core/models/src/id/image.rs rename to core/startos/src/id/image.rs index 69a04f880..d1a88e135 100644 --- a/core/models/src/id/image.rs +++ b/core/startos/src/id/image.rs @@ -5,7 +5,8 @@ use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize}; use ts_rs::TS; -use crate::{Id, InvalidId, PackageId, VersionString}; +use crate::util::VersionString; +use crate::{Id, InvalidId, PackageId}; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] #[ts(type = "string")] diff --git a/core/models/src/id/invalid_id.rs b/core/startos/src/id/invalid_id.rs similarity index 77% rename from core/models/src/id/invalid_id.rs rename to core/startos/src/id/invalid_id.rs index 4a6f0f2e7..8dec6cd1a 100644 --- a/core/models/src/id/invalid_id.rs +++ b/core/startos/src/id/invalid_id.rs @@ -1,4 +1,4 @@ -use yasi::InternedString; +use imbl_value::InternedString; #[derive(Debug, thiserror::Error)] #[error("Invalid ID: {0}")] diff --git a/core/models/src/id/mod.rs b/core/startos/src/id/mod.rs similarity index 98% rename from core/models/src/id/mod.rs rename to core/startos/src/id/mod.rs index f9f29513c..6783b6e84 100644 --- a/core/models/src/id/mod.rs +++ b/core/startos/src/id/mod.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use regex::Regex; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use yasi::InternedString; +use imbl_value::InternedString; mod action; mod gateway; diff --git a/core/models/src/id/package.rs b/core/startos/src/id/package.rs similarity index 98% rename from core/models/src/id/package.rs rename to core/startos/src/id/package.rs index 4c3b06d60..2dc7e0ae5 100644 --- a/core/models/src/id/package.rs +++ b/core/startos/src/id/package.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize, Serializer}; use ts_rs::TS; -use yasi::InternedString; +use imbl_value::InternedString; use crate::{Id, InvalidId, SYSTEM_ID}; diff --git a/core/models/src/id/replay.rs b/core/startos/src/id/replay.rs similarity index 97% rename from core/models/src/id/replay.rs rename to core/startos/src/id/replay.rs index 77cc3e607..2bc169aa5 100644 --- a/core/models/src/id/replay.rs +++ b/core/startos/src/id/replay.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; use ts_rs::TS; -use yasi::InternedString; +use imbl_value::InternedString; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] #[ts(type = "string")] diff --git a/core/models/src/id/service_interface.rs b/core/startos/src/id/service_interface.rs similarity index 96% rename from core/models/src/id/service_interface.rs rename to core/startos/src/id/service_interface.rs index f398eef78..27a3f7d82 100644 --- a/core/models/src/id/service_interface.rs +++ b/core/startos/src/id/service_interface.rs @@ -5,7 +5,8 @@ use rpc_toolkit::clap::builder::ValueParserFactory; use serde::{Deserialize, Deserializer, Serialize}; use ts_rs::TS; -use crate::{FromStrParser, Id}; +use crate::util::FromStrParser; +use crate::Id; #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] #[ts(export, type = "string")] diff --git a/core/models/src/id/volume.rs b/core/startos/src/id/volume.rs similarity index 100% rename from core/models/src/id/volume.rs rename to core/startos/src/id/volume.rs diff --git a/core/startos/src/init.rs b/core/startos/src/init.rs index 001dca911..79d66cd1d 100644 --- a/core/startos/src/init.rs +++ b/core/startos/src/init.rs @@ -7,7 +7,6 @@ use axum::extract::ws; use const_format::formatcp; use futures::{StreamExt, TryStreamExt}; use itertools::Itertools; -use models::ResultExt; use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; @@ -39,7 +38,7 @@ use crate::util::io::{IOHook, open_file}; use crate::util::lshw::lshw; use crate::util::net::WebSocketExt; use crate::util::{Invoke, cpupower}; -use crate::{Error, MAIN_DATA, PACKAGE_DATA}; +use crate::{Error, MAIN_DATA, PACKAGE_DATA, ResultExt}; pub const SYSTEM_REBUILD_PATH: &str = "/media/startos/config/system-rebuild"; pub const STANDBY_MODE_PATH: &str = "/media/startos/config/standby"; @@ -303,8 +302,8 @@ pub async fn init( if tokio::fs::metadata(&downloading).await.is_ok() { tokio::fs::remove_dir_all(&downloading).await?; } - let tmp_docker = Path::new(PACKAGE_DATA).join(formatcp!("tmp/{CONTAINER_TOOL}")); - crate::disk::mount::util::bind(&tmp_docker, CONTAINER_DATADIR, false).await?; + let tmp_docker = Path::new(PACKAGE_DATA).join("tmp").join(*CONTAINER_TOOL); + crate::disk::mount::util::bind(&tmp_docker, *CONTAINER_DATADIR, false).await?; init_tmp.complete(); let server_info = db.peek().await.into_public().into_server_info(); diff --git a/core/startos/src/install/mod.rs b/core/startos/src/install/mod.rs index 54002805a..588ae3fb4 100644 --- a/core/startos/src/install/mod.rs +++ b/core/startos/src/install/mod.rs @@ -10,7 +10,7 @@ use exver::VersionRange; use futures::StreamExt; use imbl_value::{InternedString, json}; use itertools::Itertools; -use models::{FromStrParser, VersionString}; +use crate::util::{FromStrParser, VersionString}; use reqwest::Url; use reqwest::header::{CONTENT_LENGTH, HeaderMap}; use rpc_toolkit::HandlerArgs; diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index 7b0d83e1f..2383305ca 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -43,6 +43,7 @@ pub mod diagnostic; pub mod disk; pub mod error; pub mod firmware; +pub mod id; pub mod hostname; pub mod init; pub mod install; @@ -75,7 +76,8 @@ pub mod volume; use std::time::SystemTime; use clap::Parser; -pub use error::{Error, ErrorKind, ResultExt}; +pub use error::{Error, ErrorKind, OptionExt, ResultExt}; +pub use id::*; use imbl_value::Value; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{ diff --git a/core/startos/src/logs.rs b/core/startos/src/logs.rs index 7d3b5c623..17199d117 100644 --- a/core/startos/src/logs.rs +++ b/core/startos/src/logs.rs @@ -13,7 +13,8 @@ use color_eyre::eyre::eyre; use futures::stream::BoxStream; use futures::{Future, FutureExt, Stream, StreamExt, TryStreamExt}; use itertools::Itertools; -use models::{FromStrParser, PackageId}; +use crate::util::FromStrParser; +use crate::PackageId; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{ CallRemote, Context, Empty, HandlerArgs, HandlerExt, HandlerFor, ParentHandler, from_fn_async, diff --git a/core/startos/src/lxc/mod.rs b/core/startos/src/lxc/mod.rs index bda87827d..2b154309e 100644 --- a/core/startos/src/lxc/mod.rs +++ b/core/startos/src/lxc/mod.rs @@ -7,7 +7,8 @@ use std::time::Duration; use clap::builder::ValueParserFactory; use futures::StreamExt; use imbl_value::InternedString; -use models::{FromStrParser, InvalidId, PackageId}; +use crate::util::FromStrParser; +use crate::{InvalidId, PackageId}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{RpcRequest, RpcResponse}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/main/start-cli.rs b/core/startos/src/main/start-cli.rs index 040d3c97d..d1c5741ab 100644 --- a/core/startos/src/main/start-cli.rs +++ b/core/startos/src/main/start-cli.rs @@ -1,5 +1,19 @@ use startos::bins::MultiExecutable; +use startos::s9pk::v2::pack::PREFER_DOCKER; fn main() { + if !std::env::var("STARTOS_USE_PODMAN").map_or(false, |v| { + let v = v.trim(); + if ["1", "true", "y", "yes"].into_iter().any(|x| v == x) { + true + } else if ["0", "false", "n", "no"].into_iter().any(|x| v == x) { + false + } else { + tracing::warn!("Unknown value for STARTOS_USE_PODMAN: {v}"); + false + } + }) { + PREFER_DOCKER.set(true).ok(); + } MultiExecutable::default().enable_start_cli().execute() } diff --git a/core/startos/src/middleware/auth.rs b/core/startos/src/middleware/auth.rs index 3d2d7679e..d746bb1ee 100644 --- a/core/startos/src/middleware/auth.rs +++ b/core/startos/src/middleware/auth.rs @@ -12,7 +12,6 @@ use basic_cookies::Cookie; use chrono::Utc; use color_eyre::eyre::eyre; use digest::Digest; -use helpers::const_true; use http::HeaderValue; use http::header::{COOKIE, USER_AGENT}; use imbl_value::{InternedString, json}; @@ -32,7 +31,7 @@ use crate::prelude::*; use crate::rpc_continuations::OpenAuthedContinuations; use crate::util::Invoke; use crate::util::io::{create_file_mod, read_file_to_string}; -use crate::util::serde::BASE64; +use crate::util::serde::{BASE64, const_true}; use crate::util::sync::SyncMutex; pub trait AuthContext: SignatureAuthContext { diff --git a/core/startos/src/net/acme.rs b/core/startos/src/net/acme.rs index 857ec3e65..94f00af20 100644 --- a/core/startos/src/net/acme.rs +++ b/core/startos/src/net/acme.rs @@ -9,7 +9,8 @@ use clap::builder::ValueParserFactory; use futures::StreamExt; use imbl_value::InternedString; use itertools::Itertools; -use models::{ErrorData, FromStrParser}; +use crate::error::ErrorData; +use crate::util::FromStrParser; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; diff --git a/core/startos/src/net/dns.rs b/core/startos/src/net/dns.rs index a5ee133fa..2b18cc206 100644 --- a/core/startos/src/net/dns.rs +++ b/core/startos/src/net/dns.rs @@ -9,7 +9,7 @@ use clap::Parser; use color_eyre::eyre::eyre; use futures::future::BoxFuture; use futures::{FutureExt, StreamExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use hickory_client::client::Client; use hickory_client::proto::DnsHandle; use hickory_client::proto::runtime::TokioRuntimeProvider; @@ -23,7 +23,7 @@ use hickory_server::proto::rr::{Name, Record, RecordType}; use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo}; use imbl::OrdMap; use imbl_value::InternedString; -use models::{GatewayId, OptionExt, PackageId}; +use crate::{GatewayId, OptionExt, PackageId}; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{ Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async, from_fn_blocking, diff --git a/core/startos/src/net/forward.rs b/core/startos/src/net/forward.rs index 3ab413aa2..9a535fa4b 100644 --- a/core/startos/src/net/forward.rs +++ b/core/startos/src/net/forward.rs @@ -4,11 +4,11 @@ use std::sync::{Arc, Weak}; use std::time::Duration; use futures::channel::oneshot; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use id_pool::IdPool; use iddqd::{IdOrdItem, IdOrdMap}; use imbl::OrdMap; -use models::GatewayId; +use crate::GatewayId; use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; diff --git a/core/startos/src/net/gateway.rs b/core/startos/src/net/gateway.rs index c2479eff1..8bb5297ac 100644 --- a/core/startos/src/net/gateway.rs +++ b/core/startos/src/net/gateway.rs @@ -10,12 +10,12 @@ use std::time::Duration; use clap::Parser; use futures::future::Either; use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::{OrdMap, OrdSet}; use imbl_value::InternedString; use ipnet::IpNet; use itertools::Itertools; -use models::GatewayId; +use crate::GatewayId; use nix::net::if_::if_nametoindex; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; diff --git a/core/startos/src/net/host/address.rs b/core/startos/src/net/host/address.rs index 6d7723a23..d809705fe 100644 --- a/core/startos/src/net/host/address.rs +++ b/core/startos/src/net/host/address.rs @@ -3,7 +3,7 @@ use std::net::Ipv4Addr; use clap::Parser; use imbl_value::InternedString; -use models::GatewayId; +use crate::GatewayId; use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/net/host/binding.rs b/core/startos/src/net/host/binding.rs index 4c6b85ff3..805562a85 100644 --- a/core/startos/src/net/host/binding.rs +++ b/core/startos/src/net/host/binding.rs @@ -4,7 +4,8 @@ use std::str::FromStr; use clap::Parser; use clap::builder::ValueParserFactory; use imbl::OrdSet; -use models::{FromStrParser, GatewayId, HostId}; +use crate::util::FromStrParser; +use crate::{GatewayId, HostId}; use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index c5e6388eb..924a97615 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -5,7 +5,7 @@ use std::panic::RefUnwindSafe; use clap::Parser; use imbl_value::InternedString; use itertools::Itertools; -use models::{HostId, PackageId}; +use crate::{HostId, PackageId}; use rpc_toolkit::{Context, Empty, HandlerExt, OrEmpty, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index e74eadf0c..33061bb75 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -6,7 +6,7 @@ use color_eyre::eyre::eyre; use imbl::{OrdMap, vector}; use imbl_value::InternedString; use ipnet::IpNet; -use models::{GatewayId, HostId, OptionExt, PackageId}; +use crate::{GatewayId, HostId, OptionExt, PackageId}; use tokio::sync::Mutex; use tokio::task::JoinHandle; use tokio_rustls::rustls::ClientConfig as TlsClientConfig; diff --git a/core/startos/src/net/service_interface.rs b/core/startos/src/net/service_interface.rs index 0d1a193ad..4c4cbf2c4 100644 --- a/core/startos/src/net/service_interface.rs +++ b/core/startos/src/net/service_interface.rs @@ -1,7 +1,7 @@ use std::net::{Ipv4Addr, Ipv6Addr}; use imbl_value::InternedString; -use models::{GatewayId, HostId, ServiceInterfaceId}; +use crate::{GatewayId, HostId, ServiceInterfaceId}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/net/socks.rs b/core/startos/src/net/socks.rs index d556fa143..fd4085fb3 100644 --- a/core/startos/src/net/socks.rs +++ b/core/startos/src/net/socks.rs @@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::Arc; use std::time::Duration; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use socks5_impl::protocol::{Address, Reply}; use socks5_impl::server::auth::NoAuth; use socks5_impl::server::{AuthAdaptor, ClientConnection, Server}; diff --git a/core/startos/src/net/static_server.rs b/core/startos/src/net/static_server.rs index 3c1585e7e..b7e50c7f8 100644 --- a/core/startos/src/net/static_server.rs +++ b/core/startos/src/net/static_server.rs @@ -22,7 +22,7 @@ use http::request::Parts as RequestParts; use http::{HeaderValue, Method, StatusCode}; use imbl_value::InternedString; use include_dir::Dir; -use models::PackageId; +use crate::PackageId; use new_mime_guess::MimeGuess; use openssl::hash::MessageDigest; use openssl::x509::X509; diff --git a/core/startos/src/net/tor/arti.rs b/core/startos/src/net/tor/arti.rs index 1cfe7cfb1..2202d737d 100644 --- a/core/startos/src/net/tor/arti.rs +++ b/core/startos/src/net/tor/arti.rs @@ -11,7 +11,7 @@ use base64::Engine; use clap::Parser; use color_eyre::eyre::eyre; use futures::{FutureExt, StreamExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl_value::InternedString; use itertools::Itertools; use rpc_toolkit::{Context, Empty, HandlerExt, ParentHandler, from_fn_async}; diff --git a/core/startos/src/net/tor/ctor.rs b/core/startos/src/net/tor/ctor.rs index 110e05236..fb0d33f87 100644 --- a/core/startos/src/net/tor/ctor.rs +++ b/core/startos/src/net/tor/ctor.rs @@ -10,7 +10,7 @@ use clap::Parser; use color_eyre::eyre::eyre; use futures::future::BoxFuture; use futures::{FutureExt, TryFutureExt, TryStreamExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::OrdMap; use imbl_value::InternedString; use lazy_static::lazy_static; diff --git a/core/startos/src/net/tunnel.rs b/core/startos/src/net/tunnel.rs index f58cc17c7..d0cb5de6e 100644 --- a/core/startos/src/net/tunnel.rs +++ b/core/startos/src/net/tunnel.rs @@ -1,6 +1,6 @@ use clap::Parser; use imbl_value::InternedString; -use models::GatewayId; +use crate::GatewayId; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/net/utils.rs b/core/startos/src/net/utils.rs index 18c2c3705..b7ce2d23b 100644 --- a/core/startos/src/net/utils.rs +++ b/core/startos/src/net/utils.rs @@ -8,7 +8,7 @@ use futures::stream::BoxStream; use futures::{StreamExt, TryStreamExt}; use imbl_value::InternedString; use ipnet::{IpNet, Ipv4Net, Ipv6Net}; -use models::GatewayId; +use crate::GatewayId; use nix::net::if_::if_nametoindex; use tokio::net::{TcpListener, TcpStream}; use tokio::process::Command; diff --git a/core/startos/src/net/vhost.rs b/core/startos/src/net/vhost.rs index 647b92354..3f53f1011 100644 --- a/core/startos/src/net/vhost.rs +++ b/core/startos/src/net/vhost.rs @@ -9,9 +9,9 @@ use async_acme::acme::ACME_TLS_ALPN_NAME; use color_eyre::eyre::eyre; use futures::FutureExt; use futures::future::BoxFuture; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl_value::{InOMap, InternedString}; -use models::ResultExt; +use crate::ResultExt; use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn}; use serde::{Deserialize, Serialize}; use tokio::net::TcpStream; diff --git a/core/startos/src/net/web_server.rs b/core/startos/src/net/web_server.rs index c1844ec44..47ce920b5 100644 --- a/core/startos/src/net/web_server.rs +++ b/core/startos/src/net/web_server.rs @@ -12,7 +12,7 @@ use std::time::Duration; use axum::Router; use futures::future::Either; use futures::{FutureExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use http::Extensions; use hyper_util::rt::{TokioIo, TokioTimer}; use tokio::net::TcpListener; diff --git a/core/startos/src/notifications.rs b/core/startos/src/notifications.rs index cbbea5da6..4a5a9db38 100644 --- a/core/startos/src/notifications.rs +++ b/core/startos/src/notifications.rs @@ -6,9 +6,9 @@ use chrono::{DateTime, Utc}; use clap::Parser; use clap::builder::ValueParserFactory; use color_eyre::eyre::eyre; -use helpers::const_true; use imbl_value::InternedString; -use models::{FromStrParser, PackageId}; +use crate::util::FromStrParser; +use crate::PackageId; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tracing::instrument; @@ -18,7 +18,7 @@ use crate::backup::BackupReport; use crate::context::{CliContext, RpcContext}; use crate::db::model::DatabaseModel; use crate::prelude::*; -use crate::util::serde::HandlerExtSerde; +use crate::util::serde::{HandlerExtSerde, const_true}; // #[command(subcommands(list, delete, delete_before, create))] pub fn notification() -> ParentHandler { diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index 892cc52ae..0449b55d8 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use clap::Parser; use color_eyre::eyre::eyre; -use models::Error; +use crate::Error; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; diff --git a/core/startos/src/prelude.rs b/core/startos/src/prelude.rs index 702d77c2d..d42c2c9d9 100644 --- a/core/startos/src/prelude.rs +++ b/core/startos/src/prelude.rs @@ -1,11 +1,10 @@ pub use color_eyre::eyre::eyre; pub use lazy_format::lazy_format; -pub use models::OptionExt; pub use tracing::instrument; pub use crate::db::prelude::*; pub use crate::ensure_code; -pub use crate::error::{Error, ErrorCollection, ErrorKind, ResultExt}; +pub use crate::error::{Error, ErrorCollection, ErrorKind, OptionExt, ResultExt}; #[macro_export] macro_rules! dbg { diff --git a/core/startos/src/progress.rs b/core/startos/src/progress.rs index 0a5ba351f..780456143 100644 --- a/core/startos/src/progress.rs +++ b/core/startos/src/progress.rs @@ -4,7 +4,6 @@ use std::time::Duration; use futures::future::pending; use futures::stream::BoxStream; use futures::{Future, FutureExt, StreamExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; use imbl::Vector; use imbl_value::{InOMap, InternedString}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; @@ -16,6 +15,7 @@ use ts_rs::TS; use crate::db::model::{Database, DatabaseModel}; use crate::prelude::*; +use crate::util::future::NonDetachingJoinHandle; lazy_static::lazy_static! { static ref SPINNER: ProgressStyle = ProgressStyle::with_template("{spinner} {msg}...").unwrap(); diff --git a/core/startos/src/registry/asset.rs b/core/startos/src/registry/asset.rs index 421352804..e8856c9ae 100644 --- a/core/startos/src/registry/asset.rs +++ b/core/startos/src/registry/asset.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::sync::Arc; use chrono::{DateTime, Utc}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use reqwest::Client; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWrite; diff --git a/core/startos/src/registry/info.rs b/core/startos/src/registry/info.rs index 2793180a1..4afedbfb5 100644 --- a/core/startos/src/registry/info.rs +++ b/core/startos/src/registry/info.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use clap::Parser; use imbl_value::InternedString; use itertools::Itertools; -use models::DataUrl; +use crate::util::DataUrl; use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/registry/mod.rs b/core/startos/src/registry/mod.rs index dcbae96bd..8bea37624 100644 --- a/core/startos/src/registry/mod.rs +++ b/core/startos/src/registry/mod.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use axum::Router; use futures::future::ready; use imbl_value::InternedString; -use models::DataUrl; +use crate::util::DataUrl; use rpc_toolkit::{Context, HandlerExt, ParentHandler, Server, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/registry/os/asset/get.rs b/core/startos/src/registry/os/asset/get.rs index d3723c894..604b4dad4 100644 --- a/core/startos/src/registry/os/asset/get.rs +++ b/core/startos/src/registry/os/asset/get.rs @@ -4,7 +4,6 @@ use std::path::{Path, PathBuf}; use clap::Parser; use exver::Version; -use helpers::AtomicFile; use imbl_value::{InternedString, json}; use itertools::Itertools; use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; @@ -21,7 +20,7 @@ use crate::registry::os::index::OsVersionInfo; use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; use crate::sign::commitment::Commitment; use crate::sign::commitment::blake3::Blake3Commitment; -use crate::util::io::open_file; +use crate::util::io::{AtomicFile, open_file}; pub fn get_api() -> ParentHandler { ParentHandler::new() @@ -159,9 +158,7 @@ async fn cli_get_os_asset( if let Some(download) = download { let download = download.join(format!("startos-{version}_{platform}.{ext}")); - let mut file = AtomicFile::new(&download, None::<&Path>) - .await - .with_kind(ErrorKind::Filesystem)?; + let mut file = AtomicFile::new(&download, None::<&Path>).await?; let progress = FullProgressTracker::new(); let mut download_phase = @@ -181,7 +178,7 @@ async fn cli_get_os_asset( res.download(ctx.client.clone(), &mut download_writer) .await?; let (_, mut download_phase) = download_writer.into_inner(); - file.save().await.with_kind(ErrorKind::Filesystem)?; + file.save().await?; download_phase.complete(); if let Some(mut reverify_phase) = reverify_phase { diff --git a/core/startos/src/registry/package/add.rs b/core/startos/src/registry/package/add.rs index 7d02564d2..271a6c7cc 100644 --- a/core/startos/src/registry/package/add.rs +++ b/core/startos/src/registry/package/add.rs @@ -4,7 +4,8 @@ use std::sync::Arc; use clap::Parser; use imbl_value::InternedString; use itertools::Itertools; -use models::{PackageId, VersionString}; +use crate::util::VersionString; +use crate::PackageId; use rpc_toolkit::HandlerArgs; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/registry/package/category.rs b/core/startos/src/registry/package/category.rs index 92e7d0df7..e4899bef0 100644 --- a/core/startos/src/registry/package/category.rs +++ b/core/startos/src/registry/package/category.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use clap::Parser; use imbl_value::InternedString; -use models::PackageId; +use crate::PackageId; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/registry/package/get.rs b/core/startos/src/registry/package/get.rs index a14b44108..b395343d2 100644 --- a/core/startos/src/registry/package/get.rs +++ b/core/startos/src/registry/package/get.rs @@ -3,10 +3,9 @@ use std::path::{Path, PathBuf}; use clap::{Parser, ValueEnum}; use exver::{ExtendedVersion, VersionRange}; -use helpers::to_tmp_path; use imbl_value::{InternedString, json}; use itertools::Itertools; -use models::PackageId; +use crate::PackageId; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -19,7 +18,7 @@ use crate::registry::package::index::{PackageIndex, PackageVersionInfo}; use crate::s9pk::merkle_archive::source::ArchiveSource; use crate::s9pk::v2::SIG_CONTEXT; use crate::util::VersionString; -use crate::util::io::TrackingIO; +use crate::util::io::{TrackingIO, to_tmp_path}; use crate::util::serde::{WithIoFormat, display_serializable}; use crate::util::tui::choose; @@ -457,7 +456,7 @@ pub async fn cli_download( fetching_progress.complete(); let dest = dest.unwrap_or_else(|| Path::new(".").join(id).with_extension("s9pk")); - let dest_tmp = to_tmp_path(&dest).with_kind(ErrorKind::Filesystem)?; + let dest_tmp = to_tmp_path(&dest)?; let (mut parsed, source) = s9pk .download_to(&dest_tmp, ctx.client.clone(), download_progress) .await?; diff --git a/core/startos/src/registry/package/index.rs b/core/startos/src/registry/package/index.rs index f65a34524..1877da597 100644 --- a/core/startos/src/registry/package/index.rs +++ b/core/startos/src/registry/package/index.rs @@ -3,7 +3,8 @@ use std::collections::{BTreeMap, BTreeSet}; use chrono::Utc; use exver::{Version, VersionRange}; use imbl_value::InternedString; -use models::{DataUrl, PackageId, VersionString}; +use crate::util::{DataUrl, VersionString}; +use crate::PackageId; use serde::{Deserialize, Serialize}; use ts_rs::TS; use url::Url; diff --git a/core/startos/src/registry/package/signer.rs b/core/startos/src/registry/package/signer.rs index 1c994836e..69d37b092 100644 --- a/core/startos/src/registry/package/signer.rs +++ b/core/startos/src/registry/package/signer.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use clap::Parser; use exver::VersionRange; -use models::PackageId; +use crate::PackageId; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/registry/signer.rs b/core/startos/src/registry/signer.rs index f38ff81a8..8f2dddd64 100644 --- a/core/startos/src/registry/signer.rs +++ b/core/startos/src/registry/signer.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; use itertools::Itertools; -use models::FromStrParser; +use crate::util::FromStrParser; use serde::{Deserialize, Serialize}; use ts_rs::TS; use url::Url; diff --git a/core/startos/src/rpc_continuations.rs b/core/startos/src/rpc_continuations.rs index a81d21a23..c894391b7 100644 --- a/core/startos/src/rpc_continuations.rs +++ b/core/startos/src/rpc_continuations.rs @@ -11,14 +11,14 @@ use axum::response::Response; use clap::builder::ValueParserFactory; use futures::future::BoxFuture; use futures::{Future, FutureExt}; -use helpers::TimedResource; use imbl_value::InternedString; -use models::FromStrParser; +use crate::util::FromStrParser; use tokio::sync::{Mutex as AsyncMutex, broadcast}; use ts_rs::TS; #[allow(unused_imports)] use crate::prelude::*; +use crate::util::future::TimedResource; use crate::util::new_guid; #[derive( diff --git a/core/startos/src/s9pk/rpc.rs b/core/startos/src/s9pk/rpc.rs index eced48e97..a6af628e7 100644 --- a/core/startos/src/s9pk/rpc.rs +++ b/core/startos/src/s9pk/rpc.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use std::sync::Arc; use clap::Parser; -use models::ImageId; +use crate::ImageId; use rpc_toolkit::{Empty, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/s9pk/v1/manifest.rs b/core/startos/src/s9pk/v1/manifest.rs index 31821ad68..0ce5e67a6 100644 --- a/core/startos/src/s9pk/v1/manifest.rs +++ b/core/startos/src/s9pk/v1/manifest.rs @@ -4,8 +4,8 @@ use std::path::{Path, PathBuf}; use exver::{Version, VersionRange}; use imbl_value::InternedString; use indexmap::IndexMap; -pub use models::PackageId; -use models::{ActionId, HealthCheckId, ImageId, VolumeId}; +pub use crate::PackageId; +use crate::{ActionId, HealthCheckId, ImageId, VolumeId}; use serde::{Deserialize, Serialize}; use url::Url; diff --git a/core/startos/src/s9pk/v1/reader.rs b/core/startos/src/s9pk/v1/reader.rs index c181eae89..7becf0475 100644 --- a/core/startos/src/s9pk/v1/reader.rs +++ b/core/startos/src/s9pk/v1/reader.rs @@ -9,7 +9,7 @@ use std::task::{Context, Poll}; use color_eyre::eyre::eyre; use digest::Output; use ed25519_dalek::VerifyingKey; -use models::{ImageId, PackageId}; +use crate::{ImageId, PackageId}; use sha2::{Digest, Sha512}; use tokio::fs::File; use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, BufReader, ReadBuf}; diff --git a/core/startos/src/s9pk/v2/compat.rs b/core/startos/src/s9pk/v2/compat.rs index 5d978fedd..2b0edd8fa 100644 --- a/core/startos/src/s9pk/v2/compat.rs +++ b/core/startos/src/s9pk/v2/compat.rs @@ -4,7 +4,6 @@ use std::str::FromStr; use std::sync::Arc; use exver::{ExtendedVersion, VersionRange}; -use models::{ImageId, VolumeId}; use tokio::io::{AsyncRead, AsyncSeek, AsyncWriteExt}; use tokio::process::Command; @@ -20,6 +19,7 @@ use crate::s9pk::v2::pack::{CONTAINER_TOOL, ImageSource, PackSource}; use crate::s9pk::v2::{S9pk, SIG_CONTEXT}; use crate::util::Invoke; use crate::util::io::{TmpDir, create_file}; +use crate::{ImageId, VolumeId}; pub const MAGIC_AND_VERSION: &[u8] = &[0x3b, 0x3b, 0x01]; @@ -30,7 +30,7 @@ impl S9pk> { tmp_dir: Arc, signer: ed25519_dalek::SigningKey, ) -> Result { - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("run") .arg("--rm") .arg("--privileged") @@ -80,7 +80,7 @@ impl S9pk> { // images for arch in reader.docker_arches().await? { - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("load") .input(Some(&mut reader.docker_images(&arch).await?)) .invoke(ErrorKind::Docker) @@ -104,7 +104,7 @@ impl S9pk> { &mut archive, ) .await?; - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("rmi") .arg("-f") .arg(&image_name) diff --git a/core/startos/src/s9pk/v2/manifest.rs b/core/startos/src/s9pk/v2/manifest.rs index 6dd3adf03..0e5d3badc 100644 --- a/core/startos/src/s9pk/v2/manifest.rs +++ b/core/startos/src/s9pk/v2/manifest.rs @@ -4,8 +4,9 @@ use std::path::Path; use color_eyre::eyre::eyre; use exver::{Version, VersionRange}; use imbl_value::InternedString; -pub use models::PackageId; -use models::{ImageId, VolumeId, mime}; +pub use crate::PackageId; +use crate::util::mime; +use crate::{ImageId, VolumeId}; use serde::{Deserialize, Serialize}; use ts_rs::TS; use url::Url; diff --git a/core/startos/src/s9pk/v2/mod.rs b/core/startos/src/s9pk/v2/mod.rs index 29dd543e0..3453cc21d 100644 --- a/core/startos/src/s9pk/v2/mod.rs +++ b/core/startos/src/s9pk/v2/mod.rs @@ -3,7 +3,8 @@ use std::path::Path; use std::sync::Arc; use imbl_value::InternedString; -use models::{DataUrl, PackageId, mime}; +use crate::util::{DataUrl, mime}; +use crate::PackageId; use tokio::fs::File; use crate::dependencies::DependencyMetadata; diff --git a/core/startos/src/s9pk/v2/pack.rs b/core/startos/src/s9pk/v2/pack.rs index cf35099a1..4e714eff7 100644 --- a/core/startos/src/s9pk/v2/pack.rs +++ b/core/startos/src/s9pk/v2/pack.rs @@ -1,12 +1,11 @@ use std::collections::{BTreeMap, BTreeSet}; use std::path::{Path, PathBuf}; -use std::sync::Arc; +use std::sync::{Arc, LazyLock, OnceLock}; use clap::Parser; use futures::future::{BoxFuture, ready}; use futures::{FutureExt, TryStreamExt}; use imbl_value::InternedString; -use models::{DataUrl, ImageId, PackageId, VersionString}; use serde::{Deserialize, Serialize}; use tokio::process::Command; use tokio::sync::OnceCell; @@ -31,17 +30,33 @@ use crate::s9pk::merkle_archive::{Entry, MerkleArchive}; use crate::s9pk::v2::SIG_CONTEXT; use crate::util::io::{TmpDir, create_file, open_file}; use crate::util::serde::IoFormat; -use crate::util::{Invoke, PathOrUrl, new_guid}; +use crate::util::{DataUrl, Invoke, PathOrUrl, VersionString, new_guid}; +use crate::{ImageId, PackageId}; -#[cfg(not(feature = "docker"))] -pub const CONTAINER_TOOL: &str = "podman"; -#[cfg(feature = "docker")] -pub const CONTAINER_TOOL: &str = "docker"; +pub static PREFER_DOCKER: OnceLock = OnceLock::new(); -#[cfg(feature = "docker")] -pub const CONTAINER_DATADIR: &str = "/var/lib/docker"; -#[cfg(not(feature = "docker"))] -pub const CONTAINER_DATADIR: &str = "/var/lib/containers"; +pub static CONTAINER_TOOL: LazyLock<&'static str> = LazyLock::new(|| { + if *PREFER_DOCKER.get_or_init(|| false) { + if std::process::Command::new("which") + .arg("docker") + .status() + .map_or(false, |o| o.success()) + { + "docker" + } else { + "podman" + } + } else { + "podman" + } +}); +pub static CONTAINER_DATADIR: LazyLock<&'static str> = LazyLock::new(|| { + if *CONTAINER_TOOL == "docker" { + "/var/lib/docker" + } else { + "/var/lib/containers" + } +}); pub struct SqfsDir { path: PathBuf, @@ -423,8 +438,8 @@ impl ImageSource { }; // docker buildx build ${path} -o type=image,name=start9/${id} let tag = format!("start9/{id}/{image_id}:{}", new_guid()); - let mut command = Command::new(CONTAINER_TOOL); - if CONTAINER_TOOL == "docker" { + let mut command = Command::new(*CONTAINER_TOOL); + if *CONTAINER_TOOL == "docker" { command.arg("buildx"); } command @@ -461,13 +476,13 @@ impl ImageSource { .arg("-o") .arg("type=docker,dest=-") .capture(false) - .pipe(Command::new(CONTAINER_TOOL).arg("load")) + .pipe(Command::new(*CONTAINER_TOOL).arg("load")) .invoke(ErrorKind::Docker) .await?; ImageSource::DockerTag(tag.clone()) .load(tmp_dir, id, version, image_id, arch, into) .await?; - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("rmi") .arg("-f") .arg(&tag) @@ -484,7 +499,7 @@ impl ImageSource { format!("--platform=linux/{arch}") }; let container = String::from_utf8( - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("create") .arg(&docker_platform) .arg(&tag) @@ -493,7 +508,7 @@ impl ImageSource { )?; let container = container.trim(); let config = serde_json::from_slice::( - &Command::new(CONTAINER_TOOL) + &Command::new(*CONTAINER_TOOL) .arg("container") .arg("inspect") .arg("--format") @@ -545,14 +560,14 @@ impl ImageSource { .join(Guid::new().as_ref()) .with_extension("squashfs"); - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("export") .arg(container) .pipe(&mut tar2sqfs(&dest)?) .capture(false) .invoke(ErrorKind::Docker) .await?; - Command::new(CONTAINER_TOOL) + Command::new(*CONTAINER_TOOL) .arg("rm") .arg(container) .invoke(ErrorKind::Docker) @@ -586,7 +601,7 @@ fn tar2sqfs(dest: impl AsRef) -> Result { .parent() .unwrap_or_else(|| Path::new("/")) .to_path_buf(); - let mut command = Command::new(CONTAINER_TOOL); + let mut command = Command::new(*CONTAINER_TOOL); command .arg("run") .arg("-i") diff --git a/core/startos/src/service/action.rs b/core/startos/src/service/action.rs index 2081ab939..713229ec5 100644 --- a/core/startos/src/service/action.rs +++ b/core/startos/src/service/action.rs @@ -2,7 +2,8 @@ use std::collections::BTreeMap; use std::time::Duration; use imbl_value::json; -use models::{ActionId, PackageId, ProcedureName, ReplayId}; +use crate::service::ProcedureName; +use crate::{ActionId, PackageId, ReplayId}; use crate::action::{ActionInput, ActionResult}; use crate::db::model::package::{ diff --git a/core/startos/src/service/effects/action.rs b/core/startos/src/service/effects/action.rs index ba2a0185d..3e195a92a 100644 --- a/core/startos/src/service/effects/action.rs +++ b/core/startos/src/service/effects/action.rs @@ -1,6 +1,6 @@ use std::collections::BTreeSet; -use models::{ActionId, PackageId, ReplayId}; +use crate::{ActionId, PackageId, ReplayId}; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use crate::action::{ActionInput, ActionResult, display_action_result}; diff --git a/core/startos/src/service/effects/callbacks.rs b/core/startos/src/service/effects/callbacks.rs index dea736aeb..2a94b2627 100644 --- a/core/startos/src/service/effects/callbacks.rs +++ b/core/startos/src/service/effects/callbacks.rs @@ -5,10 +5,10 @@ use std::time::{Duration, SystemTime}; use clap::Parser; use futures::future::join_all; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::{Vector, vector}; use imbl_value::InternedString; -use models::{HostId, PackageId, ServiceInterfaceId}; +use crate::{HostId, PackageId, ServiceInterfaceId}; use serde::{Deserialize, Serialize}; use tracing::warn; use ts_rs::TS; diff --git a/core/startos/src/service/effects/control.rs b/core/startos/src/service/effects/control.rs index 4289482f4..5dd0e794a 100644 --- a/core/startos/src/service/effects/control.rs +++ b/core/startos/src/service/effects/control.rs @@ -2,7 +2,8 @@ use std::str::FromStr; use chrono::Utc; use clap::builder::ValueParserFactory; -use models::{FromStrParser, PackageId}; +use crate::util::FromStrParser; +use crate::PackageId; use crate::service::RebuildParams; use crate::service::effects::prelude::*; diff --git a/core/startos/src/service/effects/dependency.rs b/core/startos/src/service/effects/dependency.rs index 3c30ff30f..876e8dc47 100644 --- a/core/startos/src/service/effects/dependency.rs +++ b/core/startos/src/service/effects/dependency.rs @@ -5,7 +5,8 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; use exver::VersionRange; use imbl_value::InternedString; -use models::{FromStrParser, HealthCheckId, PackageId, ReplayId, VersionString, VolumeId}; +use crate::util::{FromStrParser, VersionString}; +use crate::{HealthCheckId, PackageId, ReplayId, VolumeId}; use crate::DATA_DIR; use crate::db::model::package::{ diff --git a/core/startos/src/service/effects/health.rs b/core/startos/src/service/effects/health.rs index 587a5c84f..548c02dbd 100644 --- a/core/startos/src/service/effects/health.rs +++ b/core/startos/src/service/effects/health.rs @@ -1,4 +1,4 @@ -use models::HealthCheckId; +use crate::HealthCheckId; use crate::service::effects::prelude::*; use crate::status::health_check::NamedHealthCheckResult; diff --git a/core/startos/src/service/effects/net/bind.rs b/core/startos/src/service/effects/net/bind.rs index 732249d74..252423d94 100644 --- a/core/startos/src/service/effects/net/bind.rs +++ b/core/startos/src/service/effects/net/bind.rs @@ -1,4 +1,4 @@ -use models::{HostId, PackageId}; +use crate::{HostId, PackageId}; use crate::net::host::binding::{BindId, BindOptions, NetInfo}; use crate::service::effects::prelude::*; diff --git a/core/startos/src/service/effects/net/host.rs b/core/startos/src/service/effects/net/host.rs index 7039942d7..e042b58bd 100644 --- a/core/startos/src/service/effects/net/host.rs +++ b/core/startos/src/service/effects/net/host.rs @@ -1,4 +1,4 @@ -use models::{HostId, PackageId}; +use crate::{HostId, PackageId}; use crate::net::host::Host; use crate::service::effects::callbacks::CallbackHandler; diff --git a/core/startos/src/service/effects/net/info.rs b/core/startos/src/service/effects/net/info.rs index 90d3ef223..74ed7c8da 100644 --- a/core/startos/src/service/effects/net/info.rs +++ b/core/startos/src/service/effects/net/info.rs @@ -1,6 +1,6 @@ use std::net::Ipv4Addr; -use models::PackageId; +use crate::PackageId; use crate::service::effects::callbacks::CallbackHandler; use crate::service::effects::prelude::*; diff --git a/core/startos/src/service/effects/net/interface.rs b/core/startos/src/service/effects/net/interface.rs index 6cb327fff..94b416846 100644 --- a/core/startos/src/service/effects/net/interface.rs +++ b/core/startos/src/service/effects/net/interface.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use imbl::vector; -use models::{PackageId, ServiceInterfaceId}; +use crate::{PackageId, ServiceInterfaceId}; use crate::net::service_interface::{AddressInfo, ServiceInterface, ServiceInterfaceType}; use crate::service::effects::callbacks::CallbackHandler; diff --git a/core/startos/src/service/effects/subcontainer/mod.rs b/core/startos/src/service/effects/subcontainer/mod.rs index 2766c7e53..9cbeae808 100644 --- a/core/startos/src/service/effects/subcontainer/mod.rs +++ b/core/startos/src/service/effects/subcontainer/mod.rs @@ -1,9 +1,9 @@ use std::path::{Path, PathBuf}; use imbl_value::InternedString; -use models::ImageId; use tokio::process::Command; +use crate::ImageId; use crate::disk::mount::filesystem::overlayfs::OverlayGuard; use crate::disk::mount::guard::GenericMountGuard; use crate::rpc_continuations::Guid; @@ -11,14 +11,14 @@ use crate::service::effects::prelude::*; use crate::service::persistent_container::Subcontainer; use crate::util::Invoke; -#[cfg(all(feature = "pty-process", feature = "procfs"))] +#[cfg(target_os = "linux")] mod sync; -#[cfg(not(all(feature = "pty-process", feature = "procfs")))] +#[cfg(not(target_os = "linux"))] mod sync_dummy; pub use sync::*; -#[cfg(not(all(feature = "pty-process", feature = "procfs")))] +#[cfg(not(target_os = "linux"))] use sync_dummy as sync; #[derive(Debug, Deserialize, Serialize, Parser, TS)] @@ -41,7 +41,7 @@ pub async fn destroy_subcontainer_fs( .await .remove(&guid) { - #[cfg(all(feature = "pty-process", feature = "procfs"))] + #[cfg(target_os = "linux")] if tokio::fs::metadata(overlay.overlay.path().join("proc/1")) .await .is_ok() diff --git a/core/startos/src/service/effects/subcontainer/sync.rs b/core/startos/src/service/effects/subcontainer/sync.rs index 39e40243e..1fa43fcb6 100644 --- a/core/startos/src/service/effects/subcontainer/sync.rs +++ b/core/startos/src/service/effects/subcontainer/sync.rs @@ -46,7 +46,7 @@ pub fn kill_init(procfs: &Path, chroot: &Path) -> Result<(), Error> { .get(OsStr::new("pid")) .map_or(false, |ns| ns.identifier == ns_id) { - let pids = proc.read::("status").with_ctx(|_| { + let pids = proc.read::<_, NSPid>("status").with_ctx(|_| { ( ErrorKind::Filesystem, lazy_format!("read pid {} NSpid", pid), diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index e4d2ba0df..fe34c820e 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -13,10 +13,10 @@ use clap::Parser; use futures::future::BoxFuture; use futures::stream::FusedStream; use futures::{FutureExt, SinkExt, StreamExt, TryStreamExt}; -use helpers::{AtomicFile, NonDetachingJoinHandle}; +use crate::util::future::NonDetachingJoinHandle; use imbl_value::{InternedString, json}; use itertools::Itertools; -use models::{ActionId, HostId, ImageId, PackageId}; +use crate::{ActionId, HostId, ImageId, PackageId}; use nix::sys::signal::Signal; use persistent_container::{PersistentContainer, Subcontainer}; use rpc_toolkit::HandlerArgs; @@ -47,7 +47,7 @@ use crate::service::service_map::InstallProgressHandles; use crate::service::uninstall::cleanup; use crate::util::Never; use crate::util::actor::concurrent::ConcurrentActor; -use crate::util::io::{AsyncReadStream, TermSize, delete_file}; +use crate::util::io::{AsyncReadStream, AtomicFile, TermSize, delete_file}; use crate::util::net::WebSocketExt; use crate::util::serde::Pem; use crate::util::sync::SyncMutex; @@ -58,6 +58,7 @@ pub mod action; pub mod cli; pub mod effects; pub mod persistent_container; +pub mod procedure_name; mod rpc; mod service_actor; pub mod service_map; @@ -65,6 +66,7 @@ pub mod start_stop; mod transition; pub mod uninstall; +pub use procedure_name::ProcedureName; pub use service_map::ServiceMap; pub const HEALTH_CHECK_COOLDOWN_SECONDS: u64 = 15; @@ -580,16 +582,15 @@ impl Service { #[instrument(skip_all)] pub async fn backup(&self, guard: impl GenericMountGuard) -> Result<(), Error> { let id = &self.seed.id; - let mut file = AtomicFile::new(guard.path().join(id).with_extension("s9pk"), None::<&str>) - .await - .with_kind(ErrorKind::Filesystem)?; + let mut file = + AtomicFile::new(guard.path().join(id).with_extension("s9pk"), None::<&str>).await?; self.seed .persistent_container .s9pk .clone() .serialize(&mut *file, true) .await?; - file.save().await.with_kind(ErrorKind::Filesystem)?; + file.save().await?; // TODO: reverify? let backup = self .actor diff --git a/core/startos/src/service/persistent_container.rs b/core/startos/src/service/persistent_container.rs index 7a61d2d7d..5a1194945 100644 --- a/core/startos/src/service/persistent_container.rs +++ b/core/startos/src/service/persistent_container.rs @@ -5,10 +5,11 @@ use std::time::Duration; use futures::Future; use futures::future::ready; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::{Vector, vector}; use imbl_value::InternedString; -use models::{ImageId, ProcedureName, VolumeId}; +use crate::service::ProcedureName; +use crate::{ImageId, VolumeId}; use rpc_toolkit::{Empty, Server, ShutdownHandle}; use serde::de::DeserializeOwned; use tokio::process::Command; diff --git a/core/models/src/procedure_name.rs b/core/startos/src/service/procedure_name.rs similarity index 100% rename from core/models/src/procedure_name.rs rename to core/startos/src/service/procedure_name.rs diff --git a/core/startos/src/service/rpc.rs b/core/startos/src/service/rpc.rs index dc74c9843..777213443 100644 --- a/core/startos/src/service/rpc.rs +++ b/core/startos/src/service/rpc.rs @@ -7,7 +7,8 @@ use clap::builder::ValueParserFactory; use exver::{ExtendedVersion, VersionRange}; use imbl::Vector; use imbl_value::{InternedString, Value}; -use models::{FromStrParser, ProcedureName}; +use crate::service::ProcedureName; +use crate::util::FromStrParser; use rpc_toolkit::Empty; use rpc_toolkit::yajrc::RpcMethod; use ts_rs::TS; diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 46e99bba7..53ff58748 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -8,9 +8,9 @@ use exver::VersionRange; use futures::future::{BoxFuture, Fuse}; use futures::stream::FuturesUnordered; use futures::{Future, FutureExt, StreamExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use imbl::OrdMap; -use models::ErrorData; +use crate::error::ErrorData; use tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock, oneshot}; use tracing::instrument; use url::Url; diff --git a/core/startos/src/service/transition/backup.rs b/core/startos/src/service/transition/backup.rs index 8ec9fe77a..1ed404c30 100644 --- a/core/startos/src/service/transition/backup.rs +++ b/core/startos/src/service/transition/backup.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use futures::future::BoxFuture; use futures::{FutureExt, TryFutureExt}; -use models::ProcedureName; +use crate::service::ProcedureName; use rpc_toolkit::yajrc::RpcError; use crate::disk::mount::filesystem::ReadWrite; diff --git a/core/startos/src/service/uninstall.rs b/core/startos/src/service/uninstall.rs index f121a145c..4a93dff19 100644 --- a/core/startos/src/service/uninstall.rs +++ b/core/startos/src/service/uninstall.rs @@ -1,6 +1,6 @@ use std::path::Path; -use models::PackageId; +use crate::PackageId; use crate::context::RpcContext; use crate::db::model::package::{InstalledState, InstallingInfo, InstallingState, PackageState}; diff --git a/core/startos/src/sign/mod.rs b/core/startos/src/sign/mod.rs index 2c8c1289c..a685a0e62 100644 --- a/core/startos/src/sign/mod.rs +++ b/core/startos/src/sign/mod.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use ::ed25519::pkcs8::BitStringRef; use clap::builder::ValueParserFactory; use der::referenced::OwnedToRef; -use models::FromStrParser; +use crate::util::FromStrParser; use pkcs8::der::AnyRef; use pkcs8::{PrivateKeyInfo, SubjectPublicKeyInfo}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/ssh.rs b/core/startos/src/ssh.rs index c54989f37..c1bef01b7 100644 --- a/core/startos/src/ssh.rs +++ b/core/startos/src/ssh.rs @@ -4,7 +4,7 @@ use std::path::Path; use clap::Parser; use clap::builder::ValueParserFactory; use imbl_value::InternedString; -use models::FromStrParser; +use crate::util::FromStrParser; use rpc_toolkit::{Context, Empty, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::fs::OpenOptions; diff --git a/core/startos/src/status/health_check.rs b/core/startos/src/status/health_check.rs index 861954d29..8807d7a6c 100644 --- a/core/startos/src/status/health_check.rs +++ b/core/startos/src/status/health_check.rs @@ -1,8 +1,8 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; -use models::FromStrParser; -pub use models::HealthCheckId; +use crate::util::FromStrParser; +pub use crate::HealthCheckId; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/status/mod.rs b/core/startos/src/status/mod.rs index c9142c57b..9bdb987d0 100644 --- a/core/startos/src/status/mod.rs +++ b/core/startos/src/status/mod.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; use chrono::{DateTime, Utc}; -use models::{ErrorData, HealthCheckId}; +use crate::error::ErrorData; +use crate::HealthCheckId; use serde::{Deserialize, Serialize}; use ts_rs::TS; diff --git a/core/startos/src/tunnel/context.rs b/core/startos/src/tunnel/context.rs index 873aa7b8d..0e426f481 100644 --- a/core/startos/src/tunnel/context.rs +++ b/core/startos/src/tunnel/context.rs @@ -11,7 +11,7 @@ use imbl::OrdMap; use imbl_value::InternedString; use include_dir::Dir; use ipnet::Ipv4Net; -use models::GatewayId; +use crate::GatewayId; use patch_db::PatchDb; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{CallRemote, Context, Empty, ParentHandler}; diff --git a/core/startos/src/tunnel/db.rs b/core/startos/src/tunnel/db.rs index 9c6b48a7c..97353230b 100644 --- a/core/startos/src/tunnel/db.rs +++ b/core/startos/src/tunnel/db.rs @@ -8,7 +8,7 @@ use clap::Parser; use imbl::{HashMap, OrdMap}; use imbl_value::InternedString; use itertools::Itertools; -use models::GatewayId; +use crate::GatewayId; use patch_db::Dump; use patch_db::json_ptr::{JsonPointer, ROOT}; use rpc_toolkit::yajrc::RpcError; diff --git a/core/startos/src/update/mod.rs b/core/startos/src/update/mod.rs index 18d23320e..0f0923036 100644 --- a/core/startos/src/update/mod.rs +++ b/core/startos/src/update/mod.rs @@ -6,7 +6,7 @@ use clap::{ArgAction, Parser}; use color_eyre::eyre::{Result, eyre}; use exver::{Version, VersionRange}; use futures::TryStreamExt; -use helpers::{AtomicFile, NonDetachingJoinHandle}; +use crate::util::future::NonDetachingJoinHandle; use imbl_value::json; use itertools::Itertools; use patch_db::json_ptr::JsonPointer; @@ -36,6 +36,7 @@ use crate::sound::{ CIRCLE_OF_5THS_SHORT, UPDATE_FAILED_1, UPDATE_FAILED_2, UPDATE_FAILED_3, UPDATE_FAILED_4, }; use crate::util::Invoke; +use crate::util::io::AtomicFile; use crate::util::net::WebSocketExt; #[derive(Deserialize, Serialize, Parser, TS)] @@ -407,9 +408,7 @@ async fn do_update( download_phase.start(); let path = Path::new("/media/startos/images/next.squashfs"); - let mut dst = AtomicFile::new(&path, None::<&Path>) - .await - .with_kind(ErrorKind::Filesystem)?; + let mut dst = AtomicFile::new(&path, None::<&Path>).await?; let mut download_writer = download_phase.writer(&mut *dst); asset .download(ctx.client.clone(), &mut download_writer) @@ -423,7 +422,7 @@ async fn do_update( .commitment .check(&MultiCursorFile::open(&*dst).await?) .await?; - dst.save().await.with_kind(ErrorKind::Filesystem)?; + dst.save().await?; reverify_phase.complete(); finalize_phase.start(); diff --git a/core/startos/src/util/actor/concurrent.rs b/core/startos/src/util/actor/concurrent.rs index 4344f2998..111106726 100644 --- a/core/startos/src/util/actor/concurrent.rs +++ b/core/startos/src/util/actor/concurrent.rs @@ -4,7 +4,7 @@ use std::time::Duration; use futures::future::{BoxFuture, ready}; use futures::{Future, FutureExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use tokio::sync::{mpsc, oneshot}; use crate::prelude::*; diff --git a/core/startos/src/util/actor/simple.rs b/core/startos/src/util/actor/simple.rs index 7f2ad388e..e92e8e149 100644 --- a/core/startos/src/util/actor/simple.rs +++ b/core/startos/src/util/actor/simple.rs @@ -2,7 +2,7 @@ use std::time::Duration; use futures::future::ready; use futures::{Future, FutureExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; +use crate::util::future::NonDetachingJoinHandle; use tokio::sync::oneshot::error::TryRecvError; use tokio::sync::{mpsc, oneshot}; diff --git a/core/models/src/clap.rs b/core/startos/src/util/clap.rs similarity index 100% rename from core/models/src/clap.rs rename to core/startos/src/util/clap.rs diff --git a/core/models/src/data_url.rs b/core/startos/src/util/data_url.rs similarity index 97% rename from core/models/src/data_url.rs rename to core/startos/src/util/data_url.rs index f5cdcb1e4..008ae5025 100644 --- a/core/models/src/data_url.rs +++ b/core/startos/src/util/data_url.rs @@ -8,9 +8,10 @@ use reqwest::header::CONTENT_TYPE; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncRead, AsyncReadExt}; use ts_rs::TS; -use yasi::InternedString; +use imbl_value::InternedString; -use crate::{mime, Error, ErrorKind, ResultExt}; +use crate::util::mime::{mime, unmime}; +use crate::{Error, ErrorKind, ResultExt}; #[derive(Clone, TS)] #[ts(type = "string")] @@ -45,7 +46,7 @@ impl<'a> DataUrl<'a> { } pub fn canonical_ext(&self) -> Option<&'static str> { - mime::unmime(&self.mime) + unmime(&self.mime) } } impl DataUrl<'static> { diff --git a/core/startos/src/util/future.rs b/core/startos/src/util/future.rs index 4807411c8..108a7f178 100644 --- a/core/startos/src/util/future.rs +++ b/core/startos/src/util/future.rs @@ -1,15 +1,60 @@ +use std::ops::{Deref, DerefMut}; use std::pin::Pin; use std::sync::Weak; use std::task::{Context, Poll}; +use std::time::Duration; use futures::future::{BoxFuture, FusedFuture, abortable, pending}; use futures::stream::{AbortHandle, Abortable, BoxStream}; use futures::{Future, FutureExt, Stream, StreamExt}; -use tokio::sync::watch; -use tokio::task::LocalSet; +use tokio::sync::{oneshot, watch}; +use tokio::task::{JoinError, JoinHandle, LocalSet}; use crate::prelude::*; +#[pin_project::pin_project(PinnedDrop)] +pub struct NonDetachingJoinHandle(#[pin] JoinHandle); +impl NonDetachingJoinHandle { + pub async fn wait_for_abort(self) -> Result { + self.abort(); + self.await + } +} +impl From> for NonDetachingJoinHandle { + fn from(t: JoinHandle) -> Self { + NonDetachingJoinHandle(t) + } +} + +impl Deref for NonDetachingJoinHandle { + type Target = JoinHandle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for NonDetachingJoinHandle { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[pin_project::pinned_drop] +impl PinnedDrop for NonDetachingJoinHandle { + fn drop(self: std::pin::Pin<&mut Self>) { + let this = self.project(); + this.0.into_ref().get_ref().abort() + } +} +impl Future for NonDetachingJoinHandle { + type Output = Result; + fn poll( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + let this = self.project(); + this.0.poll(cx) + } +} + #[pin_project::pin_project(PinnedDrop)] pub struct DropSignaling { #[pin] @@ -223,3 +268,59 @@ impl Future for WeakFuture { } } } + +pub struct TimedResource { + handle: NonDetachingJoinHandle>, + ready: oneshot::Sender<()>, +} +impl TimedResource { + pub fn new(resource: T, timer: Duration) -> Self { + let (send, recv) = oneshot::channel(); + let handle = tokio::spawn(async move { + tokio::select! { + _ = tokio::time::sleep(timer) => { + drop(resource); + None + }, + _ = recv => Some(resource), + } + }); + Self { + handle: handle.into(), + ready: send, + } + } + + pub fn new_with_destructor< + Fn: FnOnce(T) -> Fut + Send + 'static, + Fut: Future + Send, + >( + resource: T, + timer: Duration, + destructor: Fn, + ) -> Self { + let (send, recv) = oneshot::channel(); + let handle = tokio::spawn(async move { + tokio::select! { + _ = tokio::time::sleep(timer) => { + destructor(resource).await; + None + }, + _ = recv => Some(resource), + } + }); + Self { + handle: handle.into(), + ready: send, + } + } + + pub async fn get(self) -> Option { + let _ = self.ready.send(()); + self.handle.await.unwrap() + } + + pub fn is_timed_out(&self) -> bool { + self.ready.is_closed() + } +} diff --git a/core/startos/src/util/io.rs b/core/startos/src/util/io.rs index 3c7ef4c1b..10ffd4476 100644 --- a/core/startos/src/util/io.rs +++ b/core/startos/src/util/io.rs @@ -15,9 +15,8 @@ use bytes::{Buf, BytesMut}; use clap::builder::ValueParserFactory; use futures::future::{BoxFuture, Fuse}; use futures::{FutureExt, Stream, TryStreamExt}; -use helpers::{AtomicFile, NonDetachingJoinHandle}; use inotify::{EventMask, EventStream, Inotify, WatchMask}; -use models::FromStrParser; +use crate::util::FromStrParser; use nix::unistd::{Gid, Uid}; use serde::{Deserialize, Serialize}; use tokio::fs::{File, OpenOptions}; @@ -31,6 +30,7 @@ use tokio::time::{Instant, Sleep}; use ts_rs::TS; use crate::prelude::*; +use crate::util::future::NonDetachingJoinHandle; use crate::util::sync::SyncMutex; pub trait AsyncReadSeek: AsyncRead + AsyncSeek {} @@ -1597,3 +1597,159 @@ pub fn file_string_stream( } } } + +#[pin_project::pin_project] +pub struct ByteReplacementReader { + pub replace: u8, + pub with: u8, + #[pin] + pub inner: R, +} +impl AsyncRead for ByteReplacementReader { + fn poll_read( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> std::task::Poll> { + let this = self.project(); + match this.inner.poll_read(cx, buf) { + Poll::Ready(Ok(())) => { + for idx in 0..buf.filled().len() { + if buf.filled()[idx] == *this.replace { + buf.filled_mut()[idx] = *this.with; + } + } + Poll::Ready(Ok(())) + } + a => a, + } + } +} + +pub fn to_tmp_path(path: impl AsRef) -> Result { + let path = path.as_ref(); + if let (Some(parent), Some(file_name)) = + (path.parent(), path.file_name().and_then(|f| f.to_str())) + { + Ok(parent.join(format!(".{}.tmp", file_name))) + } else { + Err(Error::new( + eyre!("invalid path: {}", path.display()), + ErrorKind::Filesystem, + )) + } +} + +pub async fn canonicalize( + path: impl AsRef + Send + Sync, + create_parent: bool, +) -> Result { + fn create_canonical_folder<'a>( + path: impl AsRef + Send + Sync + 'a, + ) -> BoxFuture<'a, Result> { + async move { + let path = canonicalize(path, true).await?; + tokio::fs::create_dir(&path) + .await + .with_ctx(|_| (ErrorKind::Filesystem, format!("mkdir {path:?}")))?; + Ok(path) + } + .boxed() + } + let path = path.as_ref(); + if tokio::fs::metadata(path).await.is_err() { + let parent = path.parent().unwrap_or(Path::new(".")); + if let Some(file_name) = path.file_name() { + if create_parent && tokio::fs::metadata(parent).await.is_err() { + return Ok(create_canonical_folder(parent).await?.join(file_name)); + } else { + return Ok(tokio::fs::canonicalize(parent) + .await + .with_ctx(|_| { + ( + ErrorKind::Filesystem, + lazy_format!("canonicalize {parent:?}"), + ) + })? + .join(file_name)); + } + } + } + tokio::fs::canonicalize(&path) + .await + .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("canonicalize {path:?}"))) +} + +pub struct AtomicFile { + tmp_path: PathBuf, + path: PathBuf, + file: Option, +} +impl AtomicFile { + pub async fn new( + path: impl AsRef + Send + Sync, + tmp_path: Option + Send + Sync>, + ) -> Result { + let path = canonicalize(&path, true).await?; + let tmp_path = if let Some(tmp_path) = tmp_path { + canonicalize(&tmp_path, true).await? + } else { + to_tmp_path(&path)? + }; + let file = File::create(&tmp_path) + .await + .with_ctx(|_| (ErrorKind::Filesystem, format!("create {tmp_path:?}")))?; + Ok(Self { + tmp_path, + path, + file: Some(file), + }) + } + + pub async fn rollback(mut self) -> Result<(), Error> { + drop(self.file.take()); + tokio::fs::remove_file(&self.tmp_path) + .await + .with_ctx(|_| (ErrorKind::Filesystem, format!("rm {:?}", self.tmp_path)))?; + Ok(()) + } + + pub async fn save(mut self) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + if let Some(file) = self.file.as_mut() { + file.flush().await?; + file.shutdown().await?; + file.sync_all().await?; + } + drop(self.file.take()); + tokio::fs::rename(&self.tmp_path, &self.path) + .await + .with_ctx(|_| { + ( + ErrorKind::Filesystem, + format!("mv {} -> {}", self.tmp_path.display(), self.path.display()), + ) + })?; + Ok(()) + } +} +impl std::ops::Deref for AtomicFile { + type Target = File; + fn deref(&self) -> &Self::Target { + self.file.as_ref().unwrap() + } +} +impl std::ops::DerefMut for AtomicFile { + fn deref_mut(&mut self) -> &mut Self::Target { + self.file.as_mut().unwrap() + } +} +impl Drop for AtomicFile { + fn drop(&mut self) { + if let Some(file) = self.file.take() { + drop(file); + let path = std::mem::take(&mut self.tmp_path); + tokio::spawn(async move { tokio::fs::remove_file(path).await.log_err() }); + } + } +} diff --git a/core/startos/src/util/lshw.rs b/core/startos/src/util/lshw.rs index df5fff5f8..425619a11 100644 --- a/core/startos/src/util/lshw.rs +++ b/core/startos/src/util/lshw.rs @@ -1,4 +1,4 @@ -use models::{Error, ResultExt}; +use crate::{Error, ResultExt}; use serde::{Deserialize, Serialize}; use tokio::process::Command; use ts_rs::TS; diff --git a/core/models/src/mime.rs b/core/startos/src/util/mime.rs similarity index 100% rename from core/models/src/mime.rs rename to core/startos/src/util/mime.rs diff --git a/core/startos/src/util/mod.rs b/core/startos/src/util/mod.rs index 772c8cd6e..df8cefb63 100644 --- a/core/startos/src/util/mod.rs +++ b/core/startos/src/util/mod.rs @@ -16,11 +16,8 @@ use color_eyre::eyre::{self, eyre}; use fd_lock_rs::FdLock; use futures::FutureExt; use futures::future::BoxFuture; -pub use helpers::NonDetachingJoinHandle; -use helpers::canonicalize; use imbl_value::InternedString; use lazy_static::lazy_static; -pub use models::VersionString; use pin_project::pin_project; use sha2::Digest; use tokio::fs::File; @@ -31,12 +28,15 @@ use ts_rs::TS; use url::Url; use crate::shutdown::Shutdown; -use crate::util::io::create_file; +use crate::util::io::{canonicalize, create_file}; use crate::util::serde::{deserialize_from_str, serialize_display}; use crate::{Error, ErrorKind, ResultExt as _}; pub mod actor; +pub mod clap; pub mod collections; +pub mod data_url; +pub mod mime; pub mod cpupower; pub mod crypto; pub mod future; @@ -48,10 +48,17 @@ pub mod lshw; pub mod net; pub mod rpc; pub mod rpc_client; +pub mod rsync; pub mod serde; // pub mod squashfs; pub mod sync; pub mod tui; +pub mod version; + +pub use clap::FromStrParser; +pub use data_url::DataUrl; +pub use mime::{mime, unmime}; +pub use version::VersionString; #[derive(Clone, Copy, Debug, ::serde::Deserialize, ::serde::Serialize)] pub enum Never {} diff --git a/core/startos/src/util/rpc_client.rs b/core/startos/src/util/rpc_client.rs index 58998afad..e80681bde 100644 --- a/core/startos/src/util/rpc_client.rs +++ b/core/startos/src/util/rpc_client.rs @@ -5,9 +5,8 @@ use std::sync::{Arc, Weak}; use futures::future::BoxFuture; use futures::{FutureExt, TryFutureExt}; -use helpers::NonDetachingJoinHandle; use lazy_async_pool::Pool; -use models::{Error, ErrorKind, ResultExt}; +use crate::{Error, ErrorKind, ResultExt}; use rpc_toolkit::yajrc::{self, Id, RpcError, RpcMethod, RpcRequest, RpcResponse}; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; @@ -16,6 +15,7 @@ use tokio::net::UnixStream; use tokio::runtime::Handle; use tokio::sync::{Mutex, OnceCell, oneshot}; +use crate::util::future::NonDetachingJoinHandle; use crate::util::io::TmpDir; type DynWrite = Box; diff --git a/core/helpers/src/rsync.rs b/core/startos/src/util/rsync.rs similarity index 96% rename from core/helpers/src/rsync.rs rename to core/startos/src/util/rsync.rs index 1ac24c8b2..fcaf11b04 100644 --- a/core/helpers/src/rsync.rs +++ b/core/startos/src/util/rsync.rs @@ -2,13 +2,15 @@ use std::path::Path; use color_eyre::eyre::eyre; use futures::StreamExt; -use models::{Error, ErrorKind}; +use crate::{Error, ErrorKind}; use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader}; use tokio::process::{Child, Command}; use tokio::sync::watch; use tokio_stream::wrappers::WatchStream; -use crate::{const_true, ByteReplacementReader, NonDetachingJoinHandle}; +use crate::util::future::NonDetachingJoinHandle; +use crate::util::io::ByteReplacementReader; +use crate::util::serde::const_true; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] @@ -85,7 +87,7 @@ impl Rsync { return Err(Error::new( eyre!("rsync command stdout is none"), ErrorKind::Filesystem, - )) + )); } Some(a) => a, }; @@ -94,7 +96,7 @@ impl Rsync { return Err(Error::new( eyre!("rsync command stderr is none"), ErrorKind::Filesystem, - )) + )); } Some(a) => a, }; @@ -143,7 +145,7 @@ impl Rsync { return Err(Error::new( eyre!("rsync stderr error: {}", err), ErrorKind::Filesystem, - )) + )); } Ok(a) => a?, }; diff --git a/core/startos/src/util/serde.rs b/core/startos/src/util/serde.rs index 2b462e5fd..82229d95b 100644 --- a/core/startos/src/util/serde.rs +++ b/core/startos/src/util/serde.rs @@ -8,7 +8,7 @@ use clap::builder::ValueParserFactory; use clap::{ArgMatches, CommandFactory, FromArgMatches}; use color_eyre::eyre::eyre; use imbl_value::imbl::OrdMap; -use models::FromStrParser; +use crate::util::FromStrParser; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{ @@ -23,6 +23,10 @@ use super::IntoDoubleEndedIterator; use crate::prelude::*; use crate::util::Apply; +pub fn const_true() -> bool { + true +} + pub fn deserialize_from_str< 'de, D: serde::de::Deserializer<'de>, diff --git a/core/models/src/version.rs b/core/startos/src/util/version.rs similarity index 100% rename from core/models/src/version.rs rename to core/startos/src/util/version.rs diff --git a/core/startos/src/version/v0_3_6_alpha_0.rs b/core/startos/src/version/v0_3_6_alpha_0.rs index d396e0c97..9ddf7c067 100644 --- a/core/startos/src/version/v0_3_6_alpha_0.rs +++ b/core/startos/src/version/v0_3_6_alpha_0.rs @@ -7,7 +7,7 @@ use const_format::formatcp; use ed25519_dalek::SigningKey; use exver::{PreReleaseSegment, VersionRange}; use imbl_value::{InternedString, json}; -use models::{HostId, Id, PackageId, ReplayId}; +use crate::{HostId, Id, PackageId, ReplayId}; use openssl::pkey::PKey; use openssl::x509::X509; use sqlx::postgres::PgConnectOptions; diff --git a/core/startos/src/version/v0_3_6_alpha_10.rs b/core/startos/src/version/v0_3_6_alpha_10.rs index 7b514bbf9..a2a2fbf28 100644 --- a/core/startos/src/version/v0_3_6_alpha_10.rs +++ b/core/startos/src/version/v0_3_6_alpha_10.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet}; use exver::{PreReleaseSegment, VersionRange}; use imbl_value::InternedString; -use models::GatewayId; +use crate::GatewayId; use serde::{Deserialize, Serialize}; use super::v0_3_5::V0_3_0_COMPAT; diff --git a/core/startos/src/version/v0_4_0_alpha_9.rs b/core/startos/src/version/v0_4_0_alpha_9.rs index e23b561a5..4f047bd74 100644 --- a/core/startos/src/version/v0_4_0_alpha_9.rs +++ b/core/startos/src/version/v0_4_0_alpha_9.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use exver::{PreReleaseSegment, VersionRange}; use imbl_value::{InOMap, InternedString}; -use models::PackageId; +use crate::PackageId; use super::v0_3_5::V0_3_0_COMPAT; use super::{VersionT, v0_4_0_alpha_8}; diff --git a/core/startos/src/volume.rs b/core/startos/src/volume.rs index 113802286..be171fd65 100644 --- a/core/startos/src/volume.rs +++ b/core/startos/src/volume.rs @@ -1,8 +1,7 @@ use std::path::{Path, PathBuf}; -pub use helpers::script_dir; -use models::PackageId; -pub use models::VolumeId; +use crate::PackageId; +pub use crate::VolumeId; use crate::prelude::*; use crate::util::VersionString;