diff --git a/.gitignore b/.gitignore index 80fad13..559270f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target .env +.idea diff --git a/Cargo.lock b/Cargo.lock index a376a6f..b5012ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,17 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -37,54 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "amq-protocol" -version = "7.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a41c091e49edfcc098b4f90d4d7706a8cf9158034e84ebfee7ff346092f67c" -dependencies = [ - "amq-protocol-tcp", - "amq-protocol-types", - "amq-protocol-uri", - "cookie-factory", - "nom", - "serde", -] - -[[package]] -name = "amq-protocol-tcp" -version = "7.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed7a4a662472f88823ed2fc81babb0b00562f2c54284e3e7bffc02b6df649bf" -dependencies = [ - "amq-protocol-uri", - "tcp-stream", - "tracing", -] - -[[package]] -name = "amq-protocol-types" -version = "7.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6484fdc918c1b6e2ae8eda2914d19a5873e1975f93ad8d33d6a24d1d98df05" -dependencies = [ - "cookie-factory", - "nom", - "serde", - "serde_json", -] - -[[package]] -name = "amq-protocol-uri" -version = "7.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7f2da69e0e1182765bf33407cd8a843f20791b5af2b57a2645818c4776c56c" -dependencies = [ - "amq-protocol-types", - "percent-encoding", - "url", -] - [[package]] name = "anstream" version = "0.6.18" @@ -137,228 +78,46 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] -name = "asn1-rs" -version = "0.7.1" +name = "async-nats" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +checksum = "08f6da6d49a956424ca4e28fe93656f790d748b469eaccbc7488fec545315180" dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", + "base64", + "bytes", + "futures", + "memchr", + "nkeys", + "nuid", + "once_cell", + "pin-project", + "portable-atomic", + "rand", + "regex", + "ring", + "rustls-native-certs", + "rustls-pemfile", + "rustls-webpki 0.102.8", + "serde", + "serde_json", + "serde_nanos", + "serde_repr", "thiserror", "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.0", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io 2.4.0", - "async-lock 3.4.0", - "blocking", - "futures-lite 2.6.0", - "once_cell", -] - -[[package]] -name = "async-global-executor" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io 2.4.0", - "async-lock 3.4.0", - "blocking", - "futures-lite 2.6.0", -] - -[[package]] -name = "async-global-executor-trait" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce" -dependencies = [ - "async-global-executor 3.1.0", - "async-trait", - "executor-trait", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.28", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.0", - "parking", - "polling 3.7.4", - "rustix 0.38.44", - "slab", + "tokio", + "tokio-rustls", + "tokio-util", + "tokio-websockets", "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.4.0", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-reactor-trait" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" -dependencies = [ - "async-io 1.13.0", - "async-trait", - "futures-core", - "reactor-trait", -] - -[[package]] -name = "async-std" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor 2.4.1", - "async-io 2.4.0", - "async-lock 3.4.0", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 2.6.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", + "tryhard", + "url", ] -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.88" @@ -439,7 +198,27 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", +] + +[[package]] +name = "base" +version = "0.0.0" +dependencies = [ + "anyhow", + "async-nats", + "async-trait", + "code0-definition-reader 0.0.8", + "code0-flow", + "futures-lite", + "http 0.0.0", + "prost 0.14.1", + "tokio", + "tonic 0.14.1", + "tonic-health", + "tucana 0.0.33", + "uuid", + "validator", ] [[package]] @@ -454,12 +233,6 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.9.0" @@ -475,28 +248,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite 2.6.0", - "piper", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -508,14 +259,8 @@ name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "serde", ] [[package]] @@ -534,44 +279,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cipher" -version = "0.4.4" +name = "code0-definition-reader" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "d3823dd8c9a5a8efec3934080920c8d10b8043637a5c8fdfc86c5fc34942e20a" dependencies = [ - "crypto-common", - "inout", + "serde", + "serde_json", + "tucana 0.0.32", ] [[package]] -name = "cms" -version = "0.2.3" +name = "code0-definition-reader" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" +checksum = "6bcdd7feee37f0c422c01e2192df7149401ae2ff0d1529a43e1c3d03ac37c779" dependencies = [ - "const-oid", - "der", - "spki", - "x509-cert", + "serde", + "serde_json", + "tucana 0.0.33", ] [[package]] name = "code0-flow" -version = "0.0.13" +version = "0.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2b4e3ce2fb62521a5fc6825074525cc88269218e4919c1e4d3a9a83ba197b" +checksum = "ee41dc45b3e7f21db03db69796b3070eb26d5fa3a462b60c1cc07e9b949c933b" dependencies = [ + "async-nats", "async-trait", + "code0-definition-reader 0.0.9", "dotenv", - "futures-lite 2.6.0", - "lapin", + "futures-core", "log", - "redis", - "serde", - "serde_json", - "tokio", - "tonic", - "tucana", + "tonic 0.14.1", + "tonic-health", + "tucana 0.0.33", ] [[package]] @@ -580,41 +323,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "cookie-factory" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" - [[package]] name = "core-foundation" version = "0.9.4" @@ -640,12 +354,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crypto-common" version = "0.1.6" @@ -656,6 +364,32 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "data-encoding" version = "2.8.0" @@ -669,37 +403,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", - "der_derive", - "flagset", "pem-rfc7468", "zeroize", ] -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "der_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "deranged" version = "0.4.1" @@ -707,15 +414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" dependencies = [ "powerfmt", -] - -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", + "serde", ] [[package]] @@ -726,7 +425,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", - "subtle", ] [[package]] @@ -740,18 +438,34 @@ dependencies = [ "syn", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "dotenv" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "signature", + "subtle", +] + [[package]] name = "either" version = "1.15.0" @@ -797,56 +511,17 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener 5.4.0", - "pin-project-lite", -] - -[[package]] -name = "executor-trait" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c39dff9342e4e0e16ce96be751eb21a94e94a87bb2f6e63ad1961c2ce109bf" -dependencies = [ - "async-trait", -] - [[package]] name = "fastrand" -version = "1.9.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "fastrand" -version = "2.3.0" +name = "fiat-crypto" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fixedbitset" @@ -854,23 +529,6 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" -[[package]] -name = "flagset" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" - -[[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - [[package]] name = "fnv" version = "1.0.7" @@ -886,6 +544,20 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -893,6 +565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -909,26 +582,11 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand 2.3.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -953,9 +611,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1000,18 +661,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "h2" version = "0.4.8" @@ -1043,33 +692,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "http" version = "0.0.0" @@ -1078,7 +700,7 @@ dependencies = [ "log", "serde_json", "tokio", - "tucana", + "tucana 0.0.33", ] [[package]] @@ -1330,43 +952,13 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "io-uring" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cfg-if", "libc", ] @@ -1417,51 +1009,14 @@ dependencies = [ ] [[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 = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lapin" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733db9f169f8dba4b89582230ceb029b80b9576437e265dbfe0c71f8438ea6bf" -dependencies = [ - "amq-protocol", - "async-global-executor-trait", - "async-reactor-trait", - "async-trait", - "executor-trait", - "flume", - "futures-core", - "futures-io", - "parking_lot", - "pinky-swear", - "reactor-trait", - "serde", - "tracing", - "waker-fn", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" +name = "js-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "libc" @@ -1469,18 +1024,6 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.9.3" @@ -1493,24 +1036,11 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -dependencies = [ - "value-bag", -] [[package]] name = "matchit" @@ -1530,12 +1060,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.5" @@ -1563,23 +1087,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] -name = "nom" -version = "7.1.3" +name = "nkeys" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "879011babc47a1c7fdf5a935ae3cfe94f34645ca0cac1c7f6424b36fc743d1bf" dependencies = [ - "memchr", - "minimal-lexical", + "data-encoding", + "ed25519", + "ed25519-dalek", + "getrandom 0.2.15", + "log", + "rand", + "signatory", ] [[package]] -name = "num-bigint" -version = "0.4.6" +name = "nuid" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "fc895af95856f929163a0aa20c26a78d26bfdc839f51b9d5aa7a5b79e52b7e83" dependencies = [ - "num-integer", - "num-traits", + "rand", ] [[package]] @@ -1588,24 +1116,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "object" version = "0.36.7" @@ -1615,15 +1125,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1636,67 +1137,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "p12-keystore" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cae83056e7cb770211494a0ecf66d9fa7eba7d00977e5bb91f0e925b40b937f" -dependencies = [ - "cbc", - "cms", - "der", - "des", - "hex", - "hmac", - "pkcs12", - "pkcs5", - "rand", - "rc2", - "sha1", - "sha2", - "thiserror", - "x509-parser", -] - [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1755,89 +1201,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pinky-swear" -version = "6.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" -dependencies = [ - "doc-comment", - "flume", - "parking_lot", - "tracing", -] - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - -[[package]] -name = "pkcs12" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695b3df3d3cc1015f12d70235e35b6b79befc5fa7a9b95b951eab1dd07c9efc2" -dependencies = [ - "cms", - "const-oid", - "der", - "digest", - "spki", - "x509-cert", - "zeroize", -] - -[[package]] -name = "pkcs5" -version = "0.7.1" +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "aes", - "cbc", "der", - "pbkdf2", - "scrypt", - "sha2", "spki", ] -[[package]] -name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.44", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "portable-atomic" version = "1.11.0" @@ -1894,7 +1266,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.5", +] + +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive 0.14.1", ] [[package]] @@ -1910,8 +1292,30 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost", - "prost-types", + "prost 0.13.5", + "prost-types 0.13.5", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-build" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.14.1", + "prost-types 0.14.1", + "pulldown-cmark", + "pulldown-cmark-to-cmark", "regex", "syn", "tempfile", @@ -1931,111 +1335,99 @@ dependencies = [ ] [[package]] -name = "prost-types" -version = "0.13.5" +name = "prost-derive" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ - "prost", + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "quote" -version = "1.0.40" +name = "prost-types" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" dependencies = [ - "proc-macro2", + "prost 0.13.5", ] [[package]] -name = "r-efi" -version = "5.2.0" +name = "prost-types" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +dependencies = [ + "prost 0.14.1", +] [[package]] -name = "rand" -version = "0.9.0" +name = "pulldown-cmark" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "rand_chacha", - "rand_core", - "zerocopy", + "bitflags", + "memchr", + "unicase", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "pulldown-cmark-to-cmark" +version = "21.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "e5b6a0769a491a08b31ea5c62494a8f144ee0987d86d670a8af4df1e1b7cde75" dependencies = [ - "ppv-lite86", - "rand_core", + "pulldown-cmark", ] [[package]] -name = "rand_core" -version = "0.9.3" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "getrandom 0.3.2", + "proc-macro2", ] [[package]] -name = "rc2" -version = "0.8.1" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" -dependencies = [ - "cipher", -] +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] -name = "reactor-trait" -version = "1.1.0" +name = "rand" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "438a4293e4d097556730f4711998189416232f009c137389e0f961d2bc0ddc58" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "async-trait", - "futures-core", - "futures-io", + "libc", + "rand_chacha", + "rand_core", ] [[package]] -name = "redis" -version = "0.31.0" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bc1ea653e0b2e097db3ebb5b7f678be339620b8041f66b30a308c1d45d36a7f" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "async-std", - "bytes", - "cfg-if", - "combine", - "futures-util", - "itoa", - "num-bigint", - "percent-encoding", - "pin-project-lite", - "ryu", - "serde", - "serde_json", - "sha1_smol", - "socket2 0.5.9", - "tokio", - "tokio-util", - "url", + "ppv-lite86", + "rand_core", ] [[package]] -name = "redox_syscall" -version = "0.5.10" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "bitflags 2.9.0", + "getrandom 0.2.15", ] [[package]] @@ -2071,16 +1463,19 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" name = "rest" version = "0.1.0" dependencies = [ + "anyhow", + "base", "code0-flow", "env_logger", "http 0.0.0", "log", + "prost 0.14.1", "regex", "serde", "serde_json", "tokio", - "tonic", - "tucana", + "tonic 0.14.1", + "tucana 0.0.33", "uuid", "validator", ] @@ -2106,39 +1501,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - -[[package]] -name = "rustix" -version = "0.37.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.44" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "semver", ] [[package]] @@ -2147,10 +1515,10 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys", "windows-sys 0.59.0", ] @@ -2168,19 +1536,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-connector" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a980454b497c439c274f2feae2523ed8138bbd3d323684e1435fec62f800481" -dependencies = [ - "log", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "rustls-webpki 0.102.8", -] - [[package]] name = "rustls-native-certs" version = "0.7.3" @@ -2215,7 +1570,6 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring", "rustls-pki-types", "untrusted", ] @@ -2239,18 +1593,9 @@ checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "salsa20" -version = "0.10.2" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" @@ -2261,30 +1606,13 @@ 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 = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2", -] - [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -2301,6 +1629,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -2334,21 +1668,24 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.6" +name = "serde_nanos" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a93142f0367a4cc53ae0fead1bcda39e85beccfad3dcd717656cacab94b12985" dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "serde", ] [[package]] -name = "sha1_smol" -version = "1.0.1" +name = "serde_repr" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "sha2" @@ -2367,6 +1704,37 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signatory" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e303f8205714074f6068773f0e29527e0453937fe837c9717d066635b65f31" +dependencies = [ + "pkcs8", + "rand_core", + "signature", + "zeroize", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.9" @@ -2382,16 +1750,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.9" @@ -2412,15 +1770,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "spki" version = "0.7.3" @@ -2471,45 +1820,33 @@ dependencies = [ "syn", ] -[[package]] -name = "tcp-stream" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495b0abdce3dc1f8fd27240651c9e68890c14e9d9c61527b1ce44d8a5a7bd3d5" -dependencies = [ - "cfg-if", - "p12-keystore", - "rustls-connector", - "rustls-pemfile", -] - [[package]] name = "tempfile" version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "fastrand 2.3.0", + "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.5", + "rustix", "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "2.0.12" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -2569,6 +1906,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "slab", "socket2 0.6.0", "tokio-macros", @@ -2586,6 +1924,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" @@ -2595,6 +1943,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -2610,6 +1959,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-websockets" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591660438b3038dd04d16c938271c79e7e06260ad2ea2885a4861bfb238605d" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-sink", + "http 1.3.1", + "httparse", + "rand", + "ring", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tokio-util", + "webpki-roots 0.26.11", +] + [[package]] name = "tonic" version = "0.13.1" @@ -2629,7 +1999,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", + "prost 0.13.5", "socket2 0.5.9", "tokio", "tokio-stream", @@ -2639,6 +2009,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac5a8627ada0968acec063a4746bf79588aa03ccb66db2f75d7dce26722a40" +dependencies = [ + "async-trait", + "axum", + "base64", + "bytes", + "h2", + "http 1.3.1", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2 0.6.0", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tonic-build" version = "0.13.0" @@ -2647,10 +2046,62 @@ checksum = "d85f0383fadd15609306383a90e85eaed44169f931a5d2be1b42c76ceff1825e" dependencies = [ "prettyplease", "proc-macro2", - "prost-build", - "prost-types", + "prost-build 0.13.5", + "prost-types 0.13.5", + "quote", + "syn", +] + +[[package]] +name = "tonic-build" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e323d8bba3be30833707e36d046deabf10a35ae8ad3cae576943ea8933e25d" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tonic-health" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8aa31379f0851de4f223496a469ffcaae24ad4ce736493179c3e42135e2af5c" +dependencies = [ + "prost 0.14.1", + "tokio", + "tokio-stream", + "tonic 0.14.1", + "tonic-prost", +] + +[[package]] +name = "tonic-prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c511b9a96d40cb12b7d5d00464446acf3b9105fd3ce25437cfe41c92b1c87d" +dependencies = [ + "bytes", + "prost 0.14.1", + "tonic 0.14.1", +] + +[[package]] +name = "tonic-prost-build" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ef298fcd01b15e135440c4b8c974460ceca4e6a5af7f1c933b08e4d2875efa1" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build 0.14.1", + "prost-types 0.14.1", "quote", "syn", + "tempfile", + "tonic-build 0.14.1", ] [[package]] @@ -2721,18 +2172,43 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tryhard" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fe58ebd5edd976e0fe0f8a14d2a04b7c81ef153ea9a54eebc42e67c2c23b4e5" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tucana" -version = "0.0.28" +version = "0.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7694d43cff47f6464cf502b67f7f5c6da1b1e05f0693dda755e5eff8deeeaa" +checksum = "8c117a81c52831392910672d37b18b6784167c37e42b055cc5281417dc82002e" dependencies = [ - "prost", - "prost-types", + "prost 0.13.5", + "prost-types 0.13.5", "serde", "serde_json", - "tonic", - "tonic-build", + "tonic 0.13.1", + "tonic-build 0.13.0", +] + +[[package]] +name = "tucana" +version = "0.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "811247bdfb777b65329d9f8e8ff9e2d405261ef626e149997f4fca57bfe106d4" +dependencies = [ + "prost 0.14.1", + "prost-types 0.14.1", + "serde", + "serde_json", + "tonic 0.14.1", + "tonic-prost", + "tonic-prost-build", ] [[package]] @@ -2741,6 +2217,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -2800,27 +2282,15 @@ dependencies = [ "regex", "serde", "serde_json", - "tucana", + "tucana 0.0.33", ] -[[package]] -name = "value-bag" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" - [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "want" version = "0.3.1" @@ -2871,19 +2341,6 @@ dependencies = [ "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" @@ -2917,44 +2374,21 @@ 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" +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "webpki-roots 1.0.2", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" +name = "webpki-roots" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ - "windows-targets 0.48.5", + "rustls-pki-types", ] [[package]] @@ -2963,7 +2397,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2972,22 +2406,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2996,46 +2415,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3048,48 +2449,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3102,7 +2479,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags", ] [[package]] @@ -3117,34 +2494,6 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "x509-cert" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" -dependencies = [ - "const-oid", - "der", - "spki", -] - -[[package]] -name = "x509-parser" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror", - "time", -] - [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index cfec66b..c44d4b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,14 @@ [workspace] -members = ["crates/http", "crates/validator", "adapter/rest"] +members = ["crates/http", "crates/validator", "adapter/rest", "crates/base"] +resolver = "3" [workspace.package] version = "0.0.0" -edition = "2021" +edition = "2024" [workspace.dependencies] -code0-flow = { version = "0.0.13" } -tucana = { version = "0.0.28", features = ["aquila"] } +code0-flow = { version = "0.0.14" } +tucana = { version = "0.0.33", features = ["aquila"] } serde_json = { version = "1.0.138" } serde = "1.0.219" log = "0.4.27" @@ -18,10 +19,20 @@ quote = "1.0" proc-macro2 = "1.0" tokio = { version = "1.44.1", features = ["rt-multi-thread"] } uuid = { version = "1.16.0", features = ["v4"] } -tonic = "0.13.0" +tonic = "0.14.0" +async-nats = "0.42.0" +async-trait = "0.1.88" +anyhow = "1.0.98" +code0-definition-reader = "0.0.8" +prost = "0.14.0" +tonic-health = "0.14.0" +futures-lite = "2.6.1" [workspace.dependencies.http] path = "../draco/crates/http" [workspace.dependencies.validator] path = "../draco/crates/validator" + +[workspace.dependencies.base] +path = "../draco/crates/base" diff --git a/GUIDE.md b/GUIDE.md new file mode 100644 index 0000000..e35ee3f --- /dev/null +++ b/GUIDE.md @@ -0,0 +1,170 @@ +# Adapter Creation Guide + +A quick guide to building custom adapter servers for the Draco framework. + +## What is an Adapter? + +An adapter is a server that: +- Listens for requests (HTTP, gRPC, etc.) +- Matches requests to validation flows +- Executes flows and returns results + +## Quick Start + +### 1. Create Your Project Structure +``` +my-adapter/ +├── Cargo.toml +└── src/ + └── main.rs +``` + +### 2. Add Dependencies +Add these to your `Cargo.toml`: +- `base` - Core Draco functionality +- `tokio` - Async runtime +- `async-trait` - Async trait support +- Your protocol library (e.g., `hyper` for HTTP) + +### 3. Main Entry Point + +```rust +#[tokio::main] +async fn main() { + let server = MyAdapter::new(); + let runner = ServerRunner::new(server).await.unwrap(); + runner.serve().await.unwrap(); +} +``` + +### 4. Configuration Struct + +```rust +#[derive(Clone)] +struct MyAdapterConfig { + port: u16, + // Add other settings +} + +impl LoadConfig for MyAdapterConfig { + fn load() -> Self { + Self { + port: env_with_default("MY_ADAPTER_PORT", 8080), + // Load other settings from environment + } + } +} +``` + +### 5. Server Implementation + +```rust +struct MyAdapter { + // Your protocol server instance + protocol_server: Option, +} + +#[async_trait] +impl ServerTrait for MyAdapter { + async fn init(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { + // Initialize your protocol server with config + self.protocol_server = Some(MyProtocolServer::new(ctx.server_config.port)); + Ok(()) + } + + async fn run(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { + if let Some(server) = &mut self.protocol_server { + // Register request handler + server.register_handler({ + let store = Arc::clone(&ctx.adapter_store); + move |request| { + let store = Arc::clone(&store); + async move { + handle_request(request, store).await + } + } + }); + + // Start your protocol server + server.start().await; + } + Ok(()) + } + + async fn shutdown(&mut self, _ctx: &ServerContext) -> anyhow::Result<()> { + if let Some(server) = &self.protocol_server { + server.shutdown(); + } + Ok(()) + } +} +``` + +### 6. Flow Matcher + +```rust +struct MyRequestMatcher { + // Store request details that help identify flows + path: String, + method: String, +} + +impl IdentifiableFlow for MyRequestMatcher { + fn identify(&self, flow: &ValidationFlow) -> bool { + // Extract expected values from flow settings + let expected_path = extract_flow_setting_field( + &flow.settings, + "REQUEST_PATH", + "path" + ); + + // Check if this request matches the flow + match expected_path.as_deref() { + Some(pattern) => { + // Use regex or simple matching + regex::Regex::new(pattern) + .map(|r| r.is_match(&self.path)) + .unwrap_or(false) + } + None => false, + } + } +} +``` + +### 7. Request Handler + +```rust +async fn handle_request(request: MyRequest, store: Arc) -> MyResponse { + // Create pattern for flow matching + let pattern = format!("*.*.{}.{}.{}", + "MY_PROTOCOL", + request.host, + request.method); + + // Create matcher with request details + let matcher = MyRequestMatcher { + path: request.path.clone(), + method: request.method.clone(), + }; + + // Find matching flows + match store.get_possible_flow_match(pattern, matcher).await { + FlowIdenfiyResult::Single(flow) => { + // Execute the flow + match store.validate_and_execute_flow(flow, request.body).await { + Some(result) => { + // Convert result to your protocol response format + create_success_response(result) + } + None => { + create_error_response("Flow execution failed") + } + } + } + _ => { + create_error_response("No matching flow found") + } + } +} +``` diff --git a/adapter/rest/Cargo.toml b/adapter/rest/Cargo.toml index a8e3913..c9271cc 100644 --- a/adapter/rest/Cargo.toml +++ b/adapter/rest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rest" version = "0.1.0" -edition = "2021" +edition.workspace = true [dependencies] http = { workspace = true } @@ -16,3 +16,6 @@ env_logger = { workspace = true } uuid = { workspace = true } regex = { workspace = true } tonic = { workspace = true } +base = { workspace = true } +anyhow = { workspace = true } +prost = { workspace = true } diff --git a/adapter/rest/src/.env b/adapter/rest/src/.env index 9575770..9e508bb 100644 --- a/adapter/rest/src/.env +++ b/adapter/rest/src/.env @@ -1,4 +1,4 @@ -PORT=8081 +HTTP_PORT=8081 REDIS_URL=redis://localhost:6379 RABBITMQ_URL=amqp://localhost:5672 AQUILA_URL=http://localhost:8080 diff --git a/adapter/rest/src/config/mod.rs b/adapter/rest/src/config/mod.rs deleted file mode 100644 index 938bef1..0000000 --- a/adapter/rest/src/config/mod.rs +++ /dev/null @@ -1,51 +0,0 @@ -use code0_flow::flow_config::{env_with_default, environment::Environment, mode::Mode}; - -/// Struct for all relevant `Draco` startup configurations -pub struct Config { - /// Options: - /// `development` (default) - /// `staging` - /// `production` - pub environment: Environment, - - /// Aquila mode - /// - /// Options: - /// `static` (default) - /// `hybrid` - pub mode: Mode, - - /// URL to the Redis Server. - /// Default none - pub redis_url: String, - - /// Verification Token required for internal communication - pub rabbitmq_url: String, - - /// URL to the `Sagittarius` Server. - pub aquila_url: String, - - /// Port for the HTTP server - pub port: u16, -} - -/// Implementation for all relevant `Aquila` startup configurations -/// -/// Behavior: -/// Searches for the env. file at root level. Filename: `.env` -impl Config { - pub fn new() -> Self { - Config { - environment: env_with_default("ENVIRONMENT", Environment::Development), - mode: env_with_default("MODE", Mode::STATIC), - redis_url: env_with_default("REDIS_URL", String::from("redis://localhost:6379")), - rabbitmq_url: env_with_default("RABBITMQ_URL", String::from("amqp://localhost:5672")), - aquila_url: env_with_default("AQUILA_URL", String::from("http://localhost:8080")), - port: env_with_default("PORT", 8080), - } - } - - pub fn is_static(&self) -> bool { - self.mode == Mode::STATIC - } -} diff --git a/adapter/rest/src/main.rs b/adapter/rest/src/main.rs index b13e3ca..11bb7cc 100644 --- a/adapter/rest/src/main.rs +++ b/adapter/rest/src/main.rs @@ -1,80 +1,122 @@ -mod config; -pub mod queue; -pub mod store; -mod types; - -use code0_flow::{ - flow_config::mode::Mode, - flow_queue::service::RabbitmqClient, - flow_store::{ - connection::create_flow_store_connection, - service::{FlowStoreService, FlowStoreServiceBase}, - }, -}; -use http::{ - request::HttpRequest, - response::HttpResponse, - server::{self, AsyncHandler}, +use base::{ + extract_flow_setting_field, + runner::{ServerContext, ServerRunner}, + store::FlowIdenfiyResult, + traits::{IdentifiableFlow, LoadConfig, Server as ServerTrait}, }; -use queue::queue::handle_connection; -use std::{future::Future, pin::Pin, sync::Arc}; -use tokio::sync::Mutex; -use types::{get_data_types, get_flow_types}; +use code0_flow::flow_config::env_with_default; +use http::{request::HttpRequest, response::HttpResponse, server::Server}; +use std::collections::HashMap; +use std::sync::Arc; +use tonic::async_trait; +use tucana::shared::ValidationFlow; + +#[tokio::main] +async fn main() { + let server = HttpServer { http_server: None }; + let runner = ServerRunner::new(server).await.unwrap(); + runner.serve().await.unwrap(); +} -use crate::config::Config; +struct HttpServer { + http_server: Option, +} -pub struct FlowConnectionHandler { - flow_store: Arc>, - rabbitmq_client: Arc, +struct RequestRoute { + url: String, } -impl FlowConnectionHandler { - pub async fn new(config: &Config) -> Self { - let flow_store = create_flow_store_connection(config.redis_url.clone()).await; - let flow_store_service = Arc::new(Mutex::new(FlowStoreServiceBase::new(flow_store).await)); +impl IdentifiableFlow for RequestRoute { + fn identify(&self, flow: &ValidationFlow) -> bool { + let url = extract_flow_setting_field(&flow.settings, "HTTP_URL", "url"); + let regex_str = match url.as_deref() { + Some(s) => s, + None => return false, + }; - let rabbitmq_client = Arc::new(RabbitmqClient::new(config.rabbitmq_url.as_str()).await); - FlowConnectionHandler { - flow_store: flow_store_service, - rabbitmq_client, + match regex::Regex::new(regex_str) { + Ok(regex) => regex.is_match(&self.url), + Err(err) => { + log::error!("Failed to compile regex: {}", err); + false + } } } } -impl AsyncHandler for FlowConnectionHandler { - fn handle( - &self, - request: HttpRequest, - ) -> Pin> + Send + 'static>> { - let flow_store = self.flow_store.clone(); - let rabbitmq_client = self.rabbitmq_client.clone(); - Box::pin(async move { handle_connection(request, flow_store, rabbitmq_client).await }) +#[async_trait] +impl ServerTrait for HttpServer { + async fn init(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { + self.http_server = Some(Server::new(ctx.server_config.port)); + Ok(()) } -} -#[tokio::main] -async fn main() { - env_logger::Builder::from_default_env() - .filter_level(log::LevelFilter::Debug) - .init(); + async fn run(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { + if let Some(server) = &mut self.http_server { + server.register_async_closure({ + let store = Arc::clone(&ctx.adapter_store); + move |request: HttpRequest| { + let store = Arc::clone(&store); + async move { + let pattern = format!("*.*.REST.{}.{:?}", request.host, request.method); + let route = RequestRoute { + url: request.path.clone(), + }; - code0_flow::flow_config::load_env_file(); + match store.get_possible_flow_match(pattern, route).await { + FlowIdenfiyResult::Single(flow) => { + execute_flow(flow, request, store).await + } + _ => Some(HttpResponse::internal_server_error( + format!("No flow found for path: {}", request.path), + HashMap::new(), + )), + } + } + } + }); - log::info!("Starting Draco REST server"); - let config = Config::new(); + server.start().await; + } + Ok(()) + } - if !config.is_static() { - let update_client = - code0_flow::flow_definition::FlowUpdateService::from_url(config.aquila_url.clone()) - .with_data_types(get_data_types()) - .with_flow_types(get_flow_types()); + async fn shutdown(&mut self, _ctx: &ServerContext) -> anyhow::Result<()> { + if let Some(server) = &self.http_server { + server.shutdown(); + } + Ok(()) + } +} - update_client.send().await; +async fn execute_flow( + flow: ValidationFlow, + request: HttpRequest, + store: Arc, +) -> Option { + match store.validate_and_execute_flow(flow, request.body).await { + Some(result) => { + let json = serde_json::to_vec_pretty(&result).unwrap_or_else(|err| { + format!(r#"{{"error": "Serialization failed: {}"}}"#, err).into_bytes() + }); + Some(HttpResponse::ok(json, HashMap::new())) + } + None => Some(HttpResponse::internal_server_error( + "Flow execution failed".to_string(), + HashMap::new(), + )), } +} - let mut server = server::Server::new(config.port); +#[derive(Clone)] +struct HttpServerConfig { + port: u16, +} - let handler = FlowConnectionHandler::new(&config).await; - server.register_handler(handler); - server.start().await +impl LoadConfig for HttpServerConfig { + fn load() -> Self { + Self { + port: env_with_default("HTTP_SERVER_PORT", 8082), + } + } } diff --git a/adapter/rest/src/queue/mod.rs b/adapter/rest/src/queue/mod.rs deleted file mode 100644 index 1760005..0000000 --- a/adapter/rest/src/queue/mod.rs +++ /dev/null @@ -1,151 +0,0 @@ -pub mod queue { - - use code0_flow::{ - flow_queue::service::{Message, RabbitmqClient}, - flow_store::service::FlowStoreService, - }; - use http::{request::HttpRequest, response::HttpResponse}; - use std::{collections::HashMap, sync::Arc, time::Duration}; - use tokio::sync::Mutex; - use tucana::shared::{Struct, Value}; - use validator::verify_flow; - - use crate::store::store::check_flow_exists; - - fn create_rest_message(message_content: String) -> Message { - Message { - message_type: code0_flow::flow_queue::service::MessageType::ExecuteFlow, - sender: code0_flow::flow_queue::service::Sender { - name: "draco_rest".to_string(), - protocol: "HTTP".to_string(), - version: "1.1".to_string(), - }, - timestamp: std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs() as i64, - message_id: uuid::Uuid::new_v4().to_string(), - body: message_content, - } - } - - pub async fn handle_connection( - mut request: HttpRequest, - flow_store: Arc>, - rabbitmq_client: Arc, - ) -> Option { - // Check if a flow exists for the given settings, return none if not exsist for http handler - let flow_exists = check_flow_exists(flow_store, &request).await; - - let flow_result = match flow_exists { - Some(flow) => flow, - None => return None, - }; - - let flow = flow_result.flow; - let regex_pattern = flow_result.regex_pattern; - let mut url_params: HashMap = HashMap::new(); - - //Resolve url params - let capture_keys = regex_pattern.capture_names(); - if let Some(captures) = regex_pattern.captures(&request.path) { - for key_option in capture_keys { - let key = match key_option { - Some(key) => key, - None => continue, - }; - - let value = match captures.name(key) { - Some(value) => value.as_str().to_string(), - None => continue, - }; - - let string_value = Value { - kind: Some(tucana::shared::value::Kind::StringValue(value)), - }; - - url_params.insert(key.to_string(), string_value); - } - }; - - //Will add the url params to the request body - if !url_params.is_empty() { - if let Some(body) = &mut request.body { - if let Some(kind) = &mut body.kind { - match kind { - tucana::shared::value::Kind::StructValue(struct_value) => { - struct_value.fields.insert( - "url".to_string(), - Value { - kind: Some(tucana::shared::value::Kind::StructValue(Struct { - fields: url_params, - })), - }, - ); - } - _ => {} - } - } - } - } - - if let Some(body) = &request.body { - // Verify the rules of a Flow - this is only possible if a body exists - if let Err(err) = verify_flow(flow.clone(), body.clone()) { - return Some(HttpResponse::bad_request(err.to_string(), HashMap::new())); - } - } - - // Serialize flow - let json_flow = match serde_json::to_string(&flow) { - Ok(string) => string, - Err(err) => { - return Some(HttpResponse::internal_server_error( - err.to_string(), - HashMap::new(), - )) - } - }; - - // Create and serialize message - let message = create_rest_message(json_flow); - let message_json = match serde_json::to_string(&message) { - Ok(string) => string, - Err(err) => { - return Some(HttpResponse::internal_server_error( - err.to_string(), - HashMap::new(), - )) - } - }; - - // Send message to RabbitMQ - match rabbitmq_client - .send_message(message_json.clone(), "send_queue") - .await - { - Ok(_) => println!("Message sent to RabbitMQ queue {}", message_json), - Err(e) => println!("Failed to send message to RabbitMQ: {:?}", e), - }; - - // Wait for response - match rabbitmq_client - .await_message( - "recieve_queue", - message.message_id, - Duration::from_secs(10), - true, - ) - .await - { - Ok(response) => Some(HttpResponse::ok( - response.body.as_bytes().to_vec(), - HashMap::new(), - )), - Err(_) => Some(HttpResponse::internal_server_error( - "Failed to receive message from RabbitMQ".to_string(), - HashMap::new(), - )), - } - } -} diff --git a/adapter/rest/src/store/mod.rs b/adapter/rest/src/store/mod.rs deleted file mode 100644 index 51bd938..0000000 --- a/adapter/rest/src/store/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -pub mod store { - use std::sync::Arc; - - use code0_flow::flow_store::service::{FlowStoreService, FlowStoreServiceBase}; - use http::request::HttpRequest; - use regex::Regex; - use tokio::sync::Mutex; - use tucana::shared::{value::Kind, Flow, FlowSetting}; - - //The regex is required for later purposes --> resolve the parameter of the url - pub struct FlowExistResult { - pub flow: Flow, - pub regex_pattern: Regex, - } - - fn extract_field(settings: &[FlowSetting], def_key: &str, field_name: &str) -> Option { - settings.iter().find_map(|setting| { - let def = setting.definition.as_ref()?; - if def.key != def_key { - return None; - } - - let obj = setting.object.as_ref()?; - obj.fields.iter().find_map(|(k, v)| { - if k == field_name { - if let Some(Kind::StringValue(s)) = &v.kind { - return Some(s.clone()); - } - } - None - }) - }) - } - - pub async fn check_flow_exists( - flow_store: Arc>, - request: &HttpRequest, - ) -> Option { - let flows = { - let mut store = flow_store.lock().await; - let pattern = format!("*::*::{}::{}", request.host, request.method.to_string()); - let result = store.query_flows(pattern).await; - - match result { - Ok(flows) => flows.flows, - Err(_) => return None, - } - }; - - for flow in flows { - let url = extract_field(&flow.settings, "HTTP_URL", "url"); - - let regex_str = match url { - Some(string) => string, - None => continue, - }; - - let regex = match regex::Regex::new(®ex_str) { - Ok(regex) => regex, - Err(err) => { - log::error!("Failed to compile regex: {}", err); - continue; - } - }; - - if regex.is_match(&request.path) { - return Some(FlowExistResult { - flow, - regex_pattern: regex, - }); - } - } - None - } -} diff --git a/adapter/rest/src/types.rs b/adapter/rest/src/types.rs deleted file mode 100644 index cceaf2c..0000000 --- a/adapter/rest/src/types.rs +++ /dev/null @@ -1,200 +0,0 @@ -use tucana::shared::{ - data_type_identifier::Type, data_type_rule::Config, value::Kind, DataType, - DataTypeContainsKeyRuleConfig, DataTypeContainsTypeRuleConfig, DataTypeIdentifier, - DataTypeRegexRuleConfig, DataTypeRule, FlowType, Translation, Value, -}; - -pub fn get_flow_types() -> Vec { - vec![FlowType { - identifier: String::from("REST"), - settings: vec![], - input_type_identifier: Some(String::from("HTTP_REQUEST_OBJECT")), - return_type_identifier: Some(String::from("HTTP_RESPONSE_OBJECT")), - editable: true, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("Rest Endpoint"), - }], - description: vec![Translation { - code: String::from("en-US"), - content: String::from("A REST API is a web service that lets clients interact with data on a server using standard HTTP methods like GET, POST, PUT, and DELETE, usually returning results in JSON format."), - }], - documentation: vec![Translation { - code: String::from("en-US"), - content: String::from("A REST API is a web service that lets clients interact with data on a server using standard HTTP methods like GET, POST, PUT, and DELETE, usually returning results in JSON format."), - }], - }] -} - -pub fn get_data_types() -> Vec { - vec![ - DataType { - variant: 2, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Method"), - }], - identifier: String::from("HTTP_METHOD"), - parent_type_identifier: None, - rules: vec![DataTypeRule { - config: Some(Config::ItemOfCollection( - tucana::shared::DataTypeItemOfCollectionRuleConfig { - items: vec![ - Value { - kind: Some(Kind::StringValue(String::from("GET"))), - }, - Value { - kind: Some(Kind::StringValue(String::from("POST"))), - }, - Value { - kind: Some(Kind::StringValue(String::from("PUT"))), - }, - Value { - kind: Some(Kind::StringValue(String::from("DELETE"))), - }, - Value { - kind: Some(Kind::StringValue(String::from("PATCH"))), - }, - Value { - kind: Some(Kind::StringValue(String::from("HEAD"))), - }, - ], - }, - )), - }], - generic_keys: vec![], - }, - DataType { - variant: 2, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Route"), - }], - identifier: String::from("HTTP_URL"), - parent_type_identifier: None, - rules: vec![DataTypeRule { - config: Some(Config::Regex(DataTypeRegexRuleConfig { - pattern: String::from(r"/^\/\w+(?:[.:~-]\w+)*(?:\/\w+(?:[.:~-]\w+)*)*$/"), - })), - }], - generic_keys: vec![], - }, - DataType { - variant: 5, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Headers"), - }], - identifier: String::from("HTTP_HEADER_MAP"), - parent_type_identifier: Some(String::from("ARRAY")), - rules: vec![DataTypeRule { - config: Some(Config::ContainsType(DataTypeContainsTypeRuleConfig { - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("HTTP_HEADER_ENTRY"))), - }), - })), - }], - generic_keys: vec![], - }, - DataType { - variant: 3, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Header Entry"), - }], - identifier: String::from("HTTP_HEADER_ENTRY"), - parent_type_identifier: Some(String::from("OBJECT")), - rules: vec![ - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("key"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("TEXT"))), - }), - })), - }, - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("value"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("TEXT"))), - }), - })), - }, - ], - generic_keys: vec![], - }, - DataType { - variant: 3, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Request"), - }], - identifier: String::from("HTTP_REQUEST_OBJECT"), - parent_type_identifier: Some(String::from("OBJECT")), - rules: vec![ - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("method"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("HTTP_METHOD"))), - }), - })), - }, - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("url"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("HTTP_URL"))), - }), - })), - }, - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("body"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("OBJECT"))), - }), - })), - }, - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("headers"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("HTTP_HEADER_MAP"))), - }), - })), - }, - ], - generic_keys: vec![], - }, - DataType { - variant: 3, - name: vec![Translation { - code: String::from("en-US"), - content: String::from("HTTP Response"), - }], - identifier: String::from("HTTP_RESPONSE_OBJECT"), - parent_type_identifier: Some(String::from("OBJECT")), - rules: vec![ - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("body"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("OBJECT"))), - }), - })), - }, - DataTypeRule { - config: Some(Config::ContainsKey(DataTypeContainsKeyRuleConfig { - key: String::from("headers"), - data_type_identifier: Some(DataTypeIdentifier { - r#type: Some(Type::DataTypeIdentifier(String::from("HTTP_HEADER_MAP"))), - }), - })), - }, - ], - generic_keys: vec![], - }, - ] -} diff --git a/crates/base/Cargo.toml b/crates/base/Cargo.toml new file mode 100644 index 0000000..5557428 --- /dev/null +++ b/crates/base/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "base" +version.workspace = true +edition.workspace = true + +[dependencies] +async-nats = { workspace = true } +tucana = { workspace = true } +tokio = { workspace = true, features = ["signal"] } +async-trait = { workspace = true } +code0-flow = { workspace = true } +anyhow = { workspace = true } +code0-definition-reader = { workspace = true } +tonic = { workspace = true } +tonic-health = { workspace = true } +validator = { workspace = true } +uuid = { workspace = true } +prost = { workspace = true } +http = { workspace = true } +futures-lite = { workspace = true } diff --git a/crates/base/src/config.rs b/crates/base/src/config.rs new file mode 100644 index 0000000..8a4da21 --- /dev/null +++ b/crates/base/src/config.rs @@ -0,0 +1,89 @@ +use code0_flow::flow_config::environment::Environment; +use code0_flow::flow_config::mode::Mode; + +/// Service Configuration +/// This configuration holds the setup for every Adapter. +/// If your Adapter needs more configuration, implement the `LoadConfig` trait. +pub struct AdapterConfig { + /// Service Environment + pub environment: Environment, + + /// STATIC: + /// The service will start with no Sagittarius in mind. + /// No Aquila connection will be established. + /// + /// DYNAMIC: + /// The service will start with Sagittarius in mind. + /// Aquila connection will be established. + pub mode: Mode, + + /// NATS URL + /// + /// URL of the NATS server to connect to. + pub nats_url: String, + + /// NATS Bucket + /// + /// Name of the NATS bucket to use. + pub nats_bucket: String, + + /// GRPC Port + /// + /// Port on which the adapter's Health Service server will listen. + pub grpc_port: u16, + + /// Aquila URL + /// + /// URL of the Aquila server to connect to. + pub aquila_url: String, + + /// Definition Path + /// + /// Path to the root definition folder. + pub definition_path: String, + + /// Is Monitored + /// + /// If true the Adapter will expose a grpc health service server. + pub is_monitored: bool, +} + +impl AdapterConfig { + pub fn from_env() -> Self { + let nats_url = code0_flow::flow_config::env_with_default( + "NATS_URL", + String::from("nats://localhost:4222"), + ); + let nats_bucket = + code0_flow::flow_config::env_with_default("NATS_BUCKET", String::from("flow_store")); + let grpc_port = code0_flow::flow_config::env_with_default("GRPC_PORT", 50051); + let aquila_url = code0_flow::flow_config::env_with_default( + "AQUILA_URL", + String::from("grpc://localhost:50051"), + ); + + let environment = + code0_flow::flow_config::env_with_default("ENVIRONMENT", Environment::Development); + let mode = code0_flow::flow_config::env_with_default("MODE", Mode::STATIC); + let definition_path = code0_flow::flow_config::env_with_default( + "DEFINITION_PATH", + String::from("./definition.yaml"), + ); + let is_monitored = code0_flow::flow_config::env_with_default("IS_MONITORED", false); + + Self { + environment, + nats_bucket, + mode, + nats_url, + grpc_port, + aquila_url, + definition_path, + is_monitored, + } + } + + pub fn is_static(&self) -> bool { + self.mode == Mode::STATIC + } +} diff --git a/crates/base/src/lib.rs b/crates/base/src/lib.rs new file mode 100644 index 0000000..5765fda --- /dev/null +++ b/crates/base/src/lib.rs @@ -0,0 +1,28 @@ +use tucana::shared::{FlowSetting, value::Kind}; + +pub mod config; +pub mod runner; +pub mod store; +pub mod traits; + +pub fn extract_flow_setting_field( + settings: &Vec, + def_key: &str, + field_name: &str, +) -> Option { + settings.iter().find_map(|setting| { + if setting.flow_setting_id != def_key { + return None; + } + + let obj = setting.object.as_ref()?; + obj.fields.iter().find_map(|(k, v)| { + if k == field_name { + if let Some(Kind::StringValue(s)) = &v.kind { + return Some(s.clone()); + } + } + None + }) + }) +} diff --git a/crates/base/src/runner.rs b/crates/base/src/runner.rs new file mode 100644 index 0000000..d449353 --- /dev/null +++ b/crates/base/src/runner.rs @@ -0,0 +1,98 @@ +use crate::{ + config::AdapterConfig, + store::AdapterStore, + traits::{LoadConfig, Server as AdapterServer}, +}; +use code0_flow::flow_definition::FlowUpdateService; +use std::sync::Arc; +use tokio::sync::broadcast; +use tonic::transport::Server; +use tonic_health::pb::health_server::HealthServer; + +/// Context passed to adapter server implementations containing all shared resources +pub struct ServerContext { + pub server_config: Arc, + pub adapter_config: Arc, + pub adapter_store: Arc, +} + +/// Main server runner that manages the complete adapter lifecycle +pub struct ServerRunner { + context: ServerContext, + server: Box>, + shutdown_sender: broadcast::Sender<()>, +} + +impl ServerRunner { + pub async fn new>(server: S) -> anyhow::Result { + code0_flow::flow_config::load_env_file(); + + let adapter_config = AdapterConfig::from_env(); + let server_config = C::load(); + let adapter_store = AdapterStore::from_url( + adapter_config.nats_url.clone(), + adapter_config.nats_bucket.clone(), + ) + .await; + + let context = ServerContext { + adapter_store: Arc::new(adapter_store), + adapter_config: Arc::new(adapter_config), + server_config: Arc::new(server_config), + }; + + let (shutdown_tx, _) = broadcast::channel(1); + + Ok(Self { + context, + server: Box::new(server), + shutdown_sender: shutdown_tx, + }) + } + + pub async fn serve(mut self) -> anyhow::Result<()> { + let config = self.context.adapter_config.clone(); + + if !config.is_static() { + let definition_service = FlowUpdateService::from_url( + config.aquila_url.clone(), + config.definition_path.as_str(), + ); + definition_service.send().await; + } + + if config.is_monitored { + let health_service = + code0_flow::flow_health::HealthService::new(config.nats_url.clone()); + let address = format!("127.0.0.1:{}", config.grpc_port).parse()?; + + tokio::spawn(async move { + let _ = Server::builder() + .add_service(HealthServer::new(health_service)) + .serve(address) + .await; + }); + + println!("Health server started at 127.0.0.1:{}", config.grpc_port); + } + + self.server.init(&self.context).await?; + + let mut rx = self.shutdown_sender.subscribe(); + let context = self.context; + let mut server = self.server; + + let handle = tokio::spawn(async move { + tokio::select! { + result = server.run(&context) => result, + _ = rx.recv() => server.shutdown(&context).await, + } + }); + + tokio::signal::ctrl_c().await?; + let _ = self.shutdown_sender.send(()); + handle.await??; + + Ok(()) + } +} diff --git a/crates/base/src/store.rs b/crates/base/src/store.rs new file mode 100644 index 0000000..f85532d --- /dev/null +++ b/crates/base/src/store.rs @@ -0,0 +1,175 @@ +use crate::traits::IdentifiableFlow; +use async_nats::jetstream::kv::Config; +use futures_lite::StreamExt; +use prost::Message; +use tucana::shared::{ExecutionFlow, ValidationFlow, Value}; +use validator::verify_flow; + +pub struct AdapterStore { + client: async_nats::Client, + kv: async_nats::jetstream::kv::Store, +} + +pub enum FlowIdenfiyResult { + None, + Single(ValidationFlow), + Multiple(Vec), +} + +impl AdapterStore { + pub async fn from_url(url: String, bucket: String) -> Self { + let client = match async_nats::connect(url).await { + Ok(client) => client, + Err(err) => panic!("Failed to connect to NATS server: {}", err), + }; + + let jetstream = async_nats::jetstream::new(client.clone()); + + let _ = jetstream + .create_key_value(Config { + bucket: bucket.clone(), + ..Default::default() + }) + .await; + + let kv = match jetstream.get_key_value(bucket).await { + Ok(kv) => kv, + Err(err) => panic!("Failed to get key-value store: {}", err), + }; + + Self { client, kv } + } + + /// get_possible_flow_matches + /// + /// This function will take a key that one or more keys of a flow. + /// It will then loop over every value received from the key and return all flows that matched the IdentifiedFlow trait. + /// + /// Arguments: + /// - pattern: The key to get possible flow matches. For example, a REST Flow is never completely identifiable through a single key because the URL is dynamic and wherefore a regex is needed to be applied to the url making it impossible to include the entire URL in the key. In this case the key just reduces the amount of flows that can be a possible match. + /// - id: The identifier to use for identifying the possible matches. Its just a fine grain identifier that can be used to identify the possible matches. For a REST Flow this will be the regex matcher, for a CRON Flow the trait just return true every time. + /// + /// Returns: + /// - FlowIdenfiyResult: The result of the flow identification process. This can be one of the following: + /// - None: No flows matched the identifier. + /// - Single(ValidationFlow): A single flow matched the identifier. + /// - Multiple(Vec): Multiple flows matched the identifier. + /// + /// None is always bad, but as always this depends on the Adapter type. + /// For example: + /// REST will have only one match, if multiple matches are found it means the regex is not correct. + /// CRON can have multiple matches, because multiple flows can have the same CRON expression. + pub async fn get_possible_flow_match( + &self, + pattern: String, + id: I, + ) -> FlowIdenfiyResult { + let mut collector = Vec::new(); + let mut keys = match self.kv.keys().await { + Ok(keys) => keys.boxed(), + Err(err) => { + eprintln!("Failed to get keys: {}", err); + return FlowIdenfiyResult::None; + } + }; + + while let Ok(Some(key)) = keys.try_next().await { + println!("comparing: key: {} pattern {:?}", key, pattern); + + if !Self::is_matching_key(&pattern, &key) { + println!("Key does not match pattern: {}", key); + continue; + } + + if let Ok(Some(bytes)) = self.kv.get(key).await { + let decoded_flow = ValidationFlow::decode(bytes); + if let Ok(flow) = decoded_flow { + if id.identify(&flow) { + collector.push(flow); + } + }; + } + } + + match collector.len() { + 0 => FlowIdenfiyResult::None, + 1 => FlowIdenfiyResult::Single(collector[0].clone()), + _ => FlowIdenfiyResult::Multiple(collector), + } + } + + /// validate_and_execute_flow + /// + /// This function will validate the flow. If the flow is valid, it will execute (send the flow to the execution and wait for a/multiple result/s) the flow. + /// + /// Arguments: + /// - flow: The flow to be validated and executed. + /// - input_value: The input value to be used for the flow execution. + pub async fn validate_and_execute_flow( + &self, + flow: ValidationFlow, + input_value: Option, + ) -> Option { + if let Some(body) = input_value.clone() { + let verify_result = verify_flow(flow.clone(), body); + + match verify_result { + Ok(()) => {} + Err(_err) => { + return None; + } + }; + } + + let uuid = uuid::Uuid::new_v4().to_string(); + let execution_flow: ExecutionFlow = Self::convert_validation_flow(flow, input_value); + let bytes = execution_flow.encode_to_vec(); + let topic = format!("execution.{}", uuid); + let result = self.client.request(topic, bytes.into()).await; + + match result { + Ok(message) => match Value::decode(message.payload) { + Ok(value) => { + println!("Response: {:?}", &value); + Some(value) + } + Err(err) => { + eprintln!("Failed to decode response from NATS server: {}", err); + return None; + } + }, + Err(err) => { + eprintln!("Failed to send request to NATS server: {}", err); + None + } + } + } + + fn convert_validation_flow(flow: ValidationFlow, input_value: Option) -> ExecutionFlow { + ExecutionFlow { + flow_id: flow.flow_id, + starting_node: flow.starting_node, + input_value: input_value, + } + } + + fn is_matching_key(pattern: &String, key: &String) -> bool { + let splitted_pattern = pattern.split("."); + let splitted_key = key.split(".").collect::>(); + + let zip = splitted_pattern.into_iter().zip(splitted_key); + + for (pattern_part, key_part) in zip { + if pattern_part == "*" { + continue; + } + + if pattern_part != key_part { + println!("matching: pattern: {} key: {}", pattern_part, key_part); + return false; + } + } + println!("pattern was correct"); + true + } +} diff --git a/crates/base/src/traits.rs b/crates/base/src/traits.rs new file mode 100644 index 0000000..ac02df9 --- /dev/null +++ b/crates/base/src/traits.rs @@ -0,0 +1,246 @@ +//! Core traits that define the contract for building servers with the Draco framework. +//! +//! This module contains the fundamental traits that users must implement to create +//! a functioning server application. The traits follow a clear lifecycle pattern +//! and provide hooks for configuration loading, initialization, execution, and cleanup. + +use crate::runner::ServerContext; +use async_trait::async_trait; +use tucana::shared::ValidationFlow; + +/// A trait for loading and managing your application's configuration. +/// +/// This trait defines how your server loads its configuration data, whether from +/// environment variables, configuration files, command line arguments, or other sources. +/// +/// # Example +/// +/// ```ignore +/// use base::traits::LoadConfig; +/// +/// #[derive(Clone)] +/// struct MyConfig { +/// port: u16, +/// database_url: String, +/// } +/// +/// impl LoadConfig for MyConfig { +/// fn load() -> Self { +/// Self { +/// port: std::env::var("PORT") +/// .unwrap_or_else(|_| "8080".to_string()) +/// .parse() +/// .expect("Invalid port"), +/// database_url: std::env::var("DATABASE_URL") +/// .expect("DATABASE_URL must be set"), +/// } +/// } +/// } +/// ``` +pub trait LoadConfig: Sized + Clone + Send + Sync + 'static { + /// Load your application's configuration from external sources. + /// + /// This method is called once during server startup and should gather + /// all necessary configuration data from environment variables, files, + /// databases, or other sources. + /// + /// # Returns + /// + /// Returns an instance of your configuration type with all values loaded + /// and validated. + /// + /// # Panics + /// + /// This method may panic if required configuration is missing or invalid, + /// as configuration errors are typically fatal and should prevent startup. + fn load() -> Self; +} + +/// The main server lifecycle trait that defines the complete execution flow. +/// +/// This trait represents the core contract for any server implementation in the +/// Draco framework. It provides three distinct phases of server operation: +/// initialization, execution, and shutdown. +/// +/// The server lifecycle follows this pattern: +/// 1. `init()` - Perform one-time setup and initialization +/// 2. `run()` - Execute the main server loop (typically runs indefinitely) +/// 3. `shutdown()` - Clean up resources and perform graceful shutdown +/// +/// # Example +/// +/// ```ignore +/// use async_trait::async_trait; +/// use base::runner::ServerContext; +/// use base::traits::{LoadConfig, Server}; +/// +/// #[derive(Clone)] +/// struct MyConfig; +/// +/// impl LoadConfig for MyConfig { +/// fn load() -> Self { +/// todo!() +/// } +/// } +/// +/// struct MyServer { +/// // Server state fields +/// } +/// +/// #[async_trait] +/// impl Server for MyServer { +/// async fn init(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { +/// // Initialize database connections, load resources, etc. +/// Ok(()) +/// } +/// +/// async fn run(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { +/// // Main server loop - handle requests, process events, etc. +/// loop { +/// // Server logic here +/// } +/// } +/// +/// async fn shutdown(&mut self, ctx: &ServerContext) -> anyhow::Result<()> { +/// // Close connections, save state, cleanup resources +/// Ok(()) +/// } +/// } +/// ``` +#[async_trait] +pub trait Server: Send + Sync + 'static { + /// Initialize the server and perform one-time setup operations. + /// + /// This method is called once during server startup, after configuration + /// has been loaded but before the main server loop begins. Use this method + /// to perform expensive initialization operations such as: + /// + /// - Establishing database connections + /// - Loading static resources or caches + /// - Validating external dependencies + /// - Setting up monitoring or logging systems + /// + /// # Parameters + /// + /// - `ctx`: The server context containing configuration and runtime information + /// + /// # Returns + /// + /// Returns `Ok(())` on successful initialization, or an error if initialization + /// fails. Initialization errors will prevent the server from starting. + /// + /// # Errors + /// + /// This method should return an error if any critical initialization step fails, + /// such as inability to connect to required external services. + async fn init(&mut self, ctx: &ServerContext) -> anyhow::Result<()>; + + /// Execute the main server loop. + /// + /// This method contains the core server logic and typically runs indefinitely + /// until a shutdown signal is received. Common patterns include: + /// + /// - HTTP/gRPC server request handling loops + /// - Message queue consumers + /// - Event processing loops + /// - Periodic task execution + /// + /// The method should be designed to run continuously and handle graceful + /// shutdown when interrupted by external signals. + /// + /// # Parameters + /// + /// - `ctx`: The server context containing configuration and runtime information + /// + /// # Returns + /// + /// Returns `Ok(())` when the server shuts down gracefully, or an error if + /// a fatal error occurs during execution. + /// + /// # Errors + /// + /// This method should return an error only for fatal conditions that require + /// immediate server termination. Recoverable errors should be handled internally. + async fn run(&mut self, ctx: &ServerContext) -> anyhow::Result<()>; + + /// Perform graceful shutdown and cleanup operations. + /// + /// This method is called when the server receives a shutdown signal (such as + /// SIGTERM or SIGINT). It should perform cleanup operations to ensure a + /// graceful shutdown: + /// + /// - Close database connections and network sockets + /// - Flush pending writes or queued operations + /// - Save application state if necessary + /// - Release system resources + /// + /// The shutdown process should complete within a reasonable timeframe to + /// avoid being forcefully terminated. + /// + /// # Parameters + /// + /// - `ctx`: The server context containing configuration and runtime information + /// + /// # Returns + /// + /// Returns `Ok(())` on successful shutdown, or an error if cleanup operations fail. + /// Shutdown errors are typically logged but don't prevent process termination. + /// + /// # Errors + /// + /// This method should return an error if critical cleanup operations fail, + /// though the server will still terminate regardless of the result. + async fn shutdown(&mut self, ctx: &ServerContext) -> anyhow::Result<()>; +} + +/// A trait for identifying and matching validation flows. +/// +/// This trait provides a mechanism to identify whether a given validation flow +/// matches specific criteria. It's typically used in systems that need to route +/// or process different types of validation flows based on their characteristics. +pub trait IdentifiableFlow { + /// Determine if this identifier matches the given validation flow. + /// + /// This method examines a validation flow and returns whether it matches + /// the criteria defined by this identifier. The matching logic is entirely + /// implementation-dependent and can be based on any properties of the flow. + /// + /// # Parameters + /// + /// - `flow`: The validation flow to examine + /// + /// # Returns + /// + /// Returns `true` if the flow matches this identifier's criteria, + /// `false` otherwise. + /// + /// # Examples + /// + /// ```ignore + /// use tucana::shared::ValidationFlow; + /// + /// use base::traits::IdentifiableFlow; + /// + /// struct MyFlowMatcher; + /// + /// impl MyFlowMatcher { + /// fn new() -> Self { + /// MyFlowMatcher {} + /// } + /// } + /// + /// impl IdentifiableFlow for MyFlowMatcher { + /// fn identify(&self, flow: &ValidationFlow) -> bool { + /// todo!() + /// } + /// } + /// + /// let matcher = MyFlowMatcher::new(); + /// let flow = ValidationFlow::default(); + /// + /// if matcher.identify(&flow) { + /// // Handle this specific type of flow + /// } + /// ``` + fn identify(&self, flow: &ValidationFlow) -> bool; +} diff --git a/crates/http/src/request.rs b/crates/http/src/request.rs index f20151e..591db4d 100644 --- a/crates/http/src/request.rs +++ b/crates/http/src/request.rs @@ -6,7 +6,7 @@ use std::{ str::FromStr, usize, }; -use tucana::shared::{helper::value::from_json_value, value::Kind, Struct, Value}; +use tucana::shared::{Struct, Value, helper::value::from_json_value, value::Kind}; #[derive(Debug, Clone)] pub enum HttpOption { @@ -161,6 +161,7 @@ pub fn convert_to_http_request(stream: &TcpStream) -> Result Pin> + Send + 'static>>; } +// Implement AsyncHandler for async closures +impl AsyncHandler for F +where + F: Fn(HttpRequest) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, +{ + fn handle( + &self, + request: HttpRequest, + ) -> Pin> + Send + 'static>> { + Box::pin(self(request)) + } +} + pub struct Server { port: u16, handlers: Arc>>, + shutdown_tx: Option>, } impl Server { @@ -20,6 +37,7 @@ impl Server { Server { port, handlers: Arc::new(Vec::new()), + shutdown_tx: None, } } @@ -33,58 +51,201 @@ impl Server { handlers.push(Box::new(handler)); } - pub async fn start(&self) { + /// Register an async closure as a handler + pub fn register_async_closure(&mut self, closure: F) + where + F: Fn(HttpRequest) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, + { + self.register_handler(closure); + } + + pub async fn start(&mut self) { + let (shutdown_tx, mut shutdown_rx) = tokio::sync::broadcast::channel(1); + self.shutdown_tx = Some(shutdown_tx); + + self.run_server(&mut shutdown_rx).await; + } + + pub fn shutdown(&self) { + if let Some(ref tx) = self.shutdown_tx { + let _ = tx.send(()); + } + } + + async fn run_server(&self, shutdown_rx: &mut tokio::sync::broadcast::Receiver<()>) { let url = format!("127.0.0.1:{}", self.port); let listener = match TcpListener::bind(&url) { - Ok(listener) => listener, + Ok(listener) => { + listener + .set_nonblocking(true) + .expect("Failed to set non-blocking"); + listener + } Err(err) => panic!("Failed to bind to {}: {}", url, err), }; - for stream_result in listener.incoming() { - let mut stream = match stream_result { - Ok(stream) => stream, - Err(err) => { - log::error!("Failed to accept incoming connection: {}", err); - continue; + let async_listener = + tokio::net::TcpListener::from_std(listener).expect("Failed to create async listener"); + + loop { + tokio::select! { + _ = shutdown_rx.recv() => { + log::info!("Shutdown signal received, stopping server"); + break; } - }; - - let handlers = self.handlers.clone(); - - tokio::spawn(async move { - match convert_to_http_request(&stream) { - Ok(request) => { - // Try each handler until one handles the request - let mut response = None; - for handler in handlers.iter() { - let handler_response = handler.handle(request.clone()).await; - if handler_response.is_some() { - response = Some(handler_response); + stream_result = async_listener.accept() => { + let (stream, _) = match stream_result { + Ok(connection) => connection, + Err(err) => { + log::error!("Failed to accept incoming connection: {}", err); + continue; + } + }; + + let handlers = self.handlers.clone(); + + tokio::spawn(async move { + println!("New connection accepted, starting to read request..."); + + // Read HTTP request data using tokio's async methods + use tokio::io::{AsyncBufReadExt, BufReader}; + + let mut buf_reader = BufReader::new(stream); + let mut raw_http_request: Vec = Vec::new(); + let mut line = String::new(); + + // Read headers until empty line + while let Ok(bytes) = buf_reader.read_line(&mut line).await { + println!("Read {} bytes: '{}'", bytes, line.trim()); + if bytes == 0 || line.trim().is_empty() { break; } + raw_http_request.push(line.trim().to_string()); + line.clear(); } - // Default response if no handler matched - let http_response = match response { - Some(Some(resp)) => resp, - Some(None) => { - let headers = std::collections::HashMap::new(); - HttpResponse::not_found("No handler found".to_string(), headers) - } - None => { + println!("Finished reading request. Raw data: {:?}", raw_http_request); + + // Parse the HTTP request manually here since we can't use convert_to_http_request with tokio stream + let request_result = if let Some(first_line) = raw_http_request.first() { + println!("Parsing first line: '{}'", first_line); + let parts: Vec<&str> = first_line.split_whitespace().collect(); + println!("Split into parts: {:?}", parts); + + if parts.len() >= 3 { + // Extract host from headers or use default + let mut host = "localhost".to_string(); + let header_lines = raw_http_request[1..].to_vec(); + for header_line in &header_lines { + if header_line.to_lowercase().starts_with("host:") { + if let Some(host_value) = header_line.split(':').nth(1) { + host = host_value.trim().to_string(); + } + break; + } + } + + let request = HttpRequest { + method: match parts[0] { + "GET" => crate::request::HttpOption::GET, + "POST" => crate::request::HttpOption::POST, + "PUT" => crate::request::HttpOption::PUT, + "DELETE" => crate::request::HttpOption::DELETE, + _ => crate::request::HttpOption::GET, + }, + path: parts[1].to_string(), + version: parts[2].to_string(), + host, + headers: HeaderMap::from_vec(header_lines), + body: None, + }; + + println!("Successfully parsed request: {:?}", request); + Ok(request) + } else { + println!("Invalid HTTP request - not enough parts"); let headers = std::collections::HashMap::new(); - HttpResponse::not_found("No handler found".to_string(), headers) + Err(HttpResponse::bad_request("Invalid HTTP request".to_string(), headers)) } + } else { + println!("Empty HTTP request - no first line"); + let headers = std::collections::HashMap::new(); + Err(HttpResponse::bad_request("Empty HTTP request".to_string(), headers)) }; - stream.write_all(&http_response.to_bytes()).unwrap(); - } - Err(response) => { - stream.write_all(&response.to_bytes()).unwrap(); - } - }; - }); + match request_result { + Ok(request) => { + println!("About to call handlers for request: {:?}", request); + + // Try each handler until one handles the request + let mut response = None; + for (i, handler) in handlers.iter().enumerate() { + println!("Calling handler {}", i); + let handler_response = handler.handle(request.clone()).await; + println!("Handler {} returned: {:?}", i, handler_response.is_some()); + if handler_response.is_some() { + response = Some(handler_response); + break; + } + } + + println!("Final response from handlers: {:?}", response.is_some()); + + // Default response if no handler matched + let http_response = match response { + Some(Some(resp)) => { + println!("Using handler response"); + resp + }, + Some(None) => { + println!("Handler returned None, using not found"); + let headers = std::collections::HashMap::new(); + HttpResponse::not_found("No handler found".to_string(), headers) + } + None => { + println!("No handlers matched, using not found"); + let headers = std::collections::HashMap::new(); + HttpResponse::not_found("No handler found".to_string(), headers) + } + }; + + println!("About to write response: {} bytes", http_response.to_bytes().len()); + + use tokio::io::AsyncWriteExt; + let mut stream = buf_reader.into_inner(); + if let Err(e) = stream.write_all(&http_response.to_bytes()).await { + println!("Failed to write response: {}", e); + log::error!("Failed to write response: {}", e); + } else if let Err(e) = stream.flush().await { + println!("Failed to flush response: {}", e); + log::error!("Failed to flush response: {}", e); + } else { + println!("Response written and flushed successfully"); + } + } + Err(response) => { + println!("Request parsing failed, sending error response"); + use tokio::io::AsyncWriteExt; + let mut stream = buf_reader.into_inner(); + if let Err(e) = stream.write_all(&response.to_bytes()).await { + println!("Failed to write error response: {}", e); + log::error!("Failed to write error response: {}", e); + } else if let Err(e) = stream.flush().await { + println!("Failed to flush error response: {}", e); + log::error!("Failed to flush error response: {}", e); + } else { + println!("Error response written and flushed successfully"); + } + } + } + + // Connection will be closed when stream goes out of scope + println!("Request processing completed"); + }); + } + } } } } diff --git a/crates/validator/src/lib.rs b/crates/validator/src/lib.rs index 4659c23..d20c9c4 100644 --- a/crates/validator/src/lib.rs +++ b/crates/validator/src/lib.rs @@ -9,10 +9,10 @@ use rules::{ violation::{DataTypeNotFoundRuleViolation, DataTypeRuleError, DataTypeRuleViolation}, }; -use tucana::shared::{data_type_rule::Config, DataType, Flow, Value}; +use tucana::shared::{ExecutionDataType, ValidationFlow, Value, execution_data_type_rule::Config}; pub struct VerificationResult; -pub fn verify_flow(flow: Flow, body: Value) -> Result<(), DataTypeRuleError> { +pub fn verify_flow(flow: ValidationFlow, body: Value) -> Result<(), DataTypeRuleError> { let input_type = match &flow.input_type_identifier { Some(r) => r.clone(), None => return Ok(()), //Returns directly because no rule is given. The body is ok and will not be concidered @@ -41,8 +41,8 @@ pub fn verify_flow(flow: Flow, body: Value) -> Result<(), DataTypeRuleError> { //Verifies the rules on the datatype of the body thats given fn verify_data_type_rules( body: Value, - data_type: DataType, - availabe_data_types: &Vec, + data_type: ExecutionDataType, + availabe_data_types: &Vec, ) -> Result<(), DataTypeRuleError> { let mut violations: Vec = Vec::new(); for rule in data_type.rules { @@ -97,8 +97,6 @@ fn verify_data_type_rules( } }; } - // Draco dont checks Node Rules (Input/Return Type Rules!) - _ => continue, } } @@ -109,11 +107,12 @@ fn verify_data_type_rules( } } -fn get_data_type_by_id(data_types: &Vec, str_id: &String) -> Option { - let id = str_id.parse::().unwrap_or(1211); - +fn get_data_type_by_id( + data_types: &Vec, + identifier: &String, +) -> Option { data_types .iter() - .find(|data_type| data_type.variant == id) + .find(|data_type| &data_type.identifier == identifier) .cloned() } diff --git a/crates/validator/src/rules/contains_key.rs b/crates/validator/src/rules/contains_key.rs index bdcc959..8c98441 100644 --- a/crates/validator/src/rules/contains_key.rs +++ b/crates/validator/src/rules/contains_key.rs @@ -1,17 +1,14 @@ use super::violation::ContainsKeyRuleViolation; -use super::violation::DataTypeIdentifierNotPresentRuleViolation; use super::violation::DataTypeRuleError; use super::violation::DataTypeRuleViolation; -use super::violation::GenericKeyNotAllowedRuleViolation; use super::violation::MissingDataTypeRuleDefinition; use crate::get_data_type_by_id; use crate::verify_data_type_rules; -use tucana::shared::data_type_identifier::Type; +use tucana::shared::ExecutionDataType; +use tucana::shared::ExecutionDataTypeContainsKeyRuleConfig; +use tucana::shared::Value; use tucana::shared::helper::path::expect_kind; use tucana::shared::value::Kind; -use tucana::shared::DataType; -use tucana::shared::DataTypeContainsKeyRuleConfig; -use tucana::shared::Value; /// # Data Type Validation Behavior /// @@ -28,45 +25,11 @@ use tucana::shared::Value; /// - Returns a `MissingDataTypeRuleDefinition` if the referenced data type doesn't exist /// - Returns validation errors if the value doesn't match the expected data type pub fn apply_contains_key( - rule: DataTypeContainsKeyRuleConfig, + rule: ExecutionDataTypeContainsKeyRuleConfig, body: &Value, - available_data_types: &Vec, + available_data_types: &Vec, ) -> Result<(), DataTypeRuleError> { - let identifier = match rule.data_type_identifier { - Some(optional_data_type) => { - if let Some(data_type) = optional_data_type.r#type { - match data_type { - Type::DataTypeIdentifier(id) => id, - _ => { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::GenericKeyNotAllowed( - GenericKeyNotAllowedRuleViolation { - key: "identifier".to_string(), - }, - )], - }) - } - } - } else { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::DataTypeIdentifierNotPresent( - DataTypeIdentifierNotPresentRuleViolation { - identifier: "identifier".to_string(), - }, - )], - }); - } - } - None => { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::DataTypeIdentifierNotPresent( - DataTypeIdentifierNotPresentRuleViolation { - identifier: "identifier".to_string(), - }, - )], - }); - } - }; + let identifier = rule.data_type_identifier; if let Some(Kind::StructValue(_)) = &body.kind { let value = match expect_kind(&identifier, &body) { diff --git a/crates/validator/src/rules/contains_type.rs b/crates/validator/src/rules/contains_type.rs index 20012cf..ee937d8 100644 --- a/crates/validator/src/rules/contains_type.rs +++ b/crates/validator/src/rules/contains_type.rs @@ -1,11 +1,8 @@ use crate::{get_data_type_by_id, verify_data_type_rules}; -use super::violation::{ - DataTypeIdentifierNotPresentRuleViolation, DataTypeRuleError, DataTypeRuleViolation, - GenericKeyNotAllowedRuleViolation, InvalidFormatRuleViolation, -}; +use super::violation::{DataTypeRuleError, DataTypeRuleViolation, InvalidFormatRuleViolation}; use tucana::shared::{ - data_type_identifier::Type, value::Kind, DataType, DataTypeContainsTypeRuleConfig, Value, + ExecutionDataType, ExecutionDataTypeContainsTypeRuleConfig, Value, value::Kind, }; /// # Item of Collection Validation @@ -19,46 +16,11 @@ use tucana::shared::{ /// - Returns an `ItemOfCollectionRuleViolation` if the value is not found in the collection /// pub fn apply_contains_type( - rule: DataTypeContainsTypeRuleConfig, - available_data_types: &Vec, + rule: ExecutionDataTypeContainsTypeRuleConfig, + available_data_types: &Vec, body: &Value, ) -> Result<(), DataTypeRuleError> { - let identifier = match rule.data_type_identifier { - Some(optional_data_type) => { - if let Some(data_type) = optional_data_type.r#type { - match data_type { - Type::DataTypeIdentifier(id) => id, - _ => { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::GenericKeyNotAllowed( - GenericKeyNotAllowedRuleViolation { - key: "identifier".to_string(), - }, - )], - }) - } - } - } else { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::DataTypeIdentifierNotPresent( - DataTypeIdentifierNotPresentRuleViolation { - identifier: "identifier".to_string(), - }, - )], - }); - } - } - None => { - return Err(DataTypeRuleError { - violations: vec![DataTypeRuleViolation::DataTypeIdentifierNotPresent( - DataTypeIdentifierNotPresentRuleViolation { - identifier: "identifier".to_string(), - }, - )], - }); - } - }; - + let identifier = rule.data_type_identifier; let real_body = match &body.kind { Some(body) => body.clone(), None => { diff --git a/crates/validator/src/rules/number_range.rs b/crates/validator/src/rules/number_range.rs index c320e08..8af4fca 100644 --- a/crates/validator/src/rules/number_range.rs +++ b/crates/validator/src/rules/number_range.rs @@ -1,4 +1,4 @@ -use tucana::shared::{value::Kind, DataTypeNumberRangeRuleConfig, Value}; +use tucana::shared::{DataTypeNumberRangeRuleConfig, Value, value::Kind}; use super::violation::{ DataTypeRuleError, DataTypeRuleViolation, NumberInRangeRuleViolation, @@ -38,7 +38,7 @@ pub fn apply_number_range( type_not_accepted: format!("{:?}", kind), }, )], - }) + }); } }; diff --git a/crates/validator/src/rules/regex.rs b/crates/validator/src/rules/regex.rs index 91752fb..09655cb 100644 --- a/crates/validator/src/rules/regex.rs +++ b/crates/validator/src/rules/regex.rs @@ -1,4 +1,4 @@ -use tucana::shared::{value::Kind, DataTypeRegexRuleConfig, Value}; +use tucana::shared::{DataTypeRegexRuleConfig, Value, value::Kind}; use super::violation::{ DataTypeRuleError, DataTypeRuleViolation, RegexRuleTypeNotAcceptedViolation, RegexRuleViolation, @@ -36,7 +36,7 @@ pub fn apply_regex(rule: DataTypeRegexRuleConfig, body: &Value) -> Result<(), Da type_not_accepted: format!("StructValue({:?})", s), }, )], - }) + }); } Kind::ListValue(l) => { return Err(DataTypeRuleError { @@ -45,7 +45,7 @@ pub fn apply_regex(rule: DataTypeRegexRuleConfig, body: &Value) -> Result<(), Da type_not_accepted: format!("ListValue({:?})", l), }, )], - }) + }); } };