diff --git a/Cargo.lock b/Cargo.lock index 6eb5491..d3cdbfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,9 +128,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.9.2" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" [[package]] name = "block-buffer" @@ -141,12 +141,33 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cc" +version = "1.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +dependencies = [ + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.3" @@ -213,6 +234,22 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -339,6 +376,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper", +] + [[package]] name = "futures-util" version = "0.3.31" @@ -396,6 +443,52 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "h2" version = "0.4.12" @@ -433,6 +526,7 @@ version = "0.1.0" dependencies = [ "async-trait", "clap", + "http", "jsonrpsee", "redis", "serde", @@ -507,6 +601,24 @@ dependencies = [ "pin-utils", "smallvec", "tokio", + "want", +] + +[[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", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", ] [[package]] @@ -516,13 +628,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "bytes", + "futures-channel", "futures-core", + "futures-util", "http", "http-body", "hyper", + "libc", "pin-project-lite", + "socket2", "tokio", "tower-service", + "tracing", ] [[package]] @@ -644,9 +761,9 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ "bitflags", "cfg-if", @@ -665,20 +782,81 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "jsonrpsee" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f3f48dc3e6b8bd21e15436c1ddd0bc22a6a54e8ec46fedd6adf3425f396ec6a" dependencies = [ + "jsonrpsee-client-transport", "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", "jsonrpsee-server", "jsonrpsee-types", + "jsonrpsee-wasm-client", + "jsonrpsee-ws-client", "tokio", "tracing", ] +[[package]] +name = "jsonrpsee-client-transport" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf36eb27f8e13fa93dcb50ccb44c417e25b818cfa1a481b5470cd07b19c60b98" +dependencies = [ + "base64", + "futures-channel", + "futures-util", + "gloo-net", + "http", + "jsonrpsee-core", + "pin-project", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "soketto", + "thiserror 2.0.16", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "url", +] + [[package]] name = "jsonrpsee-core" version = "0.26.0" @@ -687,6 +865,7 @@ checksum = "316c96719901f05d1137f19ba598b5fe9c9bc39f4335f67f6be8613921946480" dependencies = [ "async-trait", "bytes", + "futures-timer", "futures-util", "http", "http-body", @@ -698,10 +877,35 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "thiserror", + "thiserror 2.0.16", "tokio", + "tokio-stream", "tower", "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790bedefcec85321e007ff3af84b4e417540d5c87b3c9779b9e247d1bcc3dab8" +dependencies = [ + "base64", + "http-body", + "hyper", + "hyper-rustls", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror 2.0.16", + "tokio", + "tower", + "url", ] [[package]] @@ -736,7 +940,7 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror", + "thiserror 2.0.16", "tokio", "tokio-stream", "tokio-util", @@ -753,7 +957,33 @@ dependencies = [ "http", "serde", "serde_json", - "thiserror", + "thiserror 2.0.16", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7902885de4779f711a95d82c8da2d7e5f9f3a7c7cfa44d51c067fd1c29d72a3c" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "tower", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6fceceeb05301cc4c065ab3bd2fa990d41ff4eb44e4ca1b30fa99c057c3e79" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "tower", + "url", ] [[package]] @@ -859,6 +1089,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "parking_lot" version = "0.12.4" @@ -1064,6 +1300,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "route-recognizer" version = "0.3.1" @@ -1082,18 +1332,145 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[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 = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +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 = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + [[package]] name = "serde" version = "1.0.219" @@ -1143,6 +1520,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.6" @@ -1202,6 +1585,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.106" @@ -1230,13 +1619,33 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.16", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1291,6 +1700,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.17" @@ -1391,6 +1810,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.18.0" @@ -1404,10 +1829,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "url" -version = "2.5.5" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec961601b32b6f5d14ae8dabd35ff2ff2e2c6cb4c0e6641845ff105abe96d958" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137a3c834eaf7139b73688502f3f1141a0337c5d8e4d9b536f9b8c796e26a7c4" dependencies = [ "form_urlencoded", "idna", @@ -1432,6 +1863,25 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1447,12 +1897,138 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[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" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[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 = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.2", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "windows-link" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -1471,6 +2047,21 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1504,6 +2095,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -1516,6 +2113,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -1528,6 +2131,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1552,6 +2161,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -1564,6 +2179,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -1576,6 +2197,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -1588,6 +2215,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1689,6 +2322,12 @@ dependencies = [ "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" diff --git a/Cargo.toml b/Cargo.toml index 72a9ae6..bbf3950 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,12 @@ redis = { version = "0.32.5", features = [ "connection-manager", "aio", ] } -jsonrpsee = { version = "0.26.0", features = ["server", "macros"] } +jsonrpsee = { version = "0.26.0", features = [ + "server", + "macros", + "client", + "http-client", + "ws-client", +] } +http = "1.3.1" async-trait = "0.1.83" diff --git a/README.md b/README.md index 2a7b22f..ed1b920 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,122 @@ # herocoordinator +Supervisor JSON-RPC client + +This crate now includes a typed client to communicate with an external "supervisor" component via JSON-RPC 2.0 over HTTP and WebSocket, generated from the OpenAPI spec in `specs/supervisor.yaml`. + +Highlights +- Transports: HTTP and WebSocket (jsonrpsee). +- Session: optional bearer token support (Authorization header). +- Methods implemented: fetch_nonce, authenticate, whoami, play, create_job, start_job, run_job, get_job_status, get_job_output, get_job_logs, list_jobs, stop_job, delete_job, clear_all_jobs. +- Types mirror the spec exactly (enum casing etc.). + +Enable features + +jsonrpsee client features are enabled in Cargo.toml: +- server, macros, client, http-client, ws-client. + +Usage + +Add to your crate imports: +```rust +use herocoordinator::supervisor::{ + SupervisorClient, + ScriptType, + JobParams, +}; +``` + +Create an HTTP client (default http://127.0.0.1:9944/) +```rust +# #[tokio::main] +# async fn main() -> Result<(), Box> { +let mut client = SupervisorClient::new_http("http://127.0.0.1:9944/").await?; + +// Optional: obtain a token (out-of-band) and set it +// client.set_bearer_token("your-token").await?; + +let pk = "abcdef1234deadbeef"; +let nonce = client.fetch_nonce(pk).await?; +let ok = client.authenticate(pk, "signature-here", &nonce).await?; +assert!(ok, "authentication should succeed"); + +// whoami +let who = client.whoami().await?; +println!("whoami: {who}"); + +// play +let res = client.play(r#"echo "hello""#).await?; +println!("play.output: {}", res.output); + +// create a job +let job_id = client + .create_job(JobParams { + script: r#"print("hi")"#.into(), + script_type: ScriptType::Python, + caller_id: "cli".into(), + context_id: "demo".into(), + timeout: Some(30), + prerequisites: Some(vec![]), + }) + .await?; +println!("created job: {job_id}"); + +// start a job +let started = client.start_job(&job_id).await?; +println!("job started: {}", started.success); + +// get status / output / logs +let status = client.get_job_status(&job_id).await?; +println!("job status: {:?}", status); + +let output = client.get_job_output(&job_id).await?; +println!("job output: {output}"); + +let logs = client.get_job_logs(&job_id).await?; +println!("job logs: {:?}", logs.logs); + +// list / stop / delete / clear +let jobs = client.list_jobs().await?; +println!("jobs: {:?}", jobs); + +// stop and delete are noop if job is already finished (server-defined behavior) +let _ = client.stop_job(&job_id).await?; +let _ = client.delete_job(&job_id).await?; + +// clear all jobs (use with care) +let _ = client.clear_all_jobs().await?; +# Ok(()) +# } +``` + +Create a WebSocket client (default ws://127.0.0.1:9944/) +```rust +# #[tokio::main] +# async fn main() -> Result<(), Box> { +let client = SupervisorClient::new_ws("ws://127.0.0.1:9944/").await?; +// Use the same methods as the HTTP client +let who = client.whoami().await?; +println!("whoami: {who}"); +# Ok(()) +# } +``` + +Notes on authenticate and tokens +- The OpenAPI spec defines authenticate returning a boolean. If your deployment provides a token via a header or another method, capture it externally and set it on the client using: + - `client.set_bearer_token("...").await?` + - To remove: `client.clear_bearer_token().await?` + +Types +- Enums and DTOs mirror the OpenAPI casing: + - ScriptType: "OSIS" | "SAL" | "V" | "Python" + - JobStatus: "Dispatched" | "WaitingForPrerequisites" | "Started" | "Error" | "Finished" +- JobParams include: script, script_type, caller_id, context_id, timeout?, prerequisites?. + +Testing +- Unit tests verify enum casing and request param shapes. No live server needed. Run: `cargo test`. + +Files +- src/supervisor/mod.rs +- src/supervisor/types.rs +- src/supervisor/error.rs +- src/supervisor/client.rs diff --git a/src/lib.rs b/src/lib.rs index 7580f2c..cbf722a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,4 @@ pub mod service; mod time; pub mod dag; pub mod rpc; +pub mod supervisor; diff --git a/src/supervisor.rs b/src/supervisor.rs new file mode 100644 index 0000000..5328e61 --- /dev/null +++ b/src/supervisor.rs @@ -0,0 +1,18 @@ +// Public Supervisor client module entrypoint. +// +// Exposes: +// - SupervisorClient: high-level JSON-RPC client (HTTP/WS) +// - SupervisorError: typed error for transport and JSON-RPC envelopes +// - types::*: external DTOs and enums matching specs/supervisor.yaml +// +// Default endpoints (configurable at construction): +// - HTTP: http://127.0.0.1:9944/ +// - WS: ws://127.0.0.1:9944/ + +pub mod types; +pub mod error; +pub mod client; + +pub use client::SupervisorClient; +pub use error::SupervisorError; +pub use types::*; \ No newline at end of file diff --git a/src/supervisor/client.rs b/src/supervisor/client.rs new file mode 100644 index 0000000..b2e8063 --- /dev/null +++ b/src/supervisor/client.rs @@ -0,0 +1,388 @@ +use crate::supervisor::error::SupervisorError; +use crate::supervisor::types::*; +use http::header::{AUTHORIZATION, CONTENT_TYPE}; +use http::{HeaderMap, HeaderValue}; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::params::{ArrayParams, ObjectParams}; +use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use serde_json::Value; + +#[derive(Debug)] +enum TransportClient { + Http(HttpClient), + Ws(WsClient), +} + +/// High-level JSON-RPC client for the Supervisor (HTTP/WS). +/// +/// Defaults: +/// - HTTP: http://127.0.0.1:9944/ +/// - WS: ws://127.0.0.1:9944/ +pub struct SupervisorClient { + base_url: String, + bearer_token: Option, + inner: TransportClient, +} + +impl SupervisorClient { + // ----------------------------- + // Constructors + // ----------------------------- + + pub async fn new_http(base_url: impl Into) -> Result { + let base_url = base_url.into(); + let inner = Self::build_http(&base_url, None).await?; + Ok(Self { + base_url, + bearer_token: None, + inner: TransportClient::Http(inner), + }) + } + + pub async fn new_ws(base_url: impl Into) -> Result { + let base_url = base_url.into(); + let inner = Self::build_ws(&base_url, None).await?; + Ok(Self { + base_url, + bearer_token: None, + inner: TransportClient::Ws(inner), + }) + } + + pub async fn new_http_with_token( + base_url: impl Into, + token: impl Into, + ) -> Result { + let base_url = base_url.into(); + let token = Some(token.into()); + let inner = Self::build_http(&base_url, token.clone()).await?; + Ok(Self { + base_url, + bearer_token: token, + inner: TransportClient::Http(inner), + }) + } + + pub async fn new_ws_with_token( + base_url: impl Into, + token: impl Into, + ) -> Result { + let base_url = base_url.into(); + let token = Some(token.into()); + let inner = Self::build_ws(&base_url, token.clone()).await?; + Ok(Self { + base_url, + bearer_token: token, + inner: TransportClient::Ws(inner), + }) + } + + // ----------------------------- + // Session management + // ----------------------------- + + /// Set or replace the bearer token and rebuild the underlying client with auth header. + pub async fn set_bearer_token(&mut self, token: impl Into) -> Result<(), SupervisorError> { + let token = token.into(); + self.bearer_token = Some(token); + self.rebuild().await + } + + /// Remove the bearer token and rebuild the client without auth header. + pub async fn clear_bearer_token(&mut self) -> Result<(), SupervisorError> { + self.bearer_token = None; + self.rebuild().await + } + + async fn rebuild(&mut self) -> Result<(), SupervisorError> { + let token = self.bearer_token.clone(); + self.inner = match self.inner { + TransportClient::Http(_) => TransportClient::Http(Self::build_http(&self.base_url, token).await?), + TransportClient::Ws(_) => TransportClient::Ws(Self::build_ws(&self.base_url, token).await?), + }; + Ok(()) + } + + // ----------------------------- + // Internal builders + // ----------------------------- + + async fn build_http(base_url: &str, bearer: Option) -> Result { + let mut headers = HeaderMap::new(); + // jsonrpsee sets JSON content by default; being explicit doesn't hurt. + headers.insert( + CONTENT_TYPE, + HeaderValue::from_static("application/json; charset=utf-8"), + ); + if let Some(token) = bearer { + let val = format!("Bearer {token}"); + headers.insert( + AUTHORIZATION, + HeaderValue::from_str(&val).map_err(|e| SupervisorError::Transport(e.to_string()))?, + ); + } + let client = HttpClientBuilder::default() + .set_headers(headers) + .build(base_url) + .map_err(|e| SupervisorError::Transport(e.to_string()))?; + Ok(client) + } + + async fn build_ws(base_url: &str, bearer: Option) -> Result { + let mut headers = HeaderMap::new(); + if let Some(token) = bearer { + let val = format!("Bearer {token}"); + headers.insert( + AUTHORIZATION, + HeaderValue::from_str(&val).map_err(|e| SupervisorError::Transport(e.to_string()))?, + ); + } + let client = WsClientBuilder::default() + .set_headers(headers) + .build(base_url) + .await + .map_err(|e| SupervisorError::Transport(e.to_string()))?; + Ok(client) + } + + // ----------------------------- + // Request helper (named-object params) + // ----------------------------- + + async fn request(&self, method: &str, params: P) -> Result + where + R: DeserializeOwned, + P: Serialize, + { + let value = serde_json::to_value(params).map_err(SupervisorError::from)?; + match &self.inner { + TransportClient::Http(c) => { + match value { + Value::Object(map) => { + let mut obj = ObjectParams::new(); + for (k, v) in map { + obj.insert(k.as_str(), v).map_err(|e| SupervisorError::Transport(e.to_string()))?; + } + c.request(method, obj).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + Value::Array(arr) => { + let mut ap = ArrayParams::new(); + for v in arr { + ap.insert(v).map_err(|e| SupervisorError::Transport(e.to_string()))?; + } + c.request(method, ap).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + other => { + let mut ap = ArrayParams::new(); + ap.insert(other).map_err(|e| SupervisorError::Transport(e.to_string()))?; + c.request(method, ap).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + } + } + TransportClient::Ws(c) => { + match value { + Value::Object(map) => { + let mut obj = ObjectParams::new(); + for (k, v) in map { + obj.insert(k.as_str(), v).map_err(|e| SupervisorError::Transport(e.to_string()))?; + } + c.request(method, obj).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + Value::Array(arr) => { + let mut ap = ArrayParams::new(); + for v in arr { + ap.insert(v).map_err(|e| SupervisorError::Transport(e.to_string()))?; + } + c.request(method, ap).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + other => { + let mut ap = ArrayParams::new(); + ap.insert(other).map_err(|e| SupervisorError::Transport(e.to_string()))?; + c.request(method, ap).await.map_err(|e| SupervisorError::Transport(e.to_string())) + } + } + } + } + } + + // ----------------------------- + // API methods (specs/supervisor.yaml) + // ----------------------------- + + /// fetch_nonce(public_key) -> String + pub async fn fetch_nonce(&self, public_key: &str) -> Result { + let params = FetchNonceParams { + public_key: public_key.to_owned(), + }; + self.request("fetch_nonce", params).await + } + + /// authenticate(public_key, signature, nonce) -> bool + /// + /// Note: If your deployment provides a token out-of-band (e.g. header or subsequent call), + /// use set_bearer_token after obtaining it. + pub async fn authenticate( + &self, + public_key: &str, + signature: &str, + nonce: &str, + ) -> Result { + let params = AuthenticateParams { + public_key: public_key.to_owned(), + signature: signature.to_owned(), + nonce: nonce.to_owned(), + }; + self.request("authenticate", params).await + } + + /// whoami() -> String (JSON string with auth info) + pub async fn whoami(&self) -> Result { + let params = WhoAmIParams {}; + self.request("whoami", params).await + } + + /// play(script) -> PlayResult + pub async fn play(&self, script: &str) -> Result { + let params = PlayParams { + script: script.to_owned(), + }; + self.request("play", params).await + } + + /// create_job(job_params) -> String (job id) + pub async fn create_job(&self, job_params: JobParams) -> Result { + let params = CreateJobParams { job_params }; + self.request("create_job", params).await + } + + /// start_job(job_id) -> StartJobResult + pub async fn start_job(&self, job_id: &str) -> Result { + let params = StartJobParams { + job_id: job_id.to_owned(), + }; + self.request("start_job", params).await + } + + /// run_job(script, script_type, prerequisites?) -> String (output) + pub async fn run_job( + &self, + script: String, + script_type: ScriptType, + prerequisites: Option>, + ) -> Result { + let params = RunJobParams { + script, + script_type, + prerequisites, + }; + self.request("run_job", params).await + } + + /// get_job_status(job_id) -> JobStatus + pub async fn get_job_status(&self, job_id: &str) -> Result { + let params = GetJobIdParams { + job_id: job_id.to_owned(), + }; + self.request("get_job_status", params).await + } + + /// get_job_output(job_id) -> String + pub async fn get_job_output(&self, job_id: &str) -> Result { + let params = GetJobIdParams { + job_id: job_id.to_owned(), + }; + self.request("get_job_output", params).await + } + + /// get_job_logs(job_id) -> JobLogsResult + pub async fn get_job_logs(&self, job_id: &str) -> Result { + let params = GetJobIdParams { + job_id: job_id.to_owned(), + }; + self.request("get_job_logs", params).await + } + + /// list_jobs() -> Vec + pub async fn list_jobs(&self) -> Result, SupervisorError> { + let params = ListJobsParams {}; + self.request("list_jobs", params).await + } + + /// stop_job(job_id) -> null (maps to ()) + pub async fn stop_job(&self, job_id: &str) -> Result<(), SupervisorError> { + let params = GetJobIdParams { + job_id: job_id.to_owned(), + }; + // jsonrpsee will deserialize JSON null into unit type when expected. + self.request("stop_job", params).await + } + + /// delete_job(job_id) -> null (maps to ()) + pub async fn delete_job(&self, job_id: &str) -> Result<(), SupervisorError> { + let params = GetJobIdParams { + job_id: job_id.to_owned(), + }; + self.request("delete_job", params).await + } + + /// clear_all_jobs() -> null (maps to ()) + pub async fn clear_all_jobs(&self) -> Result<(), SupervisorError> { + let params = ClearAllJobsParams {}; + self.request("clear_all_jobs", params).await + } +} + +// Basic compilation-only tests for method signatures and param serialization. +#[cfg(test)] +mod tests { + use super::*; + use serde_json::to_value; + + #[test] + fn params_shapes() { + let _ = to_value(FetchNonceParams { + public_key: "abc".into(), + }) + .unwrap(); + let _ = to_value(AuthenticateParams { + public_key: "abc".into(), + signature: "sig".into(), + nonce: "nonce".into(), + }) + .unwrap(); + let _ = to_value(PlayParams { + script: "echo hi".into(), + }) + .unwrap(); + let _ = to_value(CreateJobParams { + job_params: JobParams { + script: "echo hi".into(), + script_type: ScriptType::SAL, + caller_id: "cli".into(), + context_id: "demo".into(), + timeout: Some(30), + prerequisites: Some(vec![]), + }, + }) + .unwrap(); + let _ = to_value(StartJobParams { + job_id: "jid".into(), + }) + .unwrap(); + let _ = to_value(RunJobParams { + script: "print(1)".into(), + script_type: ScriptType::Python, + prerequisites: None, + }) + .unwrap(); + let _ = to_value(GetJobIdParams { + job_id: "jid".into(), + }) + .unwrap(); + let _ = to_value(ListJobsParams {}).unwrap(); + let _ = to_value(ClearAllJobsParams {}).unwrap(); + } +} \ No newline at end of file diff --git a/src/supervisor/error.rs b/src/supervisor/error.rs new file mode 100644 index 0000000..347d3a6 --- /dev/null +++ b/src/supervisor/error.rs @@ -0,0 +1,37 @@ +use serde_json::Value; +use std::fmt::{Display, Formatter}; + +#[derive(Debug)] +pub enum SupervisorError { + Transport(String), + Rpc { code: i32, message: String, data: Option }, + Serde(serde_json::Error), +} + +impl Display for SupervisorError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + SupervisorError::Transport(e) => write!(f, "transport error: {e}"), + SupervisorError::Rpc { code, message, .. } => write!(f, "rpc error {code}: {message}"), + SupervisorError::Serde(e) => write!(f, "serde error: {e}"), + } + } +} + +impl std::error::Error for SupervisorError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + SupervisorError::Serde(e) => Some(e), + _ => None, + } + } +} + +impl From for SupervisorError { + fn from(e: serde_json::Error) -> Self { + SupervisorError::Serde(e) + } +} + +// Note: jsonrpsee error types differ across transports/versions; we avoid a blanket `From` impl. +// Callers map transport errors to SupervisorError::Transport at the callsite to reduce coupling. \ No newline at end of file diff --git a/src/supervisor/types.rs b/src/supervisor/types.rs new file mode 100644 index 0000000..570a878 --- /dev/null +++ b/src/supervisor/types.rs @@ -0,0 +1,190 @@ +use serde::{Deserialize, Serialize}; + +// Types mirroring specs/supervisor.yaml exactly (wire format) + +// Enums + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ScriptType { + #[serde(rename = "OSIS")] + OSIS, + #[serde(rename = "SAL")] + SAL, + #[serde(rename = "V")] + V, + #[serde(rename = "Python")] + Python, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum JobStatus { + #[serde(rename = "Dispatched")] + Dispatched, + #[serde(rename = "WaitingForPrerequisites")] + WaitingForPrerequisites, + #[serde(rename = "Started")] + Started, + #[serde(rename = "Error")] + Error, + #[serde(rename = "Finished")] + Finished, +} + +// DTOs + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JobParams { + pub script: String, + pub script_type: ScriptType, + pub caller_id: String, + pub context_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub timeout: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub prerequisites: Option>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayResult { + pub output: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StartJobResult { + pub success: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JobLogsResult { + pub logs: Option, +} + +// Params (named-object) per method + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FetchNonceParams { + pub public_key: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AuthenticateParams { + pub public_key: String, + pub signature: String, + pub nonce: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WhoAmIParams {} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PlayParams { + pub script: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CreateJobParams { + pub job_params: JobParams, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StartJobParams { + pub job_id: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RunJobParams { + pub script: String, + pub script_type: ScriptType, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub prerequisites: Option>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GetJobIdParams { + pub job_id: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct ListJobsParams {} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct ClearAllJobsParams {} + +// Conversions to/from internal models when convenient + +impl From for ScriptType { + fn from(v: crate::models::ScriptType) -> Self { + match v { + crate::models::ScriptType::Osis => ScriptType::OSIS, + crate::models::ScriptType::Sal => ScriptType::SAL, + crate::models::ScriptType::V => ScriptType::V, + crate::models::ScriptType::Python => ScriptType::Python, + } + } +} + +impl From for crate::models::ScriptType { + fn from(v: ScriptType) -> Self { + match v { + ScriptType::OSIS => crate::models::ScriptType::Osis, + ScriptType::SAL => crate::models::ScriptType::Sal, + ScriptType::V => crate::models::ScriptType::V, + ScriptType::Python => crate::models::ScriptType::Python, + } + } +} + +impl From for JobStatus { + fn from(v: crate::models::JobStatus) -> Self { + match v { + crate::models::JobStatus::Dispatched => JobStatus::Dispatched, + crate::models::JobStatus::WaitingForPrerequisites => JobStatus::WaitingForPrerequisites, + crate::models::JobStatus::Started => JobStatus::Started, + crate::models::JobStatus::Error => JobStatus::Error, + crate::models::JobStatus::Finished => JobStatus::Finished, + } + } +} + +impl From for crate::models::JobStatus { + fn from(v: JobStatus) -> Self { + match v { + JobStatus::Dispatched => crate::models::JobStatus::Dispatched, + JobStatus::WaitingForPrerequisites => crate::models::JobStatus::WaitingForPrerequisites, + JobStatus::Started => crate::models::JobStatus::Started, + JobStatus::Error => crate::models::JobStatus::Error, + JobStatus::Finished => crate::models::JobStatus::Finished, + } + } +} + +// Basic serialization tests (casing) + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::{json, to_value}; + + #[test] + fn script_type_casing() { + assert_eq!(to_value(&ScriptType::OSIS).unwrap(), json!("OSIS")); + assert_eq!(to_value(&ScriptType::SAL).unwrap(), json!("SAL")); + assert_eq!(to_value(&ScriptType::V).unwrap(), json!("V")); + assert_eq!(to_value(&ScriptType::Python).unwrap(), json!("Python")); + } + + #[test] + fn job_status_casing() { + assert_eq!(to_value(&JobStatus::Dispatched).unwrap(), json!("Dispatched")); + assert_eq!( + to_value(&JobStatus::WaitingForPrerequisites).unwrap(), + json!("WaitingForPrerequisites") + ); + assert_eq!(to_value(&JobStatus::Started).unwrap(), json!("Started")); + assert_eq!(to_value(&JobStatus::Error).unwrap(), json!("Error")); + assert_eq!(to_value(&JobStatus::Finished).unwrap(), json!("Finished")); + } +} \ No newline at end of file