From bd77a7db48e955988218800a88dbf914214e653b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 9 Sep 2025 16:31:06 +0200 Subject: [PATCH] WIP1 --- Cargo.lock | 797 +++++++++++++++++++++++++++++++++++++- herodb/Cargo.toml | 1 + herodb/src/lib.rs | 2 + herodb/src/main.rs | 30 +- herodb/src/rpc.rs | 242 ++++++++++++ herodb/src/rpc_server.rs | 49 +++ herodb/tests/rpc_tests.rs | 42 ++ 7 files changed, 1160 insertions(+), 3 deletions(-) create mode 100644 herodb/src/rpc.rs create mode 100644 herodb/src/rpc_server.rs create mode 100644 herodb/tests/rpc_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 15bf240..856b704 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -233,6 +239,22 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cc" +version = "1.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.1" @@ -349,6 +371,22 @@ dependencies = [ "futures", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -403,7 +441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -465,6 +503,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -480,6 +524,12 @@ dependencies = [ "toml", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "fluent" version = "0.16.1" @@ -524,6 +574,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -604,6 +660,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -649,12 +711,37 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + [[package]] name = "heck" version = "0.5.0" @@ -675,6 +762,7 @@ dependencies = [ "clap", "ed25519-dalek", "futures", + "jsonrpsee", "rand", "redb", "redis", @@ -704,6 +792,113 @@ dependencies = [ "digest", ] +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2 0.6.0", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "i18n-config" version = "0.4.8" @@ -880,6 +1075,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +dependencies = [ + "equivalent", + "hashbrown 0.15.5", +] + [[package]] name = "inout" version = "0.1.4" @@ -937,6 +1142,183 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jsonrpsee" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b26c20e2178756451cfeb0661fb74c47dd5988cb7e3939de7e9241fd604d42" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", + "jsonrpsee-types", + "jsonrpsee-ws-client", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bacb85abf4117092455e1573625e21b8f8ef4dec8aff13361140b2dc266cdff2" +dependencies = [ + "base64 0.22.1", + "futures-util", + "http", + "jsonrpsee-core", + "pin-project", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456196007ca3a14db478346f58c7238028d55ee15c1df15115596e411ff27925" +dependencies = [ + "async-trait", + "bytes", + "futures-timer", + "futures-util", + "http", + "http-body", + "http-body-util", + "jsonrpsee-types", + "parking_lot", + "pin-project", + "rand", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c872b6c9961a4ccc543e321bb5b89f6b2d2c7fe8b61906918273a3333c95400c" +dependencies = [ + "async-trait", + "base64 0.22.1", + "http-body", + "hyper", + "hyper-rustls", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e65763c942dfc9358146571911b0cd1c361c2d63e2d2305622d40d36376ca80" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e363146da18e50ad2b51a0a7925fc423137a0b1371af8235b1c231a0647328" +dependencies = [ + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" +dependencies = [ + "http", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b3323d890aa384f12148e8d2a1fd18eb66e9e7e825f9de4fa53bcc19b93eef" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "url", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1040,6 +1422,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "parking_lot" version = "0.12.4" @@ -1150,6 +1538,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1261,6 +1658,26 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "rust-embed" version = "8.7.2" @@ -1322,6 +1739,80 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.20" @@ -1346,6 +1837,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1372,6 +1872,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "self_cell" version = "0.10.3" @@ -1425,6 +1948,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha1_smol" version = "1.0.1" @@ -1442,6 +1976,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.6" @@ -1492,6 +2032,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "soketto" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "http", + "httparse", + "log", + "rand", + "sha1", +] + [[package]] name = "spki" version = "0.7.3" @@ -1619,6 +2175,28 @@ dependencies = [ "syn 2.0.106", ] +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -1627,6 +2205,7 @@ checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -1641,6 +2220,88 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "type-map" version = "0.5.1" @@ -1691,6 +2352,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.4" @@ -1730,12 +2397,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.2", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1773,6 +2467,30 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -1791,6 +2509,30 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1813,7 +2555,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -1824,6 +2566,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -1836,6 +2584,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -1848,6 +2602,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1872,6 +2632,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -1884,6 +2650,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -1896,6 +2668,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -1908,6 +2686,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1920,6 +2704,15 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + [[package]] name = "writeable" version = "0.6.1" diff --git a/herodb/Cargo.toml b/herodb/Cargo.toml index a11a8c0..f2f8c41 100644 --- a/herodb/Cargo.toml +++ b/herodb/Cargo.toml @@ -23,6 +23,7 @@ age = "0.10" secrecy = "0.8" ed25519-dalek = "2" base64 = "0.22" +jsonrpsee = { version = "0.24", features = ["http-client", "ws-client", "server", "macros"] } [dev-dependencies] redis = { version = "0.24", features = ["aio", "tokio-comp"] } diff --git a/herodb/src/lib.rs b/herodb/src/lib.rs index a66b56e..9a2f7fe 100644 --- a/herodb/src/lib.rs +++ b/herodb/src/lib.rs @@ -4,5 +4,7 @@ pub mod crypto; pub mod error; pub mod options; pub mod protocol; +pub mod rpc; +pub mod rpc_server; pub mod server; pub mod storage; diff --git a/herodb/src/main.rs b/herodb/src/main.rs index 1e3d2c6..79c7ada 100644 --- a/herodb/src/main.rs +++ b/herodb/src/main.rs @@ -3,6 +3,7 @@ use tokio::net::TcpListener; use herodb::server; +use herodb::rpc_server; use clap::Parser; @@ -30,6 +31,14 @@ struct Args { /// Encrypt the database #[arg(long)] encrypt: bool, + + /// Enable RPC management server + #[arg(long)] + enable_rpc: bool, + + /// RPC server port (default: 8080) + #[arg(long, default_value = "8080")] + rpc_port: u16, } #[tokio::main] @@ -46,7 +55,7 @@ async fn main() { // new DB option let option = herodb::options::DBOption { - dir: args.dir, + dir: args.dir.clone(), port, debug: args.debug, encryption_key: args.encryption_key, @@ -59,6 +68,25 @@ async fn main() { // Add a small delay to ensure the port is ready tokio::time::sleep(std::time::Duration::from_millis(100)).await; + // Start RPC server if enabled + let rpc_handle = if args.enable_rpc { + let rpc_addr = format!("127.0.0.1:{}", args.rpc_port).parse().unwrap(); + let base_dir = format!("{}/rpc_databases", args.dir); + + match rpc_server::start_rpc_server(rpc_addr, base_dir).await { + Ok(handle) => { + println!("RPC management server started on port {}", args.rpc_port); + Some(handle) + } + Err(e) => { + eprintln!("Failed to start RPC server: {}", e); + None + } + } + } else { + None + }; + // accept new connections loop { let stream = listener.accept().await; diff --git a/herodb/src/rpc.rs b/herodb/src/rpc.rs new file mode 100644 index 0000000..b8b9a36 --- /dev/null +++ b/herodb/src/rpc.rs @@ -0,0 +1,242 @@ +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::RwLock; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use serde::{Deserialize, Serialize}; + +use crate::server::Server; +use crate::options::DBOption; + +/// Database backend types +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BackendType { + Redb, + // Future: InMemory, Custom(String) +} + +/// Database configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DatabaseConfig { + pub name: Option, + pub storage_path: Option, + pub max_size: Option, + pub redis_version: Option, +} + +/// Database information returned by metadata queries +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DatabaseInfo { + pub id: u64, + pub name: Option, + pub backend: BackendType, + pub encrypted: bool, + pub redis_version: Option, + pub storage_path: Option, + pub size_on_disk: Option, + pub key_count: Option, + pub created_at: u64, + pub last_access: Option, +} + +/// RPC trait for HeroDB management +#[rpc(server, client, namespace = "herodb")] +pub trait Rpc { + /// Create a new database with specified configuration + #[method(name = "createDatabase")] + async fn create_database( + &self, + backend: BackendType, + config: DatabaseConfig, + encryption_key: Option, + ) -> RpcResult; + + /// Set encryption for an existing database (write-only key) + #[method(name = "setEncryption")] + async fn set_encryption(&self, db_id: u64, encryption_key: String) -> RpcResult; + + /// List all managed databases + #[method(name = "listDatabases")] + async fn list_databases(&self) -> RpcResult>; + + /// Get detailed information about a specific database + #[method(name = "getDatabaseInfo")] + async fn get_database_info(&self, db_id: u64) -> RpcResult; + + /// Delete a database + #[method(name = "deleteDatabase")] + async fn delete_database(&self, db_id: u64) -> RpcResult; + + /// Get server statistics + #[method(name = "getServerStats")] + async fn get_server_stats(&self) -> RpcResult>; +} + +/// RPC Server implementation +pub struct RpcServerImpl { + /// Base directory for database files + base_dir: String, + /// Managed database servers + servers: Arc>>>, + /// Next database ID to assign + next_db_id: Arc>, +} + +impl RpcServerImpl { + /// Create a new RPC server instance + pub fn new(base_dir: String) -> Self { + Self { + base_dir, + servers: Arc::new(RwLock::new(HashMap::new())), + next_db_id: Arc::new(RwLock::new(0)), + } + } + + /// Get the next available database ID + async fn get_next_db_id(&self) -> u64 { + let mut id = self.next_db_id.write().await; + let current_id = *id; + *id += 1; + current_id + } +} + +#[jsonrpsee::core::async_trait] +impl RpcServer for RpcServerImpl { + async fn create_database( + &self, + backend: BackendType, + config: DatabaseConfig, + encryption_key: Option, + ) -> RpcResult { + let db_id = self.get_next_db_id().await; + + // For now, only support Redb backend + match backend { + BackendType::Redb => { + // Create database directory + let db_dir = if let Some(path) = &config.storage_path { + std::path::PathBuf::from(path) + } else { + std::path::PathBuf::from(&self.base_dir).join(format!("rpc_db_{}", db_id)) + }; + + // Ensure directory exists + std::fs::create_dir_all(&db_dir) + .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( + -32000, + format!("Failed to create directory: {}", e), + None::<()> + ))?; + + // Create DB options + let encrypt = encryption_key.is_some(); + let option = DBOption { + dir: db_dir.to_string_lossy().to_string(), + port: 0, // Not used for RPC-managed databases + debug: false, + encryption_key, + encrypt, + }; + + // Create server instance + let server = Server::new(option).await; + + // Store the server + let mut servers = self.servers.write().await; + servers.insert(db_id, Arc::new(server)); + + Ok(db_id) + } + } + } + + async fn set_encryption(&self, db_id: u64, _encryption_key: String) -> RpcResult { + // Note: In a real implementation, we'd need to modify the existing database + // For now, return false as encryption can only be set during creation + let _servers = self.servers.read().await; + // TODO: Implement encryption setting for existing databases + Ok(false) + } + + async fn list_databases(&self) -> RpcResult> { + let servers = self.servers.read().await; + let mut result = Vec::new(); + + for (id, server) in servers.iter() { + // Get basic info from server + let info = DatabaseInfo { + id: *id, + name: None, // TODO: Store name in server metadata + backend: BackendType::Redb, + encrypted: server.option.encrypt, + redis_version: Some("7.0".to_string()), // Default Redis compatibility + storage_path: Some(server.option.dir.clone()), + size_on_disk: None, // TODO: Calculate actual size + key_count: None, // TODO: Get key count from storage + created_at: std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(), + last_access: None, + }; + result.push(info); + } + + Ok(result) + } + + async fn get_database_info(&self, db_id: u64) -> RpcResult { + let servers = self.servers.read().await; + + if let Some(server) = servers.get(&db_id) { + Ok(DatabaseInfo { + id: db_id, + name: None, + backend: BackendType::Redb, + encrypted: server.option.encrypt, + redis_version: Some("7.0".to_string()), + storage_path: Some(server.option.dir.clone()), + size_on_disk: None, + key_count: None, + created_at: std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(), + last_access: None, + }) + } else { + Err(jsonrpsee::types::ErrorObjectOwned::owned( + -32000, + format!("Database {} not found", db_id), + None::<()> + )) + } + } + + async fn delete_database(&self, db_id: u64) -> RpcResult { + let mut servers = self.servers.write().await; + + if let Some(server) = servers.remove(&db_id) { + // TODO: Clean up database files + let _ = server; + Ok(true) + } else { + Ok(false) + } + } + + async fn get_server_stats(&self) -> RpcResult> { + let servers = self.servers.read().await; + let mut stats = HashMap::new(); + + stats.insert("total_databases".to_string(), serde_json::json!(servers.len())); + stats.insert("uptime".to_string(), serde_json::json!( + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() + )); + + Ok(stats) + } +} \ No newline at end of file diff --git a/herodb/src/rpc_server.rs b/herodb/src/rpc_server.rs new file mode 100644 index 0000000..2222d9e --- /dev/null +++ b/herodb/src/rpc_server.rs @@ -0,0 +1,49 @@ +use std::net::SocketAddr; +use jsonrpsee::server::{ServerBuilder, ServerHandle}; +use jsonrpsee::RpcModule; + +use crate::rpc::{RpcServer, RpcServerImpl}; + +/// Start the RPC server on the specified address +pub async fn start_rpc_server(addr: SocketAddr, base_dir: String) -> Result> { + // Create the RPC server implementation + let rpc_impl = RpcServerImpl::new(base_dir); + + // Create the RPC module + let mut module = RpcModule::new(()); + module.merge(RpcServer::into_rpc(rpc_impl))?; + + // Build the server with both HTTP and WebSocket support + let server = ServerBuilder::default() + .http_only() // Start with HTTP only, can be extended to WS + .build(addr) + .await?; + + // Start the server + let handle = server.start(module); + + println!("RPC server started on {}", addr); + + Ok(handle) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Duration; + + #[tokio::test] + async fn test_rpc_server_startup() { + let addr = "127.0.0.1:0".parse().unwrap(); // Use port 0 for auto-assignment + let base_dir = "/tmp/test_rpc".to_string(); + + let handle = start_rpc_server(addr, base_dir).await.unwrap(); + + // Give the server a moment to start + tokio::time::sleep(Duration::from_millis(100)).await; + + // Stop the server + handle.stop().unwrap(); + handle.stopped().await; + } +} \ No newline at end of file diff --git a/herodb/tests/rpc_tests.rs b/herodb/tests/rpc_tests.rs new file mode 100644 index 0000000..1fa6628 --- /dev/null +++ b/herodb/tests/rpc_tests.rs @@ -0,0 +1,42 @@ +use std::net::SocketAddr; +use jsonrpsee::http_client::HttpClientBuilder; +use jsonrpsee::core::client::ClientT; +use serde_json::json; + +use herodb::rpc::{RpcClient, BackendType, DatabaseConfig}; + +#[tokio::test] +async fn test_rpc_server_basic() { + // This test would require starting the RPC server in a separate thread + // For now, we'll just test that the types compile correctly + + // Test serialization of types + let backend = BackendType::Redb; + let config = DatabaseConfig { + name: Some("test_db".to_string()), + storage_path: Some("/tmp/test".to_string()), + max_size: Some(1024 * 1024), + redis_version: Some("7.0".to_string()), + }; + + let backend_json = serde_json::to_string(&backend).unwrap(); + let config_json = serde_json::to_string(&config).unwrap(); + + assert_eq!(backend_json, "\"Redb\""); + assert!(config_json.contains("test_db")); +} + +#[tokio::test] +async fn test_database_config_serialization() { + let config = DatabaseConfig { + name: Some("my_db".to_string()), + storage_path: None, + max_size: Some(1000000), + redis_version: Some("7.0".to_string()), + }; + + let json = serde_json::to_value(&config).unwrap(); + assert_eq!(json["name"], "my_db"); + assert_eq!(json["max_size"], 1000000); + assert_eq!(json["redis_version"], "7.0"); +} \ No newline at end of file