{"id":13439844,"url":"https://github.com/vlopes11/futures-jsonrpc","last_synced_at":"2025-09-23T01:30:31.206Z","repository":{"id":57632649,"uuid":"181777068","full_name":"vlopes11/futures-jsonrpc","owner":"vlopes11","description":"Futures implementation for JSON-RPC","archived":false,"fork":false,"pushed_at":"2019-05-29T05:51:15.000Z","size":54,"stargazers_count":14,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-21T12:46:17.544Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vlopes11.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-16T22:30:46.000Z","updated_at":"2023-08-09T13:59:09.000Z","dependencies_parsed_at":"2022-08-31T13:01:26.033Z","dependency_job_id":null,"html_url":"https://github.com/vlopes11/futures-jsonrpc","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vlopes11/futures-jsonrpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vlopes11%2Ffutures-jsonrpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vlopes11%2Ffutures-jsonrpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vlopes11%2Ffutures-jsonrpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vlopes11%2Ffutures-jsonrpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vlopes11","download_url":"https://codeload.github.com/vlopes11/futures-jsonrpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vlopes11%2Ffutures-jsonrpc/sbom","scorecard":{"id":925611,"data":{"date":"2025-08-04","repo":{"name":"github.com/vlopes11/futures-jsonrpc","commit":"b2160805cc404cc503849a9f8291be187fc62bf2"},"scorecard":{"version":"v5.2.1-28-gc1d103a9","commit":"c1d103a9bb9f635ec7260bf9aa0699466fa4be0e"},"score":2.9,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: RUSTSEC-2019-0035 / GHSA-mmc9-pwm7-qj5w"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-25T11:51:38.816Z","repository_id":57632649,"created_at":"2025-08-25T11:51:38.816Z","updated_at":"2025-08-25T11:51:38.816Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276502707,"owners_count":25653732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-22T02:00:08.972Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:01:17.572Z","updated_at":"2025-09-23T01:30:30.913Z","avatar_url":"https://github.com/vlopes11.png","language":"Rust","funding_links":[],"categories":["Libraries","库","库 Libraries"],"sub_categories":["Network programming","网络编程","网络编程 Network programming"],"readme":"# futures-jsonrpc\n\n[![Crate](https://img.shields.io/crates/v/futures-jsonrpc.svg)](https://crates.io/crates/futures-jsonrpc)\n[![Documentation](https://docs.rs/futures-jsonrpc/badge.svg)](https://docs.rs/futures-jsonrpc)\n[![Travis Status](https://travis-ci.org/vlopes11/futures-jsonrpc.svg?branch=master)](https://travis-ci.org/vlopes11/futures-jsonrpc)\n[![Join the chat at https://gitter.im/futures-jsonrpc/community](https://badges.gitter.im/futures-jsonrpc/community.svg)](https://gitter.im/futures-jsonrpc/community?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n## Futures + JSON-RPC\n\nA lightweight remote procedure call protocol. It is designed to be simple! And, with futures, even more flexible!\n\nThis crate will associate [Future](futures::future::Future)s with method signatures via [register_method](handler::JrpcHandler::register_method), and parse/handle JSON-RPC messages via [handle_message](handler::JrpcHandler::handle_message).\n\nIt is fully compliant with [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification).\n\n## Contributing\n\nThe crate is not test covered yet! Any PR with a test coverage will be much appreciated :)\n\n## Installation\n\nAdd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\nfutures-jsonrpc = \"0.2\"\n```\n\n## Minimal example\n\n```rust\nuse futures_jsonrpc::futures::prelude::*;\nuse futures_jsonrpc::*;\nuse serde_json::Number;\n\n// This macro will avoid some boilerplating, leaving only the `Future` implementation to be done\n//\n// Check for additional information in the detailed explanation below\n//\n// Also, check `generate_method_with_data_and_future` and `generate_method_with_lifetime_data_and_future`\ngenerate_method!(\n    CopyParams,\n    impl Future for CopyParams {\n        type Item = Option\u003cJrpcResponse\u003e;\n        type Error = ErrorVariant;\n\n        fn poll(\u0026mut self) -\u003e Result\u003cAsync\u003cSelf::Item\u003e, Self::Error\u003e {\n            let request = self.get_request()?;\n            let params = request.get_params().clone().unwrap_or(JsonValue::Null);\n\n            let message = JrpcResponseParam::generate_result(params)\n                .and_then(|result| request.generate_response(result))?;\n\n            Ok(Async::Ready(Some(message)))\n        }\n    }\n);\n\nfn main() {\n    // `JrpcHandler` instance is responsible for registering the JSON-RPC methods and receiving the\n    // requests.\n    //\n    // This is full `Arc`/`RwLock` protected. Therefore, it can be freely copied/sent among\n    // threads.\n    let handler = JrpcHandler::new().unwrap();\n\n    handler\n        // `register_method` will tie the method signature to an instance, not a generic. This\n        // means we can freely mutate this instance across different signatures.\n        .register_method(\"some/copyParams\", CopyParams::new().unwrap())\n\n        .and_then(|h| {\n            // `handle_message` will receive a raw implementation of `ToString` and return the\n            // associated future. If no future is found, an instance of\n            // `Err(ErrorVariant::MethodSignatureNotFound(String))` is returned\n            h.handle_message(\n                r#\"\n                {\n                    \"jsonrpc\": \"2.0\",\n                    \"method\": \"some/copyParams\",\n                    \"params\": [42, 23],\n                    \"id\": 531\n                }\"#,\n            )\n        })\n\n        // Just waiting for the poll of future. Check futures documentation.\n        .and_then(|future| future.wait())\n        .and_then(|result| {\n            // The result is an instance of `JrpcResponse`\n            let result = result.unwrap();\n\n            assert_eq!(result.get_jsonrpc(), \"2.0\");\n            assert_eq!(\n                result.get_result(),\n                \u0026Some(JsonValue::Array(vec![\n                    JsonValue::Number(Number::from(42)),\n                    JsonValue::Number(Number::from(23)),\n                ]))\n            );\n            assert!(result.get_error().is_none());\n            assert_eq!(result.get_id(), \u0026JsonValue::Number(Number::from(531)));\n            Ok(())\n        })\n        .unwrap();\n}\n```\n\n## Detailed explanation\n\n```rust\nuse futures_jsonrpc::futures::prelude::*;\nuse futures_jsonrpc::*;\nuse std::marker::PhantomData;\n\n// `JrpcHandler` use foreign structures as controllers\n// This example will reflect `generate_method_with_lifetime_data_and_future` macro\n#[derive(Debug, Clone)]\npub struct CopyParams\u003c'r\u003e {\n    request: Option\u003cJrpcRequest\u003e,\n    data: (String, i32, PhantomData\u003c\u0026'r ()\u003e),\n}\n\n// This implementation is essentially some boilerplate to hold the data that may be used by the\n// future poll\nimpl\u003c'r\u003e CopyParams\u003c'r\u003e {\n    // The `new` method will always receive a n-tuple as parameter to store data\n    //\n    // It is recommended to use atomic types, or `Arc` protected for heavy data. At every request,\n    // we `Clone` this struct to send it to the responsible thread\n    pub fn new(data: (String, i32, PhantomData\u003c\u0026'r ()\u003e)) -\u003e Result\u003cSelf, ErrorVariant\u003e {\n        let request = None;\n        let some_notification = CopyParams { request, data };\n        Ok(some_notification)\n    }\n\n    // The `get_data` will support the future poll with additional information that will not be\n    // available in the JsonRpc request\n    pub fn get_data(\u0026self) -\u003e \u0026(String, i32, PhantomData\u003c\u0026'r ()\u003e) {\n        \u0026self.data\n    }\n\n    // The `get_request` method will return the JsonRpc request to the future poll\n    pub fn get_request(\u0026self) -\u003e Result\u003cJrpcRequest, ErrorVariant\u003e {\n        let request = self.request.clone();\n        request\n            .map(|r| Ok(r.clone()))\n            .unwrap_or(Err(ErrorVariant::NoRequestProvided))\n    }\n\n    // This method is of internal usage to receive the request from `JrpcHandler`\n    pub fn set_request(mut self, request: JrpcRequest) -\u003e Result\u003cSelf, ErrorVariant\u003e {\n        self.request = Some(request);\n        Ok(self)\n    }\n\n    // This \"fork\" will be performed every time a new request is received, allowing async\n    // processing\n    pub fn clone_with_request(\u0026self, request: JrpcRequest) -\u003e Result\u003cSelf, ErrorVariant\u003e {\n        self.clone().set_request(request)\n    }\n}\n\n// `JrpcHandler` will just return a pollable associated future.\n//\n// The main implementation will go here\n//\n// Tokio provides very good documentation on futures. Check it: https://tokio.rs/\nimpl\u003c'r\u003e Future for CopyParams\u003c'r\u003e {\n    // Optimally, we want to use JrpcResponse, for it is guaranteed to respect the JSON-RPC\n    // specification. But, we can change the response here to something else, if required.\n    type Item = Option\u003cJrpcResponse\u003e;\n    type Error = ErrorVariant;\n\n    fn poll(\u0026mut self) -\u003e Result\u003cAsync\u003cSelf::Item\u003e, Self::Error\u003e {\n        // We fetch the provided request to copy the data\n        let request = self.get_request()?;\n\n        // Here we can receive additional that that's not available in the request\n        let (_text, _value, _) = self.get_data();\n\n        // Do something with the request\n        // In this example, we are copying the parameters\n        let params = request.get_params().clone().unwrap_or(JsonValue::Null);\n\n        // `generate_response` will receive an enum `JrpcResponseParam` and reply\n        // with either an error or success.\n        let message = JrpcResponseParam::generate_result(params)\n            .and_then(|result| request.generate_response(result))?;\n\n        // Then, our reply is ready\n        Ok(Async::Ready(Some(message)))\n    }\n}\n\n// The handler will call this trait to spawn a new future and process it when a registered method\n// is requested.\nimpl\u003c'r\u003e JrpcMethodTrait\u003c'r\u003e for CopyParams\u003c'r\u003e {\n    // `generate_future` can generate any `Future` that respects the trait signature. This can be a\n    // foreign structure, or just a copy of `self`, in case it implements `Future`. This can also\n    // be a decision based on the received `JrpcRequest`.\n    //\n    // Since its not a reference, there are no restrictions.\n    fn generate_future(\n        \u0026self,\n        request: JrpcRequest,\n    ) -\u003e Result\u003cBox\u003c'r + Future\u003cItem = Option\u003cJrpcResponse\u003e, Error = ErrorVariant\u003e\u003e, ErrorVariant\u003e\n    {\n        Ok(Box::new(self.clone_with_request(request)?))\n    }\n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvlopes11%2Ffutures-jsonrpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvlopes11%2Ffutures-jsonrpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvlopes11%2Ffutures-jsonrpc/lists"}