1use crate::jsonrpc::{
2 ConnectionContext, HandleDispatchFrom, Handled, IntoHandled, JsonRpcResponse,
3 RawConnectionContext, connection_context,
4};
5
6use crate::role::{HasPeer, Role, handle_incoming_dispatch};
7use crate::{ConnectionTo, Dispatch, JsonRpcNotification, JsonRpcRequest, UntypedMessage};
8use super::Responder;
10use std::future::Future;
11use std::marker::PhantomData;
12use std::ops::AsyncFnMut;
13
14#[derive(Debug)]
16pub struct NullHandler;
17
18impl Default for NullHandler {
19 fn default() -> Self {
20 Self
21 }
22}
23
24impl<Counterpart: Role> HandleDispatchFrom<Counterpart> for NullHandler {
25 fn describe_chain(&self) -> impl std::fmt::Debug {
26 "(null)"
27 }
28
29 fn handle_dispatch_from(
30 &mut self,
31 message: Dispatch,
32 _cx: ConnectionTo<Counterpart>,
33 ) -> impl Future<Output = Result<Handled<Dispatch>, crate::Error>> + Send {
34 std::future::ready(Ok(Handled::No {
35 message,
36 retry: false,
37 }))
38 }
39}
40
41pub struct RequestHandler<
43 Counterpart: Role,
44 Peer: Role,
45 Req: JsonRpcRequest = UntypedMessage,
46 F = (),
47 ToFut = (),
48 Context = RawConnectionContext,
49> {
50 counterpart: Counterpart,
51 peer: Peer,
52 handler: F,
53 to_future_hack: ToFut,
54 phantom: PhantomData<fn(Req, Context)>,
55}
56
57impl<Counterpart: Role, Peer: Role, Req: JsonRpcRequest, F, ToFut, Context>
58 RequestHandler<Counterpart, Peer, Req, F, ToFut, Context>
59{
60 pub fn new(counterpart: Counterpart, peer: Peer, handler: F, to_future_hack: ToFut) -> Self {
62 Self {
63 counterpart,
64 peer,
65 handler,
66 to_future_hack,
67 phantom: PhantomData,
68 }
69 }
70}
71
72impl<Counterpart: Role, Peer: Role, Req, F, T, ToFut, Context> HandleDispatchFrom<Counterpart>
73 for RequestHandler<Counterpart, Peer, Req, F, ToFut, Context>
74where
75 Counterpart: HasPeer<Peer>,
76 Req: JsonRpcRequest,
77 Context: ConnectionContext,
78 F: AsyncFnMut(
79 Req,
80 Responder<Req::Response>,
81 Context::Connection<Counterpart>,
82 ) -> Result<T, crate::Error>
83 + Send,
84 T: crate::IntoHandled<(Req, Responder<Req::Response>)>,
85 ToFut: Fn(
86 &mut F,
87 Req,
88 Responder<Req::Response>,
89 Context::Connection<Counterpart>,
90 ) -> crate::BoxFuture<'_, Result<T, crate::Error>>
91 + Send
92 + Sync,
93{
94 fn describe_chain(&self) -> impl std::fmt::Debug {
95 std::any::type_name::<Req>()
96 }
97
98 async fn handle_dispatch_from(
99 &mut self,
100 dispatch: Dispatch,
101 connection: ConnectionTo<Counterpart>,
102 ) -> Result<Handled<Dispatch>, crate::Error> {
103 handle_incoming_dispatch(
104 self.counterpart.clone(),
105 self.peer.clone(),
106 dispatch,
107 connection,
108 async |dispatch, connection| {
109 match dispatch {
110 Dispatch::Request(message, responder) => {
111 tracing::debug!(
112 request_type = std::any::type_name::<Req>(),
113 method = %message.method,
114 "RequestHandler::handle_request"
115 );
116 if Req::matches_method(&message.method) {
117 match Req::parse_message(&message.method, &message.params) {
118 Ok(req) => {
119 tracing::trace!(
120 "RequestHandler::handle_request: parse completed"
121 );
122 let typed_responder = responder.cast();
123 let result = (self.to_future_hack)(
124 &mut self.handler,
125 req,
126 typed_responder,
127 connection_context::from_raw::<Context, _>(connection),
128 )
129 .await?;
130 match result.into_handled() {
131 Handled::Yes => Ok(Handled::Yes),
132 Handled::No {
133 message: (request, responder),
134 retry,
135 } => {
136 let untyped = request.to_untyped_message()?;
138 Ok(Handled::No {
139 message: Dispatch::Request(
140 untyped,
141 responder.erase_to_json(),
142 ),
143 retry,
144 })
145 }
146 }
147 }
148 Err(err) => {
149 tracing::trace!(
150 err = ?crate::util::redacted_error(err.code),
151 "RequestHandler::handle_request: parse errored"
152 );
153 Err(err)
154 }
155 }
156 } else {
157 tracing::trace!("RequestHandler::handle_request: method doesn't match");
158 Ok(Handled::No {
159 message: Dispatch::Request(message, responder),
160 retry: false,
161 })
162 }
163 }
164
165 Dispatch::Notification(..) | Dispatch::Response(..) => Ok(Handled::No {
166 message: dispatch,
167 retry: false,
168 }),
169 }
170 },
171 )
172 .await
173 }
174}
175
176pub struct NotificationHandler<
178 Counterpart: Role,
179 Peer: Role,
180 Notif: JsonRpcNotification = UntypedMessage,
181 F = (),
182 ToFut = (),
183 Context = RawConnectionContext,
184> {
185 counterpart: Counterpart,
186 peer: Peer,
187 handler: F,
188 to_future_hack: ToFut,
189 phantom: PhantomData<fn(Notif, Context)>,
190}
191
192impl<Counterpart: Role, Peer: Role, Notif: JsonRpcNotification, F, ToFut, Context>
193 NotificationHandler<Counterpart, Peer, Notif, F, ToFut, Context>
194{
195 pub fn new(counterpart: Counterpart, peer: Peer, handler: F, to_future_hack: ToFut) -> Self {
197 Self {
198 counterpart,
199 peer,
200 handler,
201 to_future_hack,
202 phantom: PhantomData,
203 }
204 }
205}
206
207impl<Counterpart: Role, Peer: Role, Notif, F, T, ToFut, Context> HandleDispatchFrom<Counterpart>
208 for NotificationHandler<Counterpart, Peer, Notif, F, ToFut, Context>
209where
210 Counterpart: HasPeer<Peer>,
211 Notif: JsonRpcNotification,
212 Context: ConnectionContext,
213 F: AsyncFnMut(Notif, Context::Connection<Counterpart>) -> Result<T, crate::Error> + Send,
214 T: crate::IntoHandled<(Notif, Context::Connection<Counterpart>)>,
215 ToFut: Fn(
216 &mut F,
217 Notif,
218 Context::Connection<Counterpart>,
219 ) -> crate::BoxFuture<'_, Result<T, crate::Error>>
220 + Send
221 + Sync,
222{
223 fn describe_chain(&self) -> impl std::fmt::Debug {
224 std::any::type_name::<Notif>()
225 }
226
227 async fn handle_dispatch_from(
228 &mut self,
229 dispatch: Dispatch,
230 connection: ConnectionTo<Counterpart>,
231 ) -> Result<Handled<Dispatch>, crate::Error> {
232 handle_incoming_dispatch(
233 self.counterpart.clone(),
234 self.peer.clone(),
235 dispatch,
236 connection,
237 async |dispatch, connection| {
238 match dispatch {
239 Dispatch::Notification(message) => {
240 tracing::debug!(
241 request_type = std::any::type_name::<Notif>(),
242 method = %message.method,
243 "NotificationHandler::handle_dispatch"
244 );
245 if Notif::matches_method(&message.method) {
246 match Notif::parse_message(&message.method, &message.params) {
247 Ok(notif) => {
248 tracing::trace!(
249 "NotificationHandler::handle_notification: parse completed"
250 );
251 let result = (self.to_future_hack)(
252 &mut self.handler,
253 notif,
254 connection_context::from_raw::<Context, _>(connection),
255 )
256 .await?;
257 match result.into_handled() {
258 Handled::Yes => Ok(Handled::Yes),
259 Handled::No {
260 message: (notification, _cx),
261 retry,
262 } => {
263 let untyped = notification.to_untyped_message()?;
265 Ok(Handled::No {
266 message: Dispatch::Notification(untyped),
267 retry,
268 })
269 }
270 }
271 }
272 Err(err) => {
273 tracing::trace!(
274 err = ?crate::util::redacted_error(err.code),
275 "NotificationHandler::handle_notification: parse errored"
276 );
277 Err(err)
278 }
279 }
280 } else {
281 tracing::trace!(
282 "NotificationHandler::handle_notification: method doesn't match"
283 );
284 Ok(Handled::No {
285 message: Dispatch::Notification(message),
286 retry: false,
287 })
288 }
289 }
290
291 Dispatch::Request(..) | Dispatch::Response(..) => Ok(Handled::No {
292 message: dispatch,
293 retry: false,
294 }),
295 }
296 },
297 )
298 .await
299 }
300}
301
302pub struct MessageHandler<
304 Counterpart: Role,
305 Peer: Role,
306 Req: JsonRpcRequest = UntypedMessage,
307 Notif: JsonRpcNotification = UntypedMessage,
308 F = (),
309 ToFut = (),
310 Context = RawConnectionContext,
311> {
312 counterpart: Counterpart,
313 peer: Peer,
314 handler: F,
315 to_future_hack: ToFut,
316 phantom: PhantomData<fn(Dispatch<Req, Notif>, Context)>,
317}
318
319impl<
320 Counterpart: Role,
321 Peer: Role,
322 Req: JsonRpcRequest,
323 Notif: JsonRpcNotification,
324 F,
325 ToFut,
326 Context,
327> MessageHandler<Counterpart, Peer, Req, Notif, F, ToFut, Context>
328{
329 pub fn new(counterpart: Counterpart, peer: Peer, handler: F, to_future_hack: ToFut) -> Self {
331 Self {
332 counterpart,
333 peer,
334 handler,
335 to_future_hack,
336 phantom: PhantomData,
337 }
338 }
339}
340
341impl<
342 Counterpart: Role,
343 Peer: Role,
344 Req: JsonRpcRequest,
345 Notif: JsonRpcNotification,
346 F,
347 T,
348 ToFut,
349 Context,
350> HandleDispatchFrom<Counterpart>
351 for MessageHandler<Counterpart, Peer, Req, Notif, F, ToFut, Context>
352where
353 Counterpart: HasPeer<Peer>,
354 Context: ConnectionContext,
355 F: AsyncFnMut(
356 Dispatch<Req, Notif>,
357 Context::Connection<Counterpart>,
358 ) -> Result<T, crate::Error>
359 + Send,
360 T: IntoHandled<Dispatch<Req, Notif>>,
361 ToFut: Fn(
362 &mut F,
363 Dispatch<Req, Notif>,
364 Context::Connection<Counterpart>,
365 ) -> crate::BoxFuture<'_, Result<T, crate::Error>>
366 + Send
367 + Sync,
368{
369 fn describe_chain(&self) -> impl std::fmt::Debug {
370 format!(
371 "({}, {})",
372 std::any::type_name::<Req>(),
373 std::any::type_name::<Notif>()
374 )
375 }
376
377 async fn handle_dispatch_from(
378 &mut self,
379 dispatch: Dispatch,
380 connection: ConnectionTo<Counterpart>,
381 ) -> Result<Handled<Dispatch>, crate::Error> {
382 handle_incoming_dispatch(
383 self.counterpart.clone(),
384 self.peer.clone(),
385 dispatch,
386 connection,
387 async |dispatch, connection| match dispatch.into_typed_dispatch::<Req, Notif>()? {
388 Ok(typed_dispatch) => {
389 let result = (self.to_future_hack)(
390 &mut self.handler,
391 typed_dispatch,
392 connection_context::from_raw::<Context, _>(connection),
393 )
394 .await?;
395 match result.into_handled() {
396 Handled::Yes => Ok(Handled::Yes),
397 Handled::No {
398 message: Dispatch::Request(request, responder),
399 retry,
400 } => {
401 let untyped = request.to_untyped_message()?;
402 Ok(Handled::No {
403 message: Dispatch::Request(untyped, responder.erase_to_json()),
404 retry,
405 })
406 }
407 Handled::No {
408 message: Dispatch::Notification(notification),
409 retry,
410 } => {
411 let untyped = notification.to_untyped_message()?;
412 Ok(Handled::No {
413 message: Dispatch::Notification(untyped),
414 retry,
415 })
416 }
417 Handled::No {
418 message: Dispatch::Response(result, responder),
419 retry,
420 } => {
421 let method = responder.method();
422 let untyped_result = match result {
423 Ok(response) => response.into_json(method).map(Ok),
424 Err(err) => Ok(Err(err)),
425 }?;
426 Ok(Handled::No {
427 message: Dispatch::Response(
428 untyped_result,
429 responder.erase_to_json(),
430 ),
431 retry,
432 })
433 }
434 }
435 }
436
437 Err(dispatch) => Ok(Handled::No {
438 message: dispatch,
439 retry: false,
440 }),
441 },
442 )
443 .await
444 }
445}
446
447pub struct NamedHandler<H> {
449 name: Option<String>,
450 handler: H,
451}
452
453impl<H> NamedHandler<H> {
454 pub fn new(name: Option<String>, handler: H) -> Self {
456 Self { name, handler }
457 }
458}
459
460impl<Counterpart: Role, H: HandleDispatchFrom<Counterpart>> HandleDispatchFrom<Counterpart>
461 for NamedHandler<H>
462{
463 fn describe_chain(&self) -> impl std::fmt::Debug {
464 format!(
465 "NamedHandler({:?}, {:?})",
466 self.name,
467 self.handler.describe_chain()
468 )
469 }
470
471 async fn handle_dispatch_from(
472 &mut self,
473 message: Dispatch,
474 connection: ConnectionTo<Counterpart>,
475 ) -> Result<Handled<Dispatch>, crate::Error> {
476 if let Some(name) = &self.name {
477 crate::util::instrumented_with_connection_name(
478 name.clone(),
479 self.handler.handle_dispatch_from(message, connection),
480 )
481 .await
482 } else {
483 self.handler.handle_dispatch_from(message, connection).await
484 }
485 }
486}
487
488pub struct ChainedHandler<H1, H2> {
490 handler1: H1,
491 handler2: H2,
492}
493
494impl<H1, H2> ChainedHandler<H1, H2> {
495 pub fn new(handler1: H1, handler2: H2) -> Self {
497 Self { handler1, handler2 }
498 }
499}
500
501#[inline(never)]
504fn boxed_dispatch<Counterpart, H>(
505 handler: &mut H,
506 message: Dispatch,
507 connection: ConnectionTo<Counterpart>,
508) -> crate::BoxFuture<'_, Result<Handled<Dispatch>, crate::Error>>
509where
510 Counterpart: Role,
511 H: HandleDispatchFrom<Counterpart>,
512{
513 Box::pin(handler.handle_dispatch_from(message, connection))
514}
515
516impl<Counterpart: Role, H1, H2> HandleDispatchFrom<Counterpart> for ChainedHandler<H1, H2>
517where
518 H1: HandleDispatchFrom<Counterpart>,
519 H2: HandleDispatchFrom<Counterpart>,
520{
521 fn describe_chain(&self) -> impl std::fmt::Debug {
522 format!(
523 "{:?}, {:?}",
524 self.handler1.describe_chain(),
525 self.handler2.describe_chain()
526 )
527 }
528
529 async fn handle_dispatch_from(
530 &mut self,
531 message: Dispatch,
532 connection: ConnectionTo<Counterpart>,
533 ) -> Result<Handled<Dispatch>, crate::Error> {
534 match boxed_dispatch(&mut self.handler1, message, connection.clone()).await? {
537 Handled::Yes => Ok(Handled::Yes),
538 Handled::No {
539 message,
540 retry: retry1,
541 } => match boxed_dispatch(&mut self.handler2, message, connection).await? {
542 Handled::Yes => Ok(Handled::Yes),
543 Handled::No {
544 message,
545 retry: retry2,
546 } => Ok(Handled::No {
547 message,
548 retry: retry1 | retry2,
549 }),
550 },
551 }
552 }
553}