Skip to content

Commit

Permalink
Merge pull request #6 from layer1capital/5
Browse files Browse the repository at this point in the history
fix #5
  • Loading branch information
bddap authored Apr 23, 2019
2 parents dd75c12 + f89c56b commit 2336bbc
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 38 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = """
Convert a trait definition into a jsonrpc api.
"""
repository = "https://github.com/layer1capital/easy-jsonrpc"
version = "0.4.1"
version = "0.5.0"
authors = ["Andrew Dirksen <andrew@dirksen.com>"]
license = "Apache-2.0"
documentation = "https://docs.rs/easy-jsonrpc"
Expand All @@ -13,7 +13,7 @@ readme = "readme.md"
keywords = ["json", "rpc", "macro", "client", "server"]

[dependencies]
easy-jsonrpc-proc-macro = { path = "./proc_macros", version = "0.4.1" }
easy-jsonrpc-proc-macro = { path = "./proc_macros", version = "0.5.0" }
serde_json = "1"
serde = "1"
jsonrpc-core = "10.0.1"
Expand Down
2 changes: 1 addition & 1 deletion proc_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = """
Procedural macro portion of easy-jsonrpc. Don't use this crate directly. Use easy-jsonrpc instead.
"""
repository = "https://github.com/layer1capital/easy-jsonrpc"
version = "0.4.1"
version = "0.5.0"
authors = ["Andrew Dirksen <andrew@dirksen.com>"]
license = "Apache-2.0"
edition = "2018"
Expand Down
33 changes: 24 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Easy JSON RPC

Generate a jsonrpc handler and client helpers from a trait definition. [docs](https://docs.rs/easy-jsonrpc)
Generates an rpc handler and client helpers based on a trait definition. [docs](https://docs.rs/easy-jsonrpc)

## Defining an api

Expand All @@ -27,7 +27,7 @@ The rpc macro generates
## Server side usage

```rust
use easy_jsonrpc::Handler;
use easy_jsonrpc::{Handler, MaybeReply};
use serde_json::json;

struct AdderImpl;
Expand All @@ -47,7 +47,7 @@ assert_eq!(
"params": [1, 2],
"id": 1
})),
Some(json!({
MaybeReply::Reply(json!({
"jsonrpc": "2.0",
"result": 3,
"id": 1
Expand All @@ -60,7 +60,10 @@ assert_eq!(
```rust
let bind = adder::checked_add(1, 2).unwrap();
let (call, tracker) = bind.call();
let json_response = handler.handle_request(call.as_request()).unwrap();
let json_response = match handler.handle_request(call.as_request()) {
MaybeReply::Reply(resp) => resp,
MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker.get_return(&mut response).unwrap(), Some(3));
```
Expand All @@ -80,7 +83,7 @@ assert_eq!(
},
"id": 1
})),
Some(json!({
MaybeReply::Reply(json!({
"jsonrpc": "2.0",
"result": 3,
"id": 1
Expand All @@ -97,11 +100,18 @@ assert_eq!(
"method": "wrapping_add",
"params": [1, 1]
})),
None
MaybeReply::DontReply
);

Notification are easy to generate.

```rust
let bind = adder::checked_add(0, 0).unwrap();
let notification = bind.notification().as_request();
assert_eq!(handler.handle_request(notification), MaybeReply::DontReply);
```

Batch calls are possible
Batch calls are possible.

```rust
use easy_jsonrpc::Call;
Expand All @@ -111,8 +121,13 @@ let bind1 = adder::checked_add(1, 0).unwrap();
let (call1, tracker1) = bind1.call();
let bind2 = adder::wrapping_add(1, 1).unwrap();
let (call2, tracker2) = bind2.call();
let json_request = Call::batch_request(&[call0, call1, call2]);
let json_response = handler.handle_request(json_request).unwrap();
let bind3 = adder::wrapping_add(1, 1).unwrap();
let call3 = bind3.notification();
let json_request = Call::batch_request(&[call0, call1, call2, call3]);
let json_response = match handler.handle_request(json_request) {
MaybeReply::Reply(resp) => resp,
MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker1.get_return(&mut response).unwrap(), Some(1));
assert_eq!(tracker0.get_return(&mut response).unwrap(), Some(0));
Expand Down
97 changes: 71 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The rpc macro generates
# }
# fn takes_ref(&self, rf: &isize);
# }
use easy_jsonrpc::Handler;
use easy_jsonrpc::{Handler, MaybeReply};
use serde_json::json;
struct AdderImpl;
Expand All @@ -56,7 +56,7 @@ assert_eq!(
"params": [1, 2],
"id": 1
})),
Some(json!({
MaybeReply::Reply(json!({
"jsonrpc": "2.0",
"result": 3,
"id": 1
Expand All @@ -75,7 +75,7 @@ assert_eq!(
# fn is_some(&self, a: Option<usize>) -> bool;
# fn takes_ref(&self, rf: &isize);
# }
# use easy_jsonrpc::Handler;
# use easy_jsonrpc::{Handler, MaybeReply};
# use serde_json::json;
# struct AdderImpl;
# impl Adder for AdderImpl {
Expand All @@ -93,7 +93,10 @@ assert_eq!(
# let handler = (&AdderImpl {} as &dyn Adder);
let bind = adder::checked_add(1, 2).unwrap();
let (call, tracker) = bind.call();
let json_response = handler.handle_request(call.as_request()).unwrap();
let json_response = match handler.handle_request(call.as_request()) {
MaybeReply::Reply(resp) => resp,
MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker.get_return(&mut response).unwrap(), Some(3));
```
Expand All @@ -109,7 +112,7 @@ assert_eq!(tracker.get_return(&mut response).unwrap(), Some(3));
# fn is_some(&self, a: Option<usize>) -> bool;
# fn takes_ref(&self, rf: &isize);
# }
# use easy_jsonrpc::Handler;
# use easy_jsonrpc::{Handler, MaybeReply};
# use serde_json::json;
# struct AdderImpl;
# impl Adder for AdderImpl {
Expand All @@ -136,7 +139,7 @@ assert_eq!(
},
"id": 1
})),
Some(json!({
MaybeReply::Reply(json!({
"jsonrpc": "2.0",
"result": 3,
"id": 1
Expand All @@ -150,9 +153,14 @@ assert_eq!(
"method": "wrapping_add",
"params": [1, 1]
})),
None
MaybeReply::DontReply
);
// Notification are easy to generate
let bind = adder::checked_add(0, 0).unwrap();
let notification = bind.notification().as_request();
assert_eq!(handler.handle_request(notification), MaybeReply::DontReply);
// Batch calls are possible
use easy_jsonrpc::Call;
let bind0 = adder::checked_add(0, 0).unwrap();
Expand All @@ -161,8 +169,13 @@ let bind1 = adder::checked_add(1, 0).unwrap();
let (call1, tracker1) = bind1.call();
let bind2 = adder::wrapping_add(1, 1).unwrap();
let (call2, tracker2) = bind2.call();
let json_request = Call::batch_request(&[call0, call1, call2]);
let json_response = handler.handle_request(json_request).unwrap();
let bind3 = adder::wrapping_add(1, 1).unwrap();
let call3 = bind3.notification();
let json_request = Call::batch_request(&[call0, call1, call2, call3]);
let json_response = match handler.handle_request(json_request) {
MaybeReply::Reply(resp) => resp,
MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker1.get_return(&mut response).unwrap(), Some(1));
assert_eq!(tracker0.get_return(&mut response).unwrap(), Some(0));
Expand Down Expand Up @@ -198,15 +211,11 @@ pub trait Handler {
fn handle(&self, method: &str, params: Params) -> Result<Value, jsonrpc_core::Error>;

/// Parses raw_request as a jsonrpc request, handles request according to the jsonrpc spec.
/// As per the spec, requests consisting of only notifications recieve no response. A lack of
/// response is represented as None. Any response which should be returned to the client
/// is represented as Some(value), where value can be directy serialized and sent as a
/// response.
fn handle_request(&self, raw_request: serde_json::Value) -> Option<Value> {
fn handle_request(&self, raw_request: Value) -> MaybeReply {
let request: jsonrpc_core::Request = match serde_json::from_value(raw_request) {
Ok(request) => request,
Err(_) => {
return Some(serde_json::json!({
return MaybeReply::Reply(serde_json::json!({
"jsonrpc": "2.0",
"error": {
"code": -32700,
Expand All @@ -216,8 +225,11 @@ pub trait Handler {
}));
}
};
let response = handle_parsed_request(self, request)?;
Some(serde_json::to_value(response).unwrap_or_else(|e| {
let response = match handle_parsed_request(self, request) {
Some(ret) => ret,
None => return MaybeReply::DontReply,
};
MaybeReply::Reply(serde_json::to_value(response).unwrap_or_else(|e| {
serde_json::json!({
"jsonrpc": "2.0",
"error": {
Expand All @@ -231,6 +243,25 @@ pub trait Handler {
}
}

/// Returned by Handler::handle_request
#[derive(Clone, PartialEq, Debug)]
pub enum MaybeReply {
/// The value should be serialized and returned to the client.
Reply(Value),
/// The request consisted solely of notifications. No reply is necessary.
DontReply,
}

impl MaybeReply {
/// Convert to optional value.
pub fn as_option(self) -> Option<Value> {
match self {
MaybeReply::Reply(val) => Some(val),
MaybeReply::DontReply => None,
}
}
}

/// extract method name and parameters from call
/// if call is a normal method call, call `handle` and return result
/// if call is a notification, call `handle` and return None
Expand Down Expand Up @@ -634,7 +665,7 @@ mod test {
mod easy_jsonrpc {
pub use crate::*;
}
use super::Handler;
use super::{Handler, MaybeReply};
use jsonrpc_core;
use serde_json::{json, Value};

Expand Down Expand Up @@ -689,6 +720,7 @@ mod test {
assert_eq!(
(&AdderImpl {} as &dyn Adder)
.handle_request(request)
.as_option()
.unwrap(),
response
);
Expand All @@ -697,6 +729,7 @@ mod test {
fn error_code(request: Value) -> jsonrpc_core::ErrorCode {
let raw_response = (&AdderImpl {} as &dyn Adder)
.handle_request(request)
.as_option()
.unwrap();
let response: jsonrpc_core::Response = serde_json::from_value(raw_response).unwrap();
match response {
Expand Down Expand Up @@ -993,7 +1026,10 @@ mod test {
"method": "succeed",
"params": []
});
assert_eq!((&AdderImpl {} as &dyn Adder).handle_request(request), None);
assert_eq!(
(&AdderImpl {} as &dyn Adder).handle_request(request),
MaybeReply::DontReply
);
}

#[test]
Expand Down Expand Up @@ -1030,7 +1066,10 @@ mod test {

let bind = adder_client::checked_add(1, 2).unwrap();
let (call, tracker) = bind.call();
let raw_response = handler.handle_request(call.as_request()).unwrap();
let raw_response = handler
.handle_request(call.as_request())
.as_option()
.unwrap();
let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
let result: Option<usize> = tracker.get_return(&mut response).unwrap();
assert_eq!(result, Some(3));
Expand All @@ -1042,7 +1081,7 @@ mod test {
.notification()
.as_request()
),
None
MaybeReply::DontReply
);
}

Expand All @@ -1060,15 +1099,18 @@ mod test {

let bind = adder::checked_add(1, 2).unwrap();
let (call, tracker) = bind.call();
let raw_response = handler.handle_request(call.as_request()).unwrap();
let raw_response = handler
.handle_request(call.as_request())
.as_option()
.unwrap();
let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
let result: Option<usize> = tracker.get_return(&mut response).unwrap();
assert_eq!(result, Some(3));

let call = adder::checked_add(1, 2).unwrap();
assert_eq!(
handler.handle_request(call.notification().as_request()),
None
MaybeReply::DontReply
);
}

Expand All @@ -1078,14 +1120,17 @@ mod test {

let bind = adder::echo_ref(&2).unwrap();
let (call, tracker) = bind.call();
let raw_response = handler.handle_request(call.as_request()).unwrap();
let raw_response = handler
.handle_request(call.as_request())
.as_option()
.unwrap();
let mut response = easy_jsonrpc::Response::from_json_response(raw_response).unwrap();
assert_eq!(tracker.get_return(&mut response).unwrap(), 2);

let call = adder::echo_ref(&2).unwrap();
assert_eq!(
handler.handle_request(call.notification().as_request()),
None
MaybeReply::DontReply
);
}

Expand All @@ -1100,7 +1145,7 @@ mod test {
let bind2 = adder::wrapping_add(1, 1).unwrap();
let (call2, tracker2) = bind2.call();
let json_request = Call::batch_request(&[call0, call1, call2]);
let json_response = handler.handle_request(json_request).unwrap();
let json_response = handler.handle_request(json_request).as_option().unwrap();
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker0.get_return(&mut response).unwrap(), Some(0));
assert_eq!(tracker2.get_return(&mut response).unwrap(), 2);
Expand Down

0 comments on commit 2336bbc

Please sign in to comment.