use tetsy_jsonrpc_core; use tetsy_jsonrpc_pubsub; use serde_json; #[macro_use] extern crate tetsy_jsonrpc_derive; use tetsy_jsonrpc_core::futures::sync::mpsc; use tetsy_jsonrpc_pubsub::typed::Subscriber; use tetsy_jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId}; use std::sync::Arc; pub enum MyError {} impl From for tetsy_jsonrpc_core::Error { fn from(_e: MyError) -> Self { unreachable!() } } type Result = ::std::result::Result; #[rpc] pub trait Rpc { type Metadata; /// Hello subscription. #[pubsub(subscription = "hello", subscribe, name = "hello_subscribe", alias("hello_alias"))] fn subscribe(&self, a: Self::Metadata, b: Subscriber, c: u32, d: Option); /// Hello subscription through different method. #[pubsub(subscription = "hello", subscribe, name = "hello_subscribe_second")] fn subscribe_second(&self, a: Self::Metadata, b: Subscriber, e: String); /// Unsubscribe from hello subscription. #[pubsub(subscription = "hello", unsubscribe, name = "hello_unsubscribe")] fn unsubscribe(&self, a: Option, b: SubscriptionId) -> Result; /// A regular rpc method alongside pubsub. #[rpc(name = "add")] fn add(&self, a: u64, b: u64) -> Result; /// A notification alongside pubsub. #[rpc(name = "notify")] fn notify(&self, a: u64); } #[derive(Default)] struct RpcImpl; impl Rpc for RpcImpl { type Metadata = Metadata; fn subscribe(&self, _meta: Self::Metadata, subscriber: Subscriber, _pre: u32, _trailing: Option) { let _sink = subscriber.assign_id(SubscriptionId::Number(5)); } fn subscribe_second(&self, _meta: Self::Metadata, subscriber: Subscriber, _e: String) { let _sink = subscriber.assign_id(SubscriptionId::Number(6)); } fn unsubscribe(&self, _meta: Option, _id: SubscriptionId) -> Result { Ok(true) } fn add(&self, a: u64, b: u64) -> Result { Ok(a + b) } fn notify(&self, a: u64) { println!("Received `notify` with value: {}", a); } } #[derive(Clone, Default)] struct Metadata; impl tetsy_jsonrpc_core::Metadata for Metadata {} impl PubSubMetadata for Metadata { fn session(&self) -> Option> { let (tx, _rx) = mpsc::channel(1); Some(Arc::new(Session::new(tx))) } } #[test] fn test_invalid_trailing_pubsub_params() { let mut io = PubSubHandler::default(); let rpc = RpcImpl::default(); io.extend_with(rpc.to_delegate()); // when let meta = Metadata; let req = r#"{"jsonrpc":"2.0","id":1,"method":"hello_subscribe","params":[]}"#; let res = io.handle_request_sync(req, meta); let expected = r#"{ "jsonrpc": "2.0", "error": { "code": -32602, "message": "`params` should have at least 1 argument(s)" }, "id": 1 }"#; let expected: tetsy_jsonrpc_core::Response = serde_json::from_str(expected).unwrap(); let result: tetsy_jsonrpc_core::Response = serde_json::from_str(&res.unwrap()).unwrap(); assert_eq!(expected, result); } #[test] fn test_subscribe_with_alias() { let mut io = PubSubHandler::default(); let rpc = RpcImpl::default(); io.extend_with(rpc.to_delegate()); // when let meta = Metadata; let req = r#"{"jsonrpc":"2.0","id":1,"method":"hello_alias","params":[1]}"#; let res = io.handle_request_sync(req, meta); let expected = r#"{ "jsonrpc": "2.0", "result": 5, "id": 1 }"#; let expected: tetsy_jsonrpc_core::Response = serde_json::from_str(expected).unwrap(); let result: tetsy_jsonrpc_core::Response = serde_json::from_str(&res.unwrap()).unwrap(); assert_eq!(expected, result); } #[test] fn test_subscribe_alternate_method() { let mut io = PubSubHandler::default(); let rpc = RpcImpl::default(); io.extend_with(rpc.to_delegate()); // when let meta = Metadata; let req = r#"{"jsonrpc":"2.0","id":1,"method":"hello_subscribe_second","params":["Data"]}"#; let res = io.handle_request_sync(req, meta); let expected = r#"{ "jsonrpc": "2.0", "result": 6, "id": 1 }"#; let expected: tetsy_jsonrpc_core::Response = serde_json::from_str(expected).unwrap(); let result: tetsy_jsonrpc_core::Response = serde_json::from_str(&res.unwrap()).unwrap(); assert_eq!(expected, result); }