witty_jsonrpc/
handler.rs

1use std::{fmt::Debug, sync::Arc};
2
3use futures::channel::mpsc::UnboundedSender;
4use jsonrpc_core::{MetaIoHandler, Metadata, RpcMethodSimple};
5use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, SubscribeRpcMethod, UnsubscribeRpcMethod};
6
7/// A wrapper around `jsonrpc_core`'s own `Session`, providing some convenience methods and
8/// `impl Default::default`.
9#[derive(Clone, Debug, Default)]
10pub struct Session {
11    inner: Option<Arc<jsonrpc_pubsub::Session>>,
12}
13
14impl Session {
15    /// A mocked session, i.e. created from an mpsc channel that is not wired to anything.
16    pub fn mock() -> Session {
17        let (sender, _) = futures::channel::mpsc::unbounded();
18        let inner = Some(Arc::from(jsonrpc_pubsub::Session::new(sender)));
19
20        Self { inner }
21    }
22}
23
24impl From<Arc<jsonrpc_pubsub::Session>> for Session {
25    fn from(value: Arc<jsonrpc_pubsub::Session>) -> Self {
26        Session { inner: Some(value) }
27    }
28}
29
30impl Metadata for Session {}
31
32impl PubSubMetadata for Session {
33    fn session(&self) -> Option<Arc<jsonrpc_pubsub::Session>> {
34        self.inner.clone()
35    }
36}
37
38/// Trait that abstracts away different implementations of IO handlers.
39pub trait Handler {
40    /// The type to use as the metadata for the IO handler. Especially relevant for PubSub.
41    type Metadata: PubSubMetadata + Unpin + Debug;
42
43    /// Add a JSON-RPC method.
44    fn add_method<F>(&mut self, name: &str, method: F)
45    where
46        F: RpcMethodSimple;
47
48    /// Add a JSON-RPC subscription.
49    fn add_subscription<F, G>(
50        &mut self,
51        notification: &str,
52        subscribe: (&str, F),
53        unsubscribe: (&str, G),
54    ) where
55        F: SubscribeRpcMethod<Self::Metadata>,
56        G: UnsubscribeRpcMethod<Self::Metadata>;
57
58    /// Cast this down to an instance of `MetaIoHandler`.
59    fn as_meta_io_handler(&self) -> MetaIoHandler<Self::Metadata>;
60
61    /// Get a list of all the supported JSON-RPC methods.
62    fn describe_api(&self) -> Vec<String>;
63
64    /// Programmatically trigger the handling of a JSON-RPC message.
65    /// TODO: support async
66    fn handle_request_sync(&self, request: &str, meta: Self::Metadata) -> Option<String>;
67
68    /// Derive an instance of the `Self::Metadata` associated type from an `UnboundedSender`.
69    fn metadata_from_sender(sender: UnboundedSender<String>) -> Self::Metadata;
70
71    /// Create a new instance of a `Handler` implementation.
72    fn new() -> Self;
73}
74
75impl<M> Handler for PubSubHandler<M>
76where
77    M: PubSubMetadata + Unpin + Debug + From<Arc<jsonrpc_pubsub::Session>>,
78{
79    type Metadata = M;
80
81    fn add_method<F>(&mut self, name: &str, method: F)
82    where
83        F: RpcMethodSimple,
84    {
85        MetaIoHandler::add_method(self, name, method)
86    }
87
88    fn add_subscription<F, G>(
89        &mut self,
90        notification: &str,
91        subscribe: (&str, F),
92        unsubscribe: (&str, G),
93    ) where
94        F: SubscribeRpcMethod<M>,
95        G: UnsubscribeRpcMethod<M>,
96    {
97        PubSubHandler::add_subscription(self, notification, subscribe, unsubscribe)
98    }
99
100    fn as_meta_io_handler(&self) -> MetaIoHandler<Self::Metadata> {
101        (*self).clone()
102    }
103
104    fn describe_api(&self) -> Vec<String> {
105        self.iter().map(|(name, _)| name.clone()).collect()
106    }
107
108    fn handle_request_sync(&self, request: &str, meta: Self::Metadata) -> Option<String> {
109        MetaIoHandler::handle_request_sync(self, request, meta)
110    }
111
112    fn metadata_from_sender(sender: UnboundedSender<String>) -> Self::Metadata {
113        Self::Metadata::from(Arc::new(jsonrpc_pubsub::Session::new(sender)))
114    }
115
116    fn new() -> Self {
117        PubSubHandler::new(jsonrpc_core::MetaIoHandler::default())
118    }
119}