From e5b844deeeed9719f2959809260e295d6a046e3b Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 10 Sep 2025 16:16:10 +0200 Subject: [PATCH] bump version of jsonrpsee to newest + add rpc.discover endpoint for openrpc spec --- Cargo.lock | 193 ++++++++++++++++++------ herodb/Cargo.toml | 2 +- herodb/docs/openrpc.json | 290 ++++++++++++++++++++++++++++++++++++ herodb/src/lib.rs | 3 +- herodb/src/main.rs | 4 +- herodb/src/openrpc_spec.rs | 2 + herodb/src/rpc.rs | 33 +++- herodb/src/rpc_server.rs | 6 +- herodb/tests/redis_tests.rs | 20 +-- herodb/tests/rpc_tests.rs | 7 +- 10 files changed, 483 insertions(+), 77 deletions(-) create mode 100644 herodb/docs/openrpc.json create mode 100644 herodb/src/openrpc_spec.rs diff --git a/Cargo.lock b/Cargo.lock index 856b704..c8da47f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ "lazy_static", "nom", "pin-project", - "rand", + "rand 0.8.5", "rust-embed", "scrypt", "sha2", @@ -65,7 +65,7 @@ dependencies = [ "hkdf", "io_tee", "nom", - "rand", + "rand 0.8.5", "secrecy", "sha2", ] @@ -403,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -571,7 +571,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" dependencies = [ - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -702,7 +702,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.5+wasi-0.2.4", ] [[package]] @@ -763,14 +775,14 @@ dependencies = [ "ed25519-dalek", "futures", "jsonrpsee", - "rand", + "rand 0.8.5", "redb", "redis", "secrecy", "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.69", "tokio", ] @@ -909,7 +921,7 @@ dependencies = [ "log", "serde", "serde_derive", - "thiserror", + "thiserror 1.0.69", "unic-langid", ] @@ -929,7 +941,7 @@ dependencies = [ "log", "parking_lot", "rust-embed", - "thiserror", + "thiserror 1.0.69", "unic-langid", "walkdir", ] @@ -1153,7 +1165,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1166,9 +1178,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jsonrpsee" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b26c20e2178756451cfeb0661fb74c47dd5988cb7e3939de7e9241fd604d42" +checksum = "3f3f48dc3e6b8bd21e15436c1ddd0bc22a6a54e8ec46fedd6adf3425f396ec6a" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -1182,9 +1194,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bacb85abf4117092455e1573625e21b8f8ef4dec8aff13361140b2dc266cdff2" +checksum = "cf36eb27f8e13fa93dcb50ccb44c417e25b818cfa1a481b5470cd07b19c60b98" dependencies = [ "base64 0.22.1", "futures-util", @@ -1195,7 +1207,7 @@ dependencies = [ "rustls-pki-types", "rustls-platform-verifier", "soketto", - "thiserror", + "thiserror 2.0.16", "tokio", "tokio-rustls", "tokio-util", @@ -1205,9 +1217,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456196007ca3a14db478346f58c7238028d55ee15c1df15115596e411ff27925" +checksum = "316c96719901f05d1137f19ba598b5fe9c9bc39f4335f67f6be8613921946480" dependencies = [ "async-trait", "bytes", @@ -1219,23 +1231,23 @@ dependencies = [ "jsonrpsee-types", "parking_lot", "pin-project", - "rand", + "rand 0.9.2", "rustc-hash 2.1.1", "serde", "serde_json", - "thiserror", + "thiserror 2.0.16", "tokio", "tokio-stream", + "tower", "tracing", ] [[package]] name = "jsonrpsee-http-client" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c872b6c9961a4ccc543e321bb5b89f6b2d2c7fe8b61906918273a3333c95400c" +checksum = "790bedefcec85321e007ff3af84b4e417540d5c87b3c9779b9e247d1bcc3dab8" dependencies = [ - "async-trait", "base64 0.22.1", "http-body", "hyper", @@ -1247,18 +1259,17 @@ dependencies = [ "rustls-platform-verifier", "serde", "serde_json", - "thiserror", + "thiserror 2.0.16", "tokio", "tower", - "tracing", "url", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e65763c942dfc9358146571911b0cd1c361c2d63e2d2305622d40d36376ca80" +checksum = "2da3f8ab5ce1bb124b6d082e62dffe997578ceaf0aeb9f3174a214589dc00f07" dependencies = [ "heck", "proc-macro-crate", @@ -1269,9 +1280,9 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e363146da18e50ad2b51a0a7925fc423137a0b1371af8235b1c231a0647328" +checksum = "4c51b7c290bb68ce3af2d029648148403863b982f138484a73f02a9dd52dbd7f" dependencies = [ "futures-util", "http", @@ -1286,7 +1297,7 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror", + "thiserror 2.0.16", "tokio", "tokio-stream", "tokio-util", @@ -1296,26 +1307,27 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" +checksum = "bc88ff4688e43cc3fa9883a8a95c6fa27aa2e76c96e610b737b6554d650d7fd5" dependencies = [ "http", "serde", "serde_json", - "thiserror", + "thiserror 2.0.16", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.24.9" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b3323d890aa384f12148e8d2a1fd18eb66e9e7e825f9de4fa53bcc19b93eef" +checksum = "9b6fceceeb05301cc4c065ab3bd2fa990d41ff4eb44e4ca1b30fa99c057c3e79" dependencies = [ "http", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", + "tower", "url", ] @@ -1381,7 +1393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.59.0", ] @@ -1589,6 +1601,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -1596,8 +1614,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1607,7 +1635,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -1616,7 +1654,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", ] [[package]] @@ -1666,7 +1713,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -1997,7 +2044,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2044,7 +2091,7 @@ dependencies = [ "http", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", ] @@ -2103,6 +2150,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "synstructure" version = "0.13.2" @@ -2120,7 +2173,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl 2.0.16", ] [[package]] @@ -2134,6 +2196,17 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -2239,17 +2312,16 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -2270,7 +2342,6 @@ 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", @@ -2412,6 +2483,24 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.5+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.0+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "webpki-root-certs" version = "0.26.11" @@ -2713,6 +2802,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" + [[package]] name = "writeable" version = "0.6.1" @@ -2726,7 +2821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] diff --git a/herodb/Cargo.toml b/herodb/Cargo.toml index f2f8c41..5eada28 100644 --- a/herodb/Cargo.toml +++ b/herodb/Cargo.toml @@ -23,7 +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"] } +jsonrpsee = { version = "0.26", features = ["http-client", "ws-client", "server", "macros"] } [dev-dependencies] redis = { version = "0.24", features = ["aio", "tokio-comp"] } diff --git a/herodb/docs/openrpc.json b/herodb/docs/openrpc.json new file mode 100644 index 0000000..4ac8694 --- /dev/null +++ b/herodb/docs/openrpc.json @@ -0,0 +1,290 @@ +{ + "openrpc": "1.2.6", + "info": { + "title": "HeroDB RPC API", + "version": "0.0.1", + "description": "Database management API for HeroDB" + }, + "servers": [ + { + "name": "HeroDB Server", + "url": "http://localhost:8080" + } + ], + "methods": [ + { + "name": "herodb_configureDatabase", + "summary": "Configure an existing database with specific settings", + "params": [ + { + "name": "db_index", + "description": "Database index to configure", + "schema": { + "type": "integer", + "minimum": 0 + }, + "required": true + }, + { + "name": "config", + "description": "Configuration object", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "storage_path": { + "type": "string" + }, + "max_size": { + "type": "integer" + }, + "redis_version": { + "type": "string" + } + } + }, + "required": true + } + ], + "result": { + "name": "success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "herodb_createDatabase", + "summary": "Create/pre-initialize a database at the specified index", + "params": [ + { + "name": "db_index", + "description": "Database index to create", + "schema": { + "type": "integer", + "minimum": 0 + }, + "required": true + } + ], + "result": { + "name": "success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "herodb_setDatabaseEncryption", + "summary": "Set encryption for a specific database index", + "params": [ + { + "name": "db_index", + "description": "Database index", + "schema": { + "type": "integer", + "minimum": 0 + }, + "required": true + }, + { + "name": "encryption_key", + "description": "Encryption key (write-only)", + "schema": { + "type": "string" + }, + "required": true + } + ], + "result": { + "name": "success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "herodb_listDatabases", + "summary": "List all database indices that exist", + "params": [], + "result": { + "name": "database_indices", + "schema": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + { + "name": "herodb_getDatabaseInfo", + "summary": "Get detailed information about a specific database", + "params": [ + { + "name": "db_index", + "description": "Database index", + "schema": { + "type": "integer", + "minimum": 0 + }, + "required": true + } + ], + "result": { + "name": "database_info", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "nullable": true + }, + "backend": { + "type": "string", + "enum": ["Redb"] + }, + "encrypted": { + "type": "boolean" + }, + "redis_version": { + "type": "string", + "nullable": true + }, + "storage_path": { + "type": "string", + "nullable": true + }, + "size_on_disk": { + "type": "integer", + "nullable": true + }, + "key_count": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "integer" + }, + "last_access": { + "type": "integer", + "nullable": true + } + } + } + } + }, + { + "name": "herodb_deleteDatabase", + "summary": "Delete a database and its files", + "params": [ + { + "name": "db_index", + "description": "Database index to delete", + "schema": { + "type": "integer", + "minimum": 0 + }, + "required": true + } + ], + "result": { + "name": "success", + "schema": { + "type": "boolean" + } + } + }, + { + "name": "herodb_getServerStats", + "summary": "Get server statistics", + "params": [], + "result": { + "name": "stats", + "schema": { + "type": "object", + "additionalProperties": { + "oneOf": [ + {"type": "string"}, + {"type": "integer"}, + {"type": "boolean"}, + {"type": "array"} + ] + } + } + } + } + ], + "components": { + "schemas": { + "DatabaseConfig": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "storage_path": { + "type": "string", + "nullable": true + }, + "max_size": { + "type": "integer", + "nullable": true + }, + "redis_version": { + "type": "string", + "nullable": true + } + } + }, + "DatabaseInfo": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string", + "nullable": true + }, + "backend": { + "type": "string", + "enum": ["Redb", "InMemory", "Custom"] + }, + "encrypted": { + "type": "boolean" + }, + "redis_version": { + "type": "string", + "nullable": true + }, + "storage_path": { + "type": "string", + "nullable": true + }, + "size_on_disk": { + "type": "integer", + "nullable": true + }, + "key_count": { + "type": "integer", + "nullable": true + }, + "created_at": { + "type": "integer" + }, + "last_access": { + "type": "integer", + "nullable": true + } + } + } + } + } +} \ No newline at end of file diff --git a/herodb/src/lib.rs b/herodb/src/lib.rs index 9a2f7fe..f4508ad 100644 --- a/herodb/src/lib.rs +++ b/herodb/src/lib.rs @@ -1,4 +1,4 @@ -pub mod age; // NEW +pub mod age; pub mod cmd; pub mod crypto; pub mod error; @@ -8,3 +8,4 @@ pub mod rpc; pub mod rpc_server; pub mod server; pub mod storage; +pub mod openrpc_spec; diff --git a/herodb/src/main.rs b/herodb/src/main.rs index 2e1c3f7..761986b 100644 --- a/herodb/src/main.rs +++ b/herodb/src/main.rs @@ -1,5 +1,3 @@ -// #![allow(unused_imports)] - use std::sync::Arc; use tokio::sync::Mutex; use tokio::net::TcpListener; @@ -72,7 +70,7 @@ async fn main() { tokio::time::sleep(std::time::Duration::from_millis(100)).await; // Start RPC server if enabled - let rpc_handle = if args.enable_rpc { + let _rpc_handle = if args.enable_rpc { let rpc_addr = format!("127.0.0.1:{}", args.rpc_port).parse().unwrap(); let base_dir = args.dir.clone(); diff --git a/herodb/src/openrpc_spec.rs b/herodb/src/openrpc_spec.rs new file mode 100644 index 0000000..09779bf --- /dev/null +++ b/herodb/src/openrpc_spec.rs @@ -0,0 +1,2 @@ +/// The OpenRPC specification for the HeroDB JSON-RPC API +pub const OPENRPC_SPEC: &str = include_str!("../docs/openrpc.json"); \ No newline at end of file diff --git a/herodb/src/rpc.rs b/herodb/src/rpc.rs index fef642e..98140e4 100644 --- a/herodb/src/rpc.rs +++ b/herodb/src/rpc.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; use std::sync::Arc; -use tokio::sync::{RwLock, Mutex}; +use tokio::sync::Mutex; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use serde::{Deserialize, Serialize}; +use serde_json::Value; use crate::server::Server; -use crate::options::DBOption; +use crate::openrpc_spec::OPENRPC_SPEC; /// Database backend types #[derive(Debug, Clone, Serialize, Deserialize)] @@ -39,7 +40,7 @@ pub struct DatabaseInfo { } /// RPC trait for HeroDB management -#[rpc(server, client, namespace = "herodb")] +#[rpc(client, server, namespace = "herodb")] pub trait Rpc { /// Configure an existing database with specific settings #[method(name = "configureDatabase")] @@ -74,7 +75,16 @@ pub trait Rpc { async fn get_server_stats(&self) -> RpcResult>; } +/// RPC Discovery trait for API introspection +#[rpc(client, server, namespace = "rpc", namespace_separator = ".")] +pub trait RpcDiscovery { + /// Get the OpenRPC specification for API discovery + #[method(name = "discover")] + async fn discover(&self) -> RpcResult; +} + /// RPC Server implementation +#[derive(Clone)] pub struct RpcServerImpl { /// Reference to the main Redis server main_server: Arc>, @@ -138,7 +148,7 @@ impl RpcServer for RpcServerImpl { } } - async fn set_database_encryption(&self, db_index: u64, encryption_key: String) -> RpcResult { + async fn set_database_encryption(&self, db_index: u64, _encryption_key: String) -> RpcResult { // Note: Encryption is determined at database creation time based on db_index // DB 0-9 are non-encrypted, DB 10+ are encrypted // This method is mainly for documentation/configuration purposes @@ -272,4 +282,19 @@ impl RpcServer for RpcServerImpl { Ok(stats) } +} + +#[jsonrpsee::core::async_trait] +impl RpcDiscoveryServer for RpcServerImpl { + async fn discover(&self) -> RpcResult { + // Parse the OpenRPC spec JSON and return it + match serde_json::from_str(OPENRPC_SPEC) { + Ok(spec) => Ok(spec), + Err(e) => Err(jsonrpsee::types::ErrorObjectOwned::owned( + -32000, + format!("Failed to parse OpenRPC specification: {}", e), + None::<()> + )) + } + } } \ No newline at end of file diff --git a/herodb/src/rpc_server.rs b/herodb/src/rpc_server.rs index ab8cb14..34bca31 100644 --- a/herodb/src/rpc_server.rs +++ b/herodb/src/rpc_server.rs @@ -4,7 +4,7 @@ use jsonrpsee::RpcModule; use std::sync::Arc; use tokio::sync::Mutex; -use crate::rpc::{RpcServer, RpcServerImpl}; +use crate::rpc::{RpcServer, RpcDiscoveryServer, RpcServerImpl}; use crate::server::Server; /// Start the RPC server on the specified address @@ -18,11 +18,11 @@ pub async fn start_rpc_server( // Create the RPC module let mut module = RpcModule::new(()); - module.merge(RpcServer::into_rpc(rpc_impl))?; + module.merge(RpcServer::into_rpc(rpc_impl.clone()))?; + module.merge(RpcDiscoveryServer::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?; diff --git a/herodb/tests/redis_tests.rs b/herodb/tests/redis_tests.rs index 4e88e0d..c32ba2f 100644 --- a/herodb/tests/redis_tests.rs +++ b/herodb/tests/redis_tests.rs @@ -222,7 +222,7 @@ async fn test_hash_operations() { #[tokio::test] async fn test_expiration() { - let (mut server, port) = start_test_server("expiration").await; + let (server, port) = start_test_server("expiration").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -270,7 +270,7 @@ async fn test_expiration() { #[tokio::test] async fn test_scan_operations() { - let (mut server, port) = start_test_server("scan").await; + let (server, port) = start_test_server("scan").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -306,7 +306,7 @@ async fn test_scan_operations() { #[tokio::test] async fn test_hscan_operations() { - let (mut server, port) = start_test_server("hscan").await; + let (server, port) = start_test_server("hscan").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -338,7 +338,7 @@ async fn test_hscan_operations() { #[tokio::test] async fn test_transaction_operations() { - let (mut server, port) = start_test_server("transaction").await; + let (server, port) = start_test_server("transaction").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -381,7 +381,7 @@ async fn test_transaction_operations() { #[tokio::test] async fn test_discard_transaction() { - let (mut server, port) = start_test_server("discard").await; + let (server, port) = start_test_server("discard").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -418,7 +418,7 @@ async fn test_discard_transaction() { #[tokio::test] async fn test_type_command() { - let (mut server, port) = start_test_server("type").await; + let (server, port) = start_test_server("type").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -453,7 +453,7 @@ async fn test_type_command() { #[tokio::test] async fn test_config_commands() { - let (mut server, port) = start_test_server("config").await; + let (server, port) = start_test_server("config").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -484,7 +484,7 @@ async fn test_config_commands() { #[tokio::test] async fn test_info_command() { - let (mut server, port) = start_test_server("info").await; + let (server, port) = start_test_server("info").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -513,7 +513,7 @@ async fn test_info_command() { #[tokio::test] async fn test_error_handling() { - let (mut server, port) = start_test_server("error").await; + let (server, port) = start_test_server("error").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) @@ -551,7 +551,7 @@ async fn test_error_handling() { #[tokio::test] async fn test_list_operations() { - let (mut server, port) = start_test_server("list").await; + let (server, port) = start_test_server("list").await; tokio::spawn(async move { let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) diff --git a/herodb/tests/rpc_tests.rs b/herodb/tests/rpc_tests.rs index 1fa6628..ea2d9be 100644 --- a/herodb/tests/rpc_tests.rs +++ b/herodb/tests/rpc_tests.rs @@ -1,9 +1,4 @@ -use std::net::SocketAddr; -use jsonrpsee::http_client::HttpClientBuilder; -use jsonrpsee::core::client::ClientT; -use serde_json::json; - -use herodb::rpc::{RpcClient, BackendType, DatabaseConfig}; +use herodb::rpc::{BackendType, DatabaseConfig}; #[tokio::test] async fn test_rpc_server_basic() {