rpc_router/router/router.rs
1use crate::router::router_inner::RouterInner;
2use crate::Resources;
3use crate::{CallResult, Request, ResourcesInner, RouterBuilder};
4use serde_json::Value;
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
8pub struct Router {
9 inner: Arc<RouterInner>,
10 base_resources: Resources,
11}
12
13//-- Builder
14impl Router {
15 /// Returns a new `ResourcesBuilder`.
16 /// This is equivalent to calling `Resources::default()`.
17 pub fn builder() -> RouterBuilder {
18 RouterBuilder::default()
19 }
20}
21
22// -- Methods
23impl Router {
24 /// Performs the RPC call for a given RpcRequest object (i.e., `.id, .method, .params`)
25 /// with the eventual resources of the router.
26 ///
27 /// To add additional resources on top of the router's resources, call `.call_with_resources(request, resources)`
28 ///
29 /// - Returns an CallResult that echoes the `id` and `method`, and includes the `Result<Value, rpc_router::Error>` result.
30 ///
31 /// - The `rpc_router::Error` includes a variant `rpc_router::Error::Handler(RpcHandlerError)`,
32 /// where `RpcHandlerError` allows retrieval of the application error returned by the handler
33 /// through `RpcHandlerError::get::<T>(&self) -> Option<T>`.
34 /// This mechanism enables application RPC handlers to return specific application errors while still utilizing
35 /// the `rpc-router` result structure, thereby allowing them to retrieve their specific error type.
36 ///
37 pub async fn call(&self, rpc_request: Request) -> CallResult {
38 self.inner.call(self.base_resources.clone(), rpc_request).await
39 }
40
41 /// Similar to `.call(...)`, but takes an additional `Resources` parameter that will be overlaid on top
42 /// of the eventual base router resources.
43 ///
44 /// Note: The router will first try to get the resource from the overlay, and then,
45 /// will try the base router resources.
46 pub async fn call_with_resources(&self, rpc_request: Request, additional_resources: Resources) -> CallResult {
47 let resources = self.compute_call_resources(additional_resources);
48
49 self.inner.call(resources, rpc_request).await
50 }
51
52 /// Lower level function to `.call` which take all Rpc Request properties as value.
53 /// If id is None, it will be set a Value::Null
54 ///
55 /// This also use router base resources.
56 ///
57 /// To add additional resources on top of the router's resources, call `.call_route_with_resources(request, resources)`
58 ///
59 /// - method: The json-rpc method name.
60 /// - id: The json-rpc request `.id`, which should be sent by the client.
61 /// It is required to echo it back in the json-rpc response.
62 /// Can be `Value::Null`, and if None, it will be set to `Value::Null`
63 /// - params: The optional json-rpc params
64 ///
65 /// Returns an CallResult, where either the success value (CallResponse) or the error (CallError)
66 /// will echo back the `id` and `method` part of their construct
67 pub async fn call_route(&self, id: Option<Value>, method: impl Into<String>, params: Option<Value>) -> CallResult {
68 self.inner.call_route(self.base_resources.clone(), id, method, params).await
69 }
70
71 /// Similar to `.call_route`, but takes an additional `Resources` parameter that will be overlaid on top
72 /// of the eventual base router resources.
73 ///
74 /// Note: The router will first try to get the resource from the overlay, and then,
75 /// will try the base router resources.
76 pub async fn call_route_with_resources(
77 &self,
78 id: Option<Value>,
79 method: impl Into<String>,
80 params: Option<Value>,
81 additional_resources: Resources,
82 ) -> CallResult {
83 let resources = self.compute_call_resources(additional_resources);
84
85 self.inner.call_route(resources, id, method, params).await
86 }
87}
88
89// Crate only method
90impl Router {
91 /// For specific or advanced use cases.
92 ///
93 /// Use `RpcRouterBuilder::default()...build()` if unsure.
94 ///
95 /// Creates an `RpcRouter` from its inner data.
96 ///
97 /// Note: This is intended for situations where a custom builder
98 /// workflow is needed. The recommended method for creating an `RpcRouter`
99 /// is via the `RpcRouterBuilder`.
100 pub(crate) fn new(inner: RouterInner, resources_inner: ResourcesInner) -> Self {
101 Self {
102 inner: Arc::new(inner),
103 base_resources: Resources::from_base_inner(resources_inner),
104 }
105 }
106
107 pub(crate) fn compute_call_resources(&self, call_resources: Resources) -> Resources {
108 if self.base_resources.is_empty() {
109 call_resources
110 } else {
111 self.base_resources.new_with_overlay(call_resources)
112 }
113 }
114}