[][src]Crate susy_jsonrpc_derive

High level, typed wrapper for susy_jsonrpc_core.

Enables creation of "Service" objects grouping a set of RPC methods together in a typed manner.

Example

use susy_jsonrpc_derive::rpc;
use susy_jsonrpc_core::{IoHandler, Error, Result};
use susy_jsonrpc_core::futures::future::{self, FutureResult};

#[rpc]
pub trait Rpc {
    #[rpc(name = "protocolVersion")]
    fn protocol_version(&self) -> Result<String>;

    #[rpc(name = "add")]
    fn add(&self, _: u64, _: u64) -> Result<u64>;

    #[rpc(name = "callAsync")]
    fn call(&self, _: u64) -> FutureResult<String, Error>;
}

struct RpcImpl;
impl Rpc for RpcImpl {
    fn protocol_version(&self) -> Result<String> {
        Ok("version1".into())
    }

    fn add(&self, a: u64, b: u64) -> Result<u64> {
        Ok(a + b)
    }

    fn call(&self, _: u64) -> FutureResult<String, Error> {
        future::ok("OK".to_owned()).into()
    }
}

fn main() {
  let mut io = IoHandler::new();
  let rpc = RpcImpl;

  io.extend_with(rpc.to_delegate());
}

Pub/Sub Example

Each subscription must have subscribe and unsubscribe methods. They can have any name but must be annotated with subscribe or unsubscribe and have a matching unique subscription name.

use std::thread;
use std::sync::{atomic, Arc, RwLock};
use std::collections::HashMap;

use susy_jsonrpc_core::{Error, ErrorCode, Result};
use susy_jsonrpc_core::futures::Future;
use susy_jsonrpc_derive::rpc;
use susy_jsonrpc_pubsub::{Session, PubSubHandler, SubscriptionId, typed::{Subscriber, Sink}};

#[rpc]
pub trait Rpc {
    type Metadata;

    /// Hello subscription
    #[pubsub(
        subscription = "hello",
        subscribe,
        name = "hello_subscribe",
        alias("hello_sub")
    )]
    fn subscribe(&self, _: Self::Metadata, _: Subscriber<String>, _: u64);

    /// Unsubscribe from hello subscription.
    #[pubsub(
        subscription = "hello",
        unsubscribe,
        name = "hello_unsubscribe"
    )]
    fn unsubscribe(&self, _: Option<Self::Metadata>, _: SubscriptionId) -> Result<bool>;
}


#[derive(Default)]
struct RpcImpl {
    uid: atomic::AtomicUsize,
    active: Arc<RwLock<HashMap<SubscriptionId, Sink<String>>>>,
}
impl Rpc for RpcImpl {
    type Metadata = Arc<Session>;

    fn subscribe(&self, _meta: Self::Metadata, subscriber: Subscriber<String>, param: u64) {
        if param != 10 {
            subscriber.reject(Error {
                code: ErrorCode::InvalidParams,
                message: "Rejecting subscription - invalid parameters provided.".into(),
                data: None,
            }).unwrap();
            return;
        }

        let id = self.uid.fetch_add(1, atomic::Ordering::SeqCst);
        let sub_id = SubscriptionId::Number(id as u64);
        let sink = subscriber.assign_id(sub_id.clone()).unwrap();
        self.active.write().unwrap().insert(sub_id, sink);
    }

    fn unsubscribe(&self, _meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool> {
        let removed = self.active.write().unwrap().remove(&id);
        if removed.is_some() {
            Ok(true)
        } else {
            Err(Error {
                code: ErrorCode::InvalidParams,
                message: "Invalid subscription.".into(),
                data: None,
            })
        }
    }
}

Attribute Macros

rpc

Apply #[rpc] to a trait, and a to_delegate method is generated which wires up methods decorated with #[rpc] or #[pubsub] attributes. Attach the delegate to an IoHandler and the methods are now callable via JSON-RPC.