futures_jsonrpc/
lib.rs

1//! Futures + JSON-RPC
2//!
3//! A lightweight remote procedure call protocol. It is designed to be simple! And, with futures, even more flexible!
4//!
5//! This 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).
6//!
7//! It is fully compliant with [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification).
8//!
9//! ## Installation
10//!
11//! Add this to your `Cargo.toml`:
12//!
13//! ```toml
14//! [dependencies]
15//! futures_jsonrpc = "0.2"
16//! ```
17//!
18//! ## Minimal example
19//!
20//! ```
21//! use futures_jsonrpc::futures::prelude::*;
22//! use futures_jsonrpc::*;
23//! use serde_json::Number;
24//!
25//! // This macro will avoid some boilerplating, leaving only the `Future` implementation to be done
26//! //
27//! // Check for additional information in the detailed explanation below
28//! //
29//! // Also, check `generate_method_with_data_and_future` and `generate_method_with_lifetime_data_and_future`
30//! generate_method!(
31//!     CopyParams,
32//!     impl Future for CopyParams {
33//!         type Item = Option<JrpcResponse>;
34//!         type Error = ErrorVariant;
35//!
36//!         fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
37//!             let request = self.get_request()?;
38//!             let params = request.get_params().clone().unwrap_or(JsonValue::Null);
39//!
40//!             let message = JrpcResponseParam::generate_result(params)
41//!                 .and_then(|result| request.generate_response(result))?;
42//!
43//!             Ok(Async::Ready(Some(message)))
44//!         }
45//!     }
46//! );
47//!
48//! fn main() {
49//!     // `JrpcHandler` instance is responsible for registering the JSON-RPC methods and receiving the
50//!     // requests.
51//!     //
52//!     // This is full `Arc`/`RwLock` protected. Therefore, it can be freely copied/sent among
53//!     // threads.
54//!     let handler = JrpcHandler::new().unwrap();
55//!
56//!     handler
57//!         // `register_method` will tie the method signature to an instance, not a generic. This
58//!         // means we can freely mutate this instance across different signatures.
59//!         .register_method("some/copyParams", CopyParams::new().unwrap())
60//!
61//!         .and_then(|h| {
62//!             // `handle_message` will receive a raw implementation of `ToString` and return the
63//!             // associated future. If no future is found, an instance of
64//!             // `Err(ErrorVariant::MethodSignatureNotFound(String))` is returned
65//!             h.handle_message(
66//!                 r#"
67//!                 {
68//!                     "jsonrpc": "2.0",
69//!                     "method": "some/copyParams",
70//!                     "params": [42, 23],
71//!                     "id": 531
72//!                 }"#,
73//!             )
74//!         })
75//!
76//!         // Just waiting for the poll of future. Check futures documentation.
77//!         .and_then(|future| future.wait())
78//!         .and_then(|result| {
79//!             // The result is an instance of `JrpcResponse`
80//!             let result = result.unwrap();
81//!
82//!             assert_eq!(result.get_jsonrpc(), "2.0");
83//!             assert_eq!(
84//!                 result.get_result(),
85//!                 &Some(JsonValue::Array(vec![
86//!                     JsonValue::Number(Number::from(42)),
87//!                     JsonValue::Number(Number::from(23)),
88//!                 ]))
89//!             );
90//!             assert!(result.get_error().is_none());
91//!             assert_eq!(result.get_id(), &JsonValue::Number(Number::from(531)));
92//!             Ok(())
93//!         })
94//!         .unwrap();
95//! }
96//! ```
97//!
98//! ## Detailed explanation
99//!
100//! ```
101//! use futures_jsonrpc::futures::prelude::*;
102//! use futures_jsonrpc::*;
103//! use std::marker::PhantomData;
104//!
105//! // `JrpcHandler` use foreign structures as controllers
106//! // This example will reflect `generate_method_with_lifetime_data_and_future` macro
107//! #[derive(Debug, Clone)]
108//! pub struct CopyParams<'r> {
109//!     request: Option<JrpcRequest>,
110//!     data: (String, i32, PhantomData<&'r ()>),
111//! }
112//!
113//! // This implementation is essentially some boilerplate to hold the data that may be used by the
114//! // future poll
115//! impl<'r> CopyParams<'r> {
116//!     // The `new` method will always receive a n-tuple as parameter to store data
117//!     //
118//!     // It is recommended to use atomic types, or `Arc` protected for heavy data. At every request,
119//!     // we `Clone` this struct to send it to the responsible thread
120//!     pub fn new(data: (String, i32, PhantomData<&'r ()>)) -> Result<Self, ErrorVariant> {
121//!         let request = None;
122//!         let some_notification = CopyParams { request, data };
123//!         Ok(some_notification)
124//!     }
125//!
126//!     // The `get_data` will support the future poll with additional information that will not be
127//!     // available in the JsonRpc request
128//!     pub fn get_data(&self) -> &(String, i32, PhantomData<&'r ()>) {
129//!         &self.data
130//!     }
131//!
132//!     // The `get_request` method will return the JsonRpc request to the future poll
133//!     pub fn get_request(&self) -> Result<JrpcRequest, ErrorVariant> {
134//!         let request = self.request.clone();
135//!         request
136//!             .map(|r| Ok(r.clone()))
137//!             .unwrap_or(Err(ErrorVariant::NoRequestProvided))
138//!     }
139//!
140//!     // This method is of internal usage to receive the request from `JrpcHandler`
141//!     pub fn set_request(mut self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
142//!         self.request = Some(request);
143//!         Ok(self)
144//!     }
145//!
146//!     // This "fork" will be performed every time a new request is received, allowing async
147//!     // processing
148//!     pub fn clone_with_request(&self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
149//!         self.clone().set_request(request)
150//!     }
151//! }
152//!
153//! // `JrpcHandler` will just return a pollable associated future.
154//! //
155//! // The main implementation will go here
156//! //
157//! // Tokio provides very good documentation on futures. Check it: https://tokio.rs/
158//! impl<'r> Future for CopyParams<'r> {
159//!     // Optimally, we want to use JrpcResponse, for it is guaranteed to respect the JSON-RPC
160//!     // specification. But, we can change the response here to something else, if required.
161//!     type Item = Option<JrpcResponse>;
162//!     type Error = ErrorVariant;
163//!
164//!     fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
165//!         // We fetch the provided request to copy the data
166//!         let request = self.get_request()?;
167//!
168//!         // Here we can receive additional that that's not available in the request
169//!         let (_text, _value, _) = self.get_data();
170//!
171//!         // Do something with the request
172//!         // In this example, we are copying the parameters
173//!         let params = request.get_params().clone().unwrap_or(JsonValue::Null);
174//!
175//!         // `generate_response` will receive an enum `JrpcResponseParam` and reply
176//!         // with either an error or success.
177//!         let message = JrpcResponseParam::generate_result(params)
178//!             .and_then(|result| request.generate_response(result))?;
179//!
180//!         // Then, our reply is ready
181//!         Ok(Async::Ready(Some(message)))
182//!     }
183//! }
184//!
185//! // The handler will call this trait to spawn a new future and process it when a registered method
186//! // is requested.
187//! impl<'r> JrpcMethodTrait<'r> for CopyParams<'r> {
188//!     // `generate_future` can generate any `Future` that respects the trait signature. This can be a
189//!     // foreign structure, or just a copy of `self`, in case it implements `Future`. This can also
190//!     // be a decision based on the received `JrpcRequest`.
191//!     //
192//!     // Since its not a reference, there are no restrictions.
193//!     fn generate_future(
194//!         &self,
195//!         request: JrpcRequest,
196//!     ) -> Result<Box<'r + Future<Item = Option<JrpcResponse>, Error = ErrorVariant>>, ErrorVariant>
197//!     {
198//!         Ok(Box::new(self.clone_with_request(request)?))
199//!     }
200//! }
201//! ```
202
203#[macro_use]
204extern crate log;
205
206pub use crate::handler::JrpcHandler;
207pub use crate::method::JrpcMethodTrait;
208pub use crate::parser::{JrpcError, JrpcErrorEnum, JrpcRequest, JrpcResponse, JrpcResponseParam};
209pub use futures;
210pub use serde_json::error::Error as JsonError;
211pub use serde_json::Value as JsonValue;
212use std::fmt;
213use std::io::Error as IoError;
214
215pub mod handler;
216pub mod method;
217pub mod parser;
218
219#[derive(Debug)]
220pub enum ErrorVariant {
221    RwLockPoisoned,
222    MethodSignatureNotFound(String),
223    JsonParseError(JsonError),
224    InvalidJsonRpcVersion,
225    InvalidJsonRpcId,
226    ResponseCannotContainResultAndError,
227    ResponseMustContainResultOrError,
228    NoRequestProvided,
229    IoError(IoError),
230    InternalError,
231    InternalErrorMessage(String),
232}
233
234impl fmt::Display for ErrorVariant {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        match self {
237            ErrorVariant::MethodSignatureNotFound(s) => {
238                write!(f, "Method signature '{}' not found", s)
239            }
240            ErrorVariant::InternalErrorMessage(s) => write!(f, "An error ocurred: {}", s),
241            _ => write!(f, "{:?}", self),
242        }
243    }
244}
245
246#[macro_export]
247macro_rules! generate_method {
248    ($struct_identifier:ident, $future:item) => {
249        #[derive(Debug, Clone)]
250        pub struct $struct_identifier {
251            request: Option<JrpcRequest>,
252        }
253
254        impl $struct_identifier {
255            pub fn new() -> Result<Self, ErrorVariant> {
256                let request = None;
257                let some_notification = $struct_identifier {
258                    request,
259                };
260                Ok(some_notification)
261            }
262
263            pub fn get_request(&self) -> Result<JrpcRequest, ErrorVariant> {
264                let request = self.request.clone();
265                request
266                    .map(|r| Ok(r.clone()))
267                    .unwrap_or(Err(ErrorVariant::NoRequestProvided))
268            }
269
270            pub fn set_request(mut self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
271                self.request = Some(request);
272                Ok(self)
273            }
274
275            pub fn clone_with_request(&self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
276                self.clone().set_request(request)
277            }
278        }
279
280        $future
281
282        impl<'r> JrpcMethodTrait<'r> for $struct_identifier {
283            fn generate_future(
284                &self,
285                request: JrpcRequest,
286            ) -> Result<
287                Box<'r + Future<Item = Option<JrpcResponse>, Error = ErrorVariant>>,
288                ErrorVariant,
289            > {
290                Ok(Box::new(self.clone_with_request(request)?))
291            }
292        }
293    };
294}
295
296#[macro_export]
297macro_rules! generate_method_with_data_and_future {
298    ($struct_identifier:ident, $data:ty, $future:item) => {
299        #[derive(Debug, Clone)]
300        pub struct $struct_identifier {
301            request: Option<JrpcRequest>,
302            data: $data,
303        }
304
305        impl $struct_identifier {
306            pub fn new(data: $data) -> Result<Self, ErrorVariant> {
307                let request = None;
308                let some_notification = $struct_identifier {
309                    request,
310                    data,
311                };
312                Ok(some_notification)
313            }
314
315            pub fn get_data(&self) -> &$data {
316                &self.data
317            }
318
319            pub fn get_request(&self) -> Result<JrpcRequest, ErrorVariant> {
320                let request = self.request.clone();
321                request
322                    .map(|r| Ok(r.clone()))
323                    .unwrap_or(Err(ErrorVariant::NoRequestProvided))
324            }
325
326            pub fn set_request(mut self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
327                self.request = Some(request);
328                Ok(self)
329            }
330
331            pub fn clone_with_request(&self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
332                self.clone().set_request(request)
333            }
334        }
335
336        $future
337
338        impl<'r> JrpcMethodTrait<'r> for $struct_identifier {
339            fn generate_future(
340                &self,
341                request: JrpcRequest,
342            ) -> Result<
343                Box<'r + Future<Item = Option<JrpcResponse>, Error = ErrorVariant>>,
344                ErrorVariant,
345            > {
346                Ok(Box::new(self.clone_with_request(request)?))
347            }
348        }
349    };
350}
351
352#[macro_export]
353macro_rules! generate_method_with_lifetime_data_and_future {
354    ($struct_identifier:ident, $lifetime:tt, $data:ty, $future:item) => {
355        #[derive(Debug, Clone)]
356        pub struct $struct_identifier<$lifetime> {
357            request: Option<JrpcRequest>,
358            data: $data,
359        }
360
361        impl<$lifetime> $struct_identifier<$lifetime> {
362            pub fn new(data: $data) -> Result<Self, ErrorVariant> {
363                let request = None;
364                let some_notification = $struct_identifier {
365                    request,
366                    data,
367                };
368                Ok(some_notification)
369            }
370
371            pub fn get_data(&self) -> &$data {
372                &self.data
373            }
374
375            pub fn get_request(&self) -> Result<JrpcRequest, ErrorVariant> {
376                let request = self.request.clone();
377                request
378                    .map(|r| Ok(r.clone()))
379                    .unwrap_or(Err(ErrorVariant::NoRequestProvided))
380            }
381
382            pub fn set_request(mut self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
383                self.request = Some(request);
384                Ok(self)
385            }
386
387            pub fn clone_with_request(&self, request: JrpcRequest) -> Result<Self, ErrorVariant> {
388                self.clone().set_request(request)
389            }
390        }
391
392        $future
393
394        impl<$lifetime> JrpcMethodTrait<$lifetime> for $struct_identifier<$lifetime> {
395            fn generate_future(
396                &self,
397                request: JrpcRequest,
398            ) -> Result<
399                Box<$lifetime + Future<Item = Option<JrpcResponse>, Error = ErrorVariant>>,
400                ErrorVariant,
401            > {
402                Ok(Box::new(self.clone_with_request(request)?))
403            }
404        }
405    };
406}