jsonrpc_macros/
delegates.rs

1use std::sync::Arc;
2use std::collections::HashMap;
3
4use jsonrpc_core::{Params, Value, Error};
5use jsonrpc_core::{Metadata, RemoteProcedure, RpcMethod, RpcNotification};
6use jsonrpc_core::futures::{self, BoxFuture, Future};
7
8use jsonrpc_pubsub::{self, SubscriptionId, Subscriber, PubSubMetadata};
9
10type Data = Result<Value, Error>;
11type AsyncData = BoxFuture<Value, Error>;
12
13struct DelegateMethod<T, F> {
14	delegate: Arc<T>,
15	closure: F,
16}
17
18impl<T, M, F> RpcMethod<M> for DelegateMethod<T, F> where
19	F: Fn(&T, Params) -> Data + 'static,
20	F: Send + Sync + 'static,
21	T: Send + Sync + 'static,
22	M: Metadata,
23{
24	fn call(&self, params: Params, _meta: M) -> AsyncData {
25		let closure = &self.closure;
26		futures::done(closure(&self.delegate, params)).boxed()
27	}
28}
29
30struct DelegateAsyncMethod<T, F> {
31	delegate: Arc<T>,
32	closure: F,
33}
34
35impl<T, M, F> RpcMethod<M> for DelegateAsyncMethod<T, F> where
36	F: Fn(&T, Params) -> AsyncData,
37	F: Send + Sync + 'static,
38	T: Send + Sync + 'static,
39	M: Metadata,
40{
41	fn call(&self, params: Params, _meta: M) -> AsyncData {
42		let closure = &self.closure;
43		closure(&self.delegate, params)
44	}
45}
46
47struct DelegateMethodWithMeta<T, F> {
48	delegate: Arc<T>,
49	closure: F,
50}
51
52impl<T, M, F> RpcMethod<M> for DelegateMethodWithMeta<T, F> where
53	T: Send + Sync + 'static,
54	M: Metadata,
55	F: Fn(&T, Params, M) -> AsyncData + Send + Sync + 'static,
56{
57	fn call(&self, params: Params, meta: M) -> AsyncData {
58		let closure = &self.closure;
59		closure(&self.delegate, params, meta)
60	}
61}
62
63struct DelegateNotification<T, F> {
64	delegate: Arc<T>,
65	closure: F,
66}
67
68impl<T, M, F> RpcNotification<M> for DelegateNotification<T, F> where
69	F: Fn(&T, Params) + 'static,
70	F: Send + Sync + 'static,
71	T: Send + Sync + 'static,
72	M: Metadata,
73{
74	fn execute(&self, params: Params, _meta: M) {
75		let closure = &self.closure;
76		closure(&self.delegate, params)
77	}
78}
79
80struct DelegateSubscribe<T, F> {
81	delegate: Arc<T>,
82	closure: F,
83}
84
85impl<T, M, F> jsonrpc_pubsub::SubscribeRpcMethod<M> for DelegateSubscribe<T, F> where
86	T: Send + Sync + 'static,
87	M: PubSubMetadata,
88	F: Fn(&T, Params, M, Subscriber) + Send + Sync + 'static,
89{
90	fn call(&self, params: Params, meta: M, subscriber: Subscriber) {
91		let closure = &self.closure;
92		closure(&self.delegate, params, meta, subscriber)
93	}
94}
95
96struct DelegateUnsubscribe<T, F> {
97	delegate: Arc<T>,
98	closure: F,
99}
100
101impl<T, F> jsonrpc_pubsub::UnsubscribeRpcMethod for DelegateUnsubscribe<T, F> where
102	T: Send + Sync + 'static,
103	F: Fn(&T, SubscriptionId) -> AsyncData + Send + Sync + 'static,
104{
105	fn call(&self, id: SubscriptionId) -> AsyncData {
106		let closure = &self.closure;
107		closure(&self.delegate, id)
108	}
109}
110
111/// A set of RPC methods and notifications tied to single `delegate` struct.
112pub struct IoDelegate<T, M = ()> where
113	T: Send + Sync + 'static,
114	M: Metadata,
115{
116	delegate: Arc<T>,
117	methods: HashMap<String, RemoteProcedure<M>>,
118}
119
120impl<T, M> IoDelegate<T, M> where
121	T: Send + Sync + 'static,
122	M: Metadata,
123{
124	/// Creates new `IoDelegate`
125	pub fn new(delegate: Arc<T>) -> Self {
126		IoDelegate {
127			delegate: delegate,
128			methods: HashMap::new(),
129		}
130	}
131
132	/// Adds an alias to existing method.
133	/// NOTE: Aliases are not transitive, i.e. you cannot create alias to an alias.
134	pub fn add_alias(&mut self, from: &str, to: &str) {
135		self.methods.insert(from.into(), RemoteProcedure::Alias(to.into()));
136	}
137
138	/// Adds sync method to the delegate.
139	pub fn add_method<F>(&mut self, name: &str, method: F) where
140		F: Fn(&T, Params) -> Data,
141		F: Send + Sync + 'static,
142	{
143		self.methods.insert(name.into(), RemoteProcedure::Method(Arc::new(
144			DelegateMethod {
145				delegate: self.delegate.clone(),
146				closure: method,
147			}
148		)));
149	}
150
151	/// Adds async method to the delegate.
152	pub fn add_async_method<F>(&mut self, name: &str, method: F) where
153		F: Fn(&T, Params) -> AsyncData,
154		F: Send + Sync + 'static,
155	{
156		self.methods.insert(name.into(), RemoteProcedure::Method(Arc::new(
157			DelegateAsyncMethod {
158				delegate: self.delegate.clone(),
159				closure: method,
160			}
161		)));
162	}
163
164	/// Adds async method with metadata to the delegate.
165	pub fn add_method_with_meta<F>(&mut self, name: &str, method: F) where
166		F: Fn(&T, Params, M) -> AsyncData,
167		F: Send + Sync + 'static,
168	{
169		self.methods.insert(name.into(), RemoteProcedure::Method(Arc::new(
170			DelegateMethodWithMeta {
171				delegate: self.delegate.clone(),
172				closure: method,
173			}
174		)));
175	}
176
177	/// Adds notification to the delegate.
178	pub fn add_notification<F>(&mut self, name: &str, notification: F) where
179		F: Fn(&T, Params),
180		F: Send + Sync + 'static,
181	{
182		self.methods.insert(name.into(), RemoteProcedure::Notification(Arc::new(
183			DelegateNotification {
184				delegate: self.delegate.clone(),
185				closure: notification,
186			}
187		)));
188	}
189}
190
191impl<T, M> IoDelegate<T, M> where
192	T: Send + Sync + 'static,
193	M: PubSubMetadata,
194{
195	/// Adds subscription to the delegate.
196	pub fn add_subscription<Sub, Unsub>(
197		&mut self,
198		name: &str,
199		subscribe: (&str, Sub),
200		unsubscribe: (&str, Unsub),
201	) where
202		Sub: Fn(&T, Params, M, Subscriber),
203		Sub: Send + Sync + 'static,
204		Unsub: Fn(&T, SubscriptionId) -> AsyncData,
205		Unsub: Send + Sync + 'static,
206	{
207		let (sub, unsub) = jsonrpc_pubsub::new_subscription(
208			name,
209			DelegateSubscribe {
210				delegate: self.delegate.clone(),
211				closure: subscribe.1,
212			},
213			DelegateUnsubscribe {
214				delegate: self.delegate.clone(),
215				closure: unsubscribe.1,
216			}
217		);
218		self.add_method_with_meta(subscribe.0, move |_, params, meta| sub.call(params, meta));
219		self.add_method_with_meta(unsubscribe.0, move |_, params, meta| unsub.call(params, meta));
220	}
221}
222
223impl<T, M> Into<HashMap<String, RemoteProcedure<M>>> for IoDelegate<T, M> where
224	T: Send + Sync + 'static,
225	M: Metadata,
226{
227	fn into(self) -> HashMap<String, RemoteProcedure<M>> {
228		self.methods
229	}
230}