diff options
author | yuzu <yuzu@b9215c17-b818-4693-b096-d1e41a411fef> | 2025-07-12 22:17:26 +0000 |
---|---|---|
committer | yuzu <yuzu@b9215c17-b818-4693-b096-d1e41a411fef> | 2025-07-12 22:17:26 +0000 |
commit | e33f9a59f875edf1240ca80c1014235296ff3cbf (patch) | |
tree | 5777c00bafad650d6be84f42f51ba4f873d92c53 | |
parent | 78608add1c69a877b76a05147f6c26b7abe66669 (diff) | |
download | salaryman-e33f9a59f875edf1240ca80c1014235296ff3cbf.tar.gz salaryman-e33f9a59f875edf1240ca80c1014235296ff3cbf.tar.bz2 salaryman-e33f9a59f875edf1240ca80c1014235296ff3cbf.zip |
add additional endpoints; change out mutexes for rwlocks
git-svn-id: svn+ssh://diminuette.aengel.lesbianunix.dev/salaryman/trunk@15 b9215c17-b818-4693-b096-d1e41a411fef
-rw-r--r-- | Cargo.lock | 811 | ||||
-rw-r--r-- | Cargo.toml | 51 | ||||
-rw-r--r-- | src/cli/main.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/model.rs | 31 | ||||
-rw-r--r-- | src/server/context.rs | 47 | ||||
-rw-r--r-- | src/server/endpoints.rs | 359 | ||||
-rw-r--r-- | src/server/main.rs (renamed from src/smd/main.rs) | 38 | ||||
-rw-r--r-- | src/smd/context.rs | 47 | ||||
-rw-r--r-- | src/smd/endpoints.rs | 205 |
10 files changed, 1321 insertions, 275 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9752728..2025dbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -83,6 +98,22 @@ dependencies = [ ] [[package]] +name = "async-compression" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd", + "zstd-safe", +] + +[[package]] name = "async-stream" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -164,6 +195,27 @@ dependencies = [ ] [[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -196,6 +248,8 @@ version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -265,6 +319,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[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 = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -290,6 +373,15 @@ dependencies = [ ] [[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] name = "crossbeam-channel" version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -361,6 +453,26 @@ dependencies = [ ] [[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] name = "dof" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -400,7 +512,7 @@ dependencies = [ "openapiv3", "paste", "percent-encoding", - "rustls", + "rustls 0.22.4", "rustls-pemfile", "schemars", "scopeguard", @@ -417,7 +529,7 @@ dependencies = [ "slog-term", "thiserror 2.0.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "toml", "usdt", "uuid", @@ -473,12 +585,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -753,6 +906,38 @@ dependencies = [ ] [[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls 0.23.29", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.2", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] name = "hyper-util" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -803,6 +988,113 @@ dependencies = [ ] [[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] name = "indexmap" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -820,6 +1112,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "is-terminal" version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -843,6 +1145,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -869,6 +1181,24 @@ dependencies = [ ] [[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] name = "lock_api" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -950,6 +1280,23 @@ dependencies = [ ] [[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1006,6 +1353,50 @@ dependencies = [ ] [[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] name = "parking_lot" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1097,12 +1488,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1124,6 +1530,22 @@ dependencies = [ ] [[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" +dependencies = [ + "idna", + "psl-types", +] + +[[package]] name = "quote" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1159,6 +1581,51 @@ dependencies = [ ] [[package]] +name = "reqwest" +version = "0.12.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +dependencies = [ + "async-compression", + "base64", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] name = "ring" version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1179,6 +1646,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] name = "rustls" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1187,7 +1667,20 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.4", "subtle", "zeroize", ] @@ -1222,6 +1715,17 @@ dependencies = [ ] [[package]] +name = "rustls-webpki" +version = "0.103.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1239,6 +1743,7 @@ version = "0.0.1" dependencies = [ "clap", "dropshot", + "reqwest", "schemars", "semver", "serde", @@ -1248,6 +1753,15 @@ dependencies = [ ] [[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] name = "schemars" version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1299,6 +1813,29 @@ dependencies = [ ] [[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1511,6 +2048,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1534,6 +2077,26 @@ dependencies = [ ] [[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1561,6 +2124,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] name = "term" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1664,6 +2240,16 @@ dependencies = [ ] [[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] name = "tokio" version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1693,17 +2279,37 @@ dependencies = [ ] [[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] name = "tokio-rustls" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls", + "rustls 0.22.4", "rustls-pki-types", "tokio", ] [[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.29", + "tokio", +] + +[[package]] name = "tokio-util" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1758,6 +2364,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] name = "tower-service" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1813,6 +2458,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] name = "usdt" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1877,6 +2533,12 @@ dependencies = [ ] [[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1895,6 +2557,12 @@ dependencies = [ ] [[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1960,6 +2628,19 @@ dependencies = [ ] [[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1992,6 +2673,16 @@ dependencies = [ ] [[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2184,6 +2875,36 @@ dependencies = [ ] [[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2205,7 +2926,89 @@ dependencies = [ ] [[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 466871a..8f07281 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,35 +6,72 @@ authors = ["Ren Kararou <[email protected]>"] description = "A very simple service management framework" [features] -default = ["smd"] +default = ["models", "smd", "sm-cli"] +models = [] smd = [ "dep:clap", "dep:dropshot", - "dep:schemars", "dep:toml", "dep:semver", + "models", +] +sm-cli = [ + "dep:clap", + "dep:toml", + "dep:reqwest", + "models", ] [dependencies] -clap = { version = "4.5.39", features = ["derive"], optional = true } -dropshot = { version = "0.16.2", features = ["usdt","usdt-probes"], optional = true } -schemars = { version = "0.8.22", features = ["uuid1"], optional = true } +schemars = { version = "0.8.22", features = ["uuid1"] } semver = { version = "1.0.26", optional = true } serde = { version = "1.0.219", features = ["derive"] } tokio = { version = "1.45.1", features = ["full"] } toml = { version = "0.8.22", optional = true } uuid = { version = "1.17.0", features = ["v4", "serde"] } +[dependencies.clap] +version = "4.5.39" +features = [ + "derive", +] +optional = true + +[dependencies.dropshot] +version = "0.16.2" +features = [ + "usdt", + "usdt-probes", +] +optional = true + +[dependencies.reqwest] +version = "0.12.22" +features = [ + "gzip", + "cookies", + "brotli", + "zstd" +] +optional = true + [[bin]] name = "smd" -path = "src/smd/main.rs" +path = "src/server/main.rs" test = false bench = false required-features = ["smd"] +[[bin]] +name = "sm" +path = "src/cli/main.rs" +test = false +bench = false +required-features = ["sm-cli"] + [profile.release] strip = true -lto = "thin" +lto = true panic = "abort" codegen-units = 1 diff --git a/src/cli/main.rs b/src/cli/main.rs new file mode 100644 index 0000000..1b85472 --- /dev/null +++ b/src/cli/main.rs @@ -0,0 +1,4 @@ +#[tokio::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 1f278a4..95486cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,4 @@ pub mod service; + +#[cfg(feature = "models")] +pub mod model; diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..578d9b4 --- /dev/null +++ b/src/model.rs @@ -0,0 +1,31 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::net::IpAddr; +use std::path::PathBuf; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, JsonSchema, Debug)] +pub struct UpdateConf { + pub address: Option<IpAddr>, + pub port: Option<u16>, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug)] +pub struct StdinBuffer { + pub stdin: String, + pub endl: Option<bool>, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug)] +pub struct ServicePath { + pub service_uuid: Uuid, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug)] +pub struct NewService { + pub name: Option<String>, + pub command: Option<String>, + pub args: Option<Option<String>>, + pub directory: Option<Option<PathBuf>>, + pub autostart: Option<bool>, +} diff --git a/src/server/context.rs b/src/server/context.rs new file mode 100644 index 0000000..132e2dc --- /dev/null +++ b/src/server/context.rs @@ -0,0 +1,47 @@ +use super::Config; +use salaryman::service::{Service, ServiceConf}; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct SalarymanService { + pub config: ServiceConf, + pub service: Arc<RwLock<Service>>, +} +impl SalarymanService { + pub fn new() -> Self { + Self { + config: ServiceConf::new(), + service: Arc::new(RwLock::new(Service::new())), + } + } + pub fn from_parts(config: ServiceConf, service: Arc<RwLock<Service>>) -> Self { + Self { config, service } + } +} + +pub struct SalarymanDContext { + pub services: RwLock<Vec<Arc<SalarymanService>>>, + pub save_file: PathBuf, + pub config: Arc<RwLock<Config>>, +} +impl SalarymanDContext { + pub fn new() -> Self { + Self { + services: RwLock::new(Vec::new()), + save_file: PathBuf::from(""), + config: Arc::new(RwLock::new(Config::new())), + } + } + pub fn from_parts( + services: RwLock<Vec<Arc<SalarymanService>>>, + save_file: PathBuf, + config: Arc<RwLock<Config>>, + ) -> Self { + Self { + services, + save_file, + config, + } + } +} diff --git a/src/server/endpoints.rs b/src/server/endpoints.rs new file mode 100644 index 0000000..8ebc42e --- /dev/null +++ b/src/server/endpoints.rs @@ -0,0 +1,359 @@ +use super::Config; +use super::context::{SalarymanDContext, SalarymanService}; +use dropshot::{HttpError, HttpResponseOk, Path, RequestContext, TypedBody, endpoint}; +use salaryman::model::{NewService, ServicePath, StdinBuffer, UpdateConf}; +use salaryman::service::{Service, ServiceConf}; +use std::sync::Arc; +use tokio::fs::File; +use tokio::io::AsyncWriteExt; +use tokio::sync::RwLock; + +#[endpoint { + method = GET, + path = "/config", +}] +pub async fn endpoint_get_config( + rqctx: RequestContext<Arc<SalarymanDContext>>, +) -> Result<HttpResponseOk<Config>, HttpError> { + let ctx = rqctx.context(); + let lock = ctx.config.read().await; + let conf = lock.clone(); + drop(lock); + Ok(HttpResponseOk(conf)) +} +#[endpoint { + method = PUT, + path = "/config", +}] +pub async fn endpoint_put_config( + rqctx: RequestContext<Arc<SalarymanDContext>>, + body: TypedBody<UpdateConf>, +) -> Result<HttpResponseOk<()>, HttpError> { + let ctx = rqctx.context(); + let update = body.into_inner(); + if let Some(addr) = update.address { + let mut lock = ctx.config.write().await; + lock.address = Some(addr); + drop(lock); + } + if let Some(port) = update.port { + let mut lock = ctx.config.write().await; + lock.port = Some(port); + drop(lock); + } + Ok(HttpResponseOk(())) +} +#[endpoint { + method = GET, + path = "/config/save" +}] +pub async fn endpoint_get_config_save( + rqctx: RequestContext<Arc<SalarymanDContext>>, +) -> Result<HttpResponseOk<()>, HttpError> { + let ctx = rqctx.context(); + let mut v: Vec<ServiceConf> = Vec::new(); + let rlock = ctx.services.read().await; + for i in 0..rlock.len() { + v.push(rlock[i].config.clone()); + } + drop(rlock); + let rlock = ctx.config.read().await; + let save = Config { + address: rlock.address, + port: rlock.port, + user: rlock.user.clone(), + service: v, + }; + drop(rlock); + let mut f = match File::open(&ctx.save_file).await { + Ok(f) => f, + Err(_) => { + return Err(HttpError::for_internal_error(String::from( + "cannot open desired file", + ))); + } + }; + let save = match toml::to_string(&save) { + Ok(s) => s, + Err(_) => { + return Err(HttpError::for_internal_error(String::from( + "cannot serialize config!", + ))); + } + }; + match f.write_all(save.as_str().as_bytes()).await { + Ok(_) => (), + Err(_) => { + return Err(HttpError::for_internal_error(String::from( + "could not write to file!", + ))); + } + } + Ok(HttpResponseOk(())) +} +#[endpoint { + method = GET, + path = "/service", +}] +pub async fn endpoint_get_services( + rqctx: RequestContext<Arc<SalarymanDContext>>, +) -> Result<HttpResponseOk<Vec<ServiceConf>>, HttpError> { + let ret = { + let ctx = rqctx.context(); + let mut v: Vec<ServiceConf> = Vec::new(); + let lock = ctx.services.read().await; + for i in 0..lock.len() { + v.push(lock[i].config.clone()); + } + v + }; + Ok(HttpResponseOk(ret)) +} +#[endpoint { + method = POST, + path = "/service", +}] +pub async fn endpoint_post_service( + rqctx: RequestContext<Arc<SalarymanDContext>>, + body: TypedBody<NewService>, +) -> Result<HttpResponseOk<ServiceConf>, HttpError> { + let ctx = rqctx.context(); + let body = body.into_inner(); + let mut s: ServiceConf = ServiceConf::new(); + if let Some(name) = &body.name { + s.name = name.clone().to_owned(); + } else { + return Err(HttpError::for_bad_request( + None, + String::from("name field is required!"), + )); + } + if let Some(command) = &body.command { + s.command = command.clone().to_owned(); + } else { + return Err(HttpError::for_bad_request( + None, + String::from("command field is required!"), + )); + } + if let Some(args) = &body.args { + if let Some(args) = args { + s.args = Some(args.clone().to_owned()); + } + } + if let Some(dir) = &body.directory { + if let Some(dir) = dir { + s.directory = Some(dir.clone().to_owned()); + } + } + if let Some(auto) = &body.autostart { + s.autostart = auto.clone().to_owned(); + } else { + s.autostart = false; + } + let service: SalarymanService = + SalarymanService::from_parts(s.clone(), Arc::new(RwLock::new(Service::from_conf(&s)))); + if service.config.autostart { + let mut lock = service.service.write().await; + match lock.start_with_output().await { + Ok(_) => (), + Err(_) => (), + } + drop(lock); + } + let mut lock = ctx.config.write().await; + lock.service.push(s.clone()); + drop(lock); + let mut lock = ctx.services.write().await; + lock.push(Arc::new(service)); + drop(lock); + Ok(HttpResponseOk(ServiceConf::new())) +} +#[endpoint { + method = GET, + path = "/service/{service_uuid}", +}] +pub async fn endpoint_get_service( + rqctx: RequestContext<Arc<SalarymanDContext>>, + path_params: Path<ServicePath>, +) -> Result<HttpResponseOk<ServiceConf>, HttpError> { + let u = path_params.into_inner().service_uuid; + let ctx = rqctx.context(); + let mut service: Option<Arc<SalarymanService>> = None; + let lock = ctx.services.read().await; + for i in 0..lock.len() { + if lock[i].config.uuid == u { + service = Some(lock[i].clone()); + } else { + continue; + } + } + let s = match service { + Some(s) => s.config.clone(), + None => { + return Err(HttpError::for_unavail( + None, + String::from("Service Not Found"), + )); + } + }; + Ok(HttpResponseOk(s)) +} +#[endpoint { + method = GET, + path = "/service/{service_uuid}/start", +}] +pub async fn endpoint_start_service( + rqctx: RequestContext<Arc<SalarymanDContext>>, + path_params: Path<ServicePath>, +) -> Result<HttpResponseOk<()>, HttpError> { + let u = path_params.into_inner().service_uuid; + let ctx = rqctx.context(); + let mut service: Option<Arc<SalarymanService>> = None; + let lock = ctx.services.read().await; + for i in 0..lock.len() { + if lock[i].config.uuid == u { + service = Some(lock[i].clone()); + } else { + continue; + } + } + match service { + Some(s) => { + let mut lock = s.service.write().await; + match lock.start_with_output().await { + Ok(_) => (), + Err(e) => return Err(HttpError::for_internal_error(e.to_string())), + } + } + None => { + return Err(HttpError::for_unavail( + None, + String::from("Service Not Found"), + )); + } + }; + Ok(HttpResponseOk(())) +} +#[endpoint { + method = GET, + path = "/service/{service_uuid}/stop", +}] +pub async fn endpoint_stop_service( + rqctx: RequestContext<Arc<SalarymanDContext>>, + path_params: Path<ServicePath>, +) -> Result<HttpResponseOk<()>, HttpError> { + let u = path_params.into_inner().service_uuid; + let ctx = rqctx.context(); + let mut service: Option<Arc<SalarymanService>> = None; + let lock = ctx.services.read().await; + for i in 0..lock.len() { + if lock[i].config.uuid == u { + service = Some(lock[i].clone()); + } else { + continue; + } + } + match service { + Some(s) => { + let mut lock = s.service.write().await; + match lock.stop().await { + Ok(_) => (), + Err(e) => return Err(HttpError::for_internal_error(e.to_string())), + } + } + None => { + return Err(HttpError::for_unavail( + None, + String::from("Service Not Found"), + )); + } + }; + Ok(HttpResponseOk(())) +} +#[endpoint { + method = GET, + path = "/service/{service_uuid}/restart", +}] +pub async fn endpoint_restart_service( + rqctx: RequestContext<Arc<SalarymanDContext>>, + path_params: Path<ServicePath>, +) -> Result<HttpResponseOk<()>, HttpError> { + let u = path_params.into_inner().service_uuid; + let ctx = rqctx.context(); + let mut service: Option<Arc<SalarymanService>> = None; + let lock = ctx.services.read().await; + for i in 0..lock.len() { + if lock[i].config.uuid == u { + service = Some(lock[i].clone()); + } else { + continue; + } + } + match service { + Some(s) => { + let mut lock = s.service.write().await; + match lock.restart_with_output().await { + Ok(_) => (), + Err(e) => return Err(HttpError::for_internal_error(e.to_string())), + } + } + None => { + return Err(HttpError::for_unavail( + None, + String::from("Service Not Found"), + )); + } + }; + Ok(HttpResponseOk(())) +} +#[endpoint { + method = PUT, + path = "/service/{service_uuid}/write" +}] +pub async fn endpoint_post_stdin( + rqctx: RequestContext<Arc<SalarymanDContext>>, + path_params: Path<ServicePath>, + update: TypedBody<StdinBuffer>, +) -> Result<HttpResponseOk<()>, HttpError> { + let ctx = rqctx.context(); + let stdin_str = update.into_inner(); + let u = path_params.into_inner().service_uuid; + let mut service: Option<Arc<SalarymanService>> = None; + let lock = ctx.services.read().await; + for i in 0..lock.len() { + if lock[i].config.uuid == u { + service = Some(lock[i].clone()); + } else { + continue; + } + } + match service { + Some(s) => { + let mut lock = s.service.write().await; + if lock.started().await { + let b = if let Some(endl) = stdin_str.endl { + if endl { + lock.writeln_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! + } else { + lock.write_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! + } + } else { + lock.writeln_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! + }; + match b { + Ok(_) => (), + Err(e) => return Err(HttpError::for_internal_error(e.to_string())), + } + } + drop(lock); + } + None => { + return Err(HttpError::for_unavail( + None, + String::from("Service Not Found"), + )); + } + } + Ok(HttpResponseOk(())) +} diff --git a/src/smd/main.rs b/src/server/main.rs index b81df2f..7557145 100644 --- a/src/smd/main.rs +++ b/src/server/main.rs @@ -6,7 +6,7 @@ use dropshot::{ApiDescription, ConfigDropshot, ConfigLogging, ConfigLoggingLevel use salaryman::service::{Service, ServiceConf}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use tokio::{fs::read_to_string, sync::Mutex}; +use tokio::{fs::read_to_string, sync::RwLock}; use std::{ net::{IpAddr, SocketAddr}, @@ -16,7 +16,8 @@ use std::{ use crate::context::{SalarymanDContext, SalarymanService}; use crate::endpoints::{ - endpoint_get_service, endpoint_get_services, endpoint_post_stdin, endpoint_restart_service, + endpoint_get_config, endpoint_get_config_save, endpoint_get_service, endpoint_get_services, + endpoint_post_service, endpoint_post_stdin, endpoint_put_config, endpoint_restart_service, endpoint_start_service, endpoint_stop_service, }; @@ -107,26 +108,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { args.port }; let bind = SocketAddr::new(addr, port); - let mut services: Vec<Arc<SalarymanService>> = Vec::new(); + let services: RwLock<Vec<Arc<SalarymanService>>> = RwLock::new(Vec::new()); for i in 0..conf.service.len() { - services.push(Arc::new(SalarymanService::from_parts( + let mut lock = services.write().await; + lock.push(Arc::new(SalarymanService::from_parts( conf.service[i].clone(), - Arc::new(Mutex::new(Service::from_conf(&conf.service[i]))), + Arc::new(RwLock::new(Service::from_conf(&conf.service[i]))), ))); + drop(lock); } - for i in 0..services.len() { - if services[i].config.autostart { - let mut lock = services[i].service.lock().await; - lock.start().await?; - lock.scan_stdout().await?; - lock.scan_stderr().await?; + let lock = services.write().await; + for i in 0..lock.len() { + if lock[i].config.autostart { + let mut l = lock[i].service.write().await; + l.start().await?; + l.scan_stdout().await?; + l.scan_stderr().await?; + drop(l); } } + drop(lock); let log_conf = ConfigLogging::StderrTerminal { level: ConfigLoggingLevel::Info, }; let log = log_conf.to_logger("smd")?; - let ctx = Arc::new(SalarymanDContext::from_vec(services)); + let ctx = Arc::new(SalarymanDContext::from_parts( + services, + args.config, + Arc::new(RwLock::new(conf)), + )); let config = ConfigDropshot { bind_address: bind, ..Default::default() @@ -138,6 +148,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { api.register(endpoint_stop_service)?; api.register(endpoint_restart_service)?; api.register(endpoint_post_stdin)?; + api.register(endpoint_post_service)?; + api.register(endpoint_get_config)?; + api.register(endpoint_put_config)?; + api.register(endpoint_get_config_save)?; api.openapi("Salaryman", semver::Version::new(1, 0, 0)) .write(&mut std::io::stdout())?; let server = ServerBuilder::new(api, ctx.clone(), log) diff --git a/src/smd/context.rs b/src/smd/context.rs deleted file mode 100644 index 5d8038c..0000000 --- a/src/smd/context.rs +++ /dev/null @@ -1,47 +0,0 @@ -use salaryman::service::{Service, ServiceConf}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use tokio::sync::Mutex; -use uuid::Uuid; - -pub struct SalarymanService { - pub config: ServiceConf, - pub service: Arc<Mutex<Service>>, -} -impl SalarymanService { - pub fn new() -> Self { - Self { - config: ServiceConf::new(), - service: Arc::new(Mutex::new(Service::new())), - } - } - pub fn from_parts(config: ServiceConf, service: Arc<Mutex<Service>>) -> Self { - Self { config, service } - } -} - -pub struct SalarymanDContext { - pub services: Vec<Arc<SalarymanService>>, -} -impl SalarymanDContext { - pub fn new() -> Self { - Self { - services: Vec::new(), - } - } - pub fn from_vec(services: Vec<Arc<SalarymanService>>) -> Self { - Self { services } - } -} - -#[derive(Serialize, Deserialize, JsonSchema, Debug)] -pub struct StdinBuffer { - pub stdin: String, - pub endl: Option<bool>, -} - -#[derive(Serialize, Deserialize, JsonSchema, Debug)] -pub struct ServicePath { - pub service_uuid: Uuid, -} diff --git a/src/smd/endpoints.rs b/src/smd/endpoints.rs deleted file mode 100644 index f0ba0ea..0000000 --- a/src/smd/endpoints.rs +++ /dev/null @@ -1,205 +0,0 @@ -use super::context::{SalarymanDContext, SalarymanService, ServicePath, StdinBuffer}; -use dropshot::{HttpError, HttpResponseOk, Path, RequestContext, TypedBody, endpoint}; -use salaryman::service::ServiceConf; -use std::sync::Arc; - -#[endpoint { - method = GET, - path = "/service", -}] -pub async fn endpoint_get_services( - rqctx: RequestContext<Arc<SalarymanDContext>>, -) -> Result<HttpResponseOk<Vec<ServiceConf>>, HttpError> { - let ret = { - let ctx = rqctx.context(); - let mut v: Vec<ServiceConf> = Vec::new(); - for i in 0..ctx.services.len() { - v.push(ctx.services[i].config.clone()); - } - v - }; - Ok(HttpResponseOk(ret)) -} -#[endpoint { - method = GET, - path = "/service/{service_uuid}", -}] -pub async fn endpoint_get_service( - rqctx: RequestContext<Arc<SalarymanDContext>>, - path_params: Path<ServicePath>, -) -> Result<HttpResponseOk<ServiceConf>, HttpError> { - let u = path_params.into_inner().service_uuid; - let ctx = rqctx.context(); - let mut service: Option<Arc<SalarymanService>> = None; - for i in 0..ctx.services.len() { - if ctx.services[i].config.uuid == u { - service = Some(ctx.services[i].clone()); - } else { - continue; - } - } - let s = match service { - Some(s) => s.config.clone(), - None => { - return Err(HttpError::for_unavail( - None, - String::from("Service Not Found"), - )); - } - }; - Ok(HttpResponseOk(s)) -} -#[endpoint { - method = GET, - path = "/service/{service_uuid}/start", -}] -pub async fn endpoint_start_service( - rqctx: RequestContext<Arc<SalarymanDContext>>, - path_params: Path<ServicePath>, -) -> Result<HttpResponseOk<()>, HttpError> { - let u = path_params.into_inner().service_uuid; - let ctx = rqctx.context(); - let mut service: Option<Arc<SalarymanService>> = None; - for i in 0..ctx.services.len() { - if ctx.services[i].config.uuid == u { - service = Some(ctx.services[i].clone()); - } else { - continue; - } - } - match service { - Some(s) => { - let mut lock = s.service.lock().await; - match lock.start_with_output().await { - Ok(_) => (), - Err(e) => return Err(HttpError::for_internal_error(e.to_string())), - } - } - None => { - return Err(HttpError::for_unavail( - None, - String::from("Service Not Found"), - )); - } - }; - Ok(HttpResponseOk(())) -} -#[endpoint { - method = GET, - path = "/service/{service_uuid}/stop", -}] -pub async fn endpoint_stop_service( - rqctx: RequestContext<Arc<SalarymanDContext>>, - path_params: Path<ServicePath>, -) -> Result<HttpResponseOk<()>, HttpError> { - let u = path_params.into_inner().service_uuid; - let ctx = rqctx.context(); - let mut service: Option<Arc<SalarymanService>> = None; - for i in 0..ctx.services.len() { - if ctx.services[i].config.uuid == u { - service = Some(ctx.services[i].clone()); - } else { - continue; - } - } - match service { - Some(s) => { - let mut lock = s.service.lock().await; - match lock.stop().await { - Ok(_) => (), - Err(e) => return Err(HttpError::for_internal_error(e.to_string())), - } - } - None => { - return Err(HttpError::for_unavail( - None, - String::from("Service Not Found"), - )); - } - }; - Ok(HttpResponseOk(())) -} -#[endpoint { - method = GET, - path = "/service/{service_uuid}/restart", -}] -pub async fn endpoint_restart_service( - rqctx: RequestContext<Arc<SalarymanDContext>>, - path_params: Path<ServicePath>, -) -> Result<HttpResponseOk<()>, HttpError> { - let u = path_params.into_inner().service_uuid; - let ctx = rqctx.context(); - let mut service: Option<Arc<SalarymanService>> = None; - for i in 0..ctx.services.len() { - if ctx.services[i].config.uuid == u { - service = Some(ctx.services[i].clone()); - } else { - continue; - } - } - match service { - Some(s) => { - let mut lock = s.service.lock().await; - match lock.restart_with_output().await { - Ok(_) => (), - Err(e) => return Err(HttpError::for_internal_error(e.to_string())), - } - } - None => { - return Err(HttpError::for_unavail( - None, - String::from("Service Not Found"), - )); - } - }; - Ok(HttpResponseOk(())) -} -#[endpoint { - method = PUT, - path = "/service/{service_uuid}/write" -}] -pub async fn endpoint_post_stdin( - rqctx: RequestContext<Arc<SalarymanDContext>>, - path_params: Path<ServicePath>, - update: TypedBody<StdinBuffer>, -) -> Result<HttpResponseOk<()>, HttpError> { - let ctx = rqctx.context(); - let stdin_str = update.into_inner(); - let u = path_params.into_inner().service_uuid; - let mut service: Option<Arc<SalarymanService>> = None; - for i in 0..ctx.services.len() { - if ctx.services[i].config.uuid == u { - service = Some(ctx.services[i].clone()); - } else { - continue; - } - } - match service { - Some(s) => { - let mut lock = s.service.lock().await; - if lock.started().await { - let b = if let Some(endl) = stdin_str.endl { - if endl { - lock.writeln_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! - } else { - lock.write_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! - } - } else { - lock.writeln_stdin(stdin_str.stdin.clone()).await //TODO: PROPERLY HANDLE ERROR! - }; - match b { - Ok(_) => (), - Err(e) => return Err(HttpError::for_internal_error(e.to_string())), - } - } - drop(lock); - } - None => { - return Err(HttpError::for_unavail( - None, - String::from("Service Not Found"), - )); - } - } - Ok(HttpResponseOk(())) -} |