workflow_rpc/server/interface/
method.rs

1//! Module containing RPC [`Method`] closure wrappers
2use crate::imports::*;
3
4/// Base trait representing an RPC method, used to retain
5/// method structures in an [`Interface`](super::Interface)
6/// map without generics.
7#[async_trait]
8pub(crate) trait MethodTrait<ServerContext, ConnectionContext>:
9    Send + Sync + 'static
10{
11    async fn call_with_borsh(
12        &self,
13        server_ctx: ServerContext,
14        connection_ctx: ConnectionContext,
15        data: &[u8],
16    ) -> ServerResult<Vec<u8>>;
17    async fn call_with_serde_json(
18        &self,
19        server_ctx: ServerContext,
20        connection_ctx: ConnectionContext,
21        value: Value,
22    ) -> ServerResult<Value>;
23}
24
25/// RPC method function type
26pub type MethodFn<ServerContext, ConnectionContext, Req, Resp> = Arc<
27    Box<
28        dyn Send
29            + Sync
30            + Fn(ServerContext, ConnectionContext, Req) -> MethodFnReturn<Resp>
31            + 'static,
32    >,
33>;
34
35/// RPC method function return type
36pub type MethodFnReturn<T> = Pin<Box<(dyn Send + 'static + Future<Output = ServerResult<T>>)>>;
37
38/// RPC method wrapper. Contains the method closure function.
39pub struct Method<ServerContext, ConnectionContext, Req, Resp>
40where
41    ServerContext: Send + Sync + 'static,
42    Req: MsgT,
43    Resp: MsgT,
44{
45    method: MethodFn<ServerContext, ConnectionContext, Req, Resp>,
46}
47
48impl<ServerContext, ConnectionContext, Req, Resp>
49    Method<ServerContext, ConnectionContext, Req, Resp>
50where
51    ServerContext: Send + Sync + 'static,
52    Req: MsgT,
53    Resp: MsgT,
54{
55    pub fn new<FN>(method_fn: FN) -> Method<ServerContext, ConnectionContext, Req, Resp>
56    where
57        FN: Send
58            + Sync
59            + Fn(ServerContext, ConnectionContext, Req) -> MethodFnReturn<Resp>
60            + 'static,
61    {
62        Method {
63            method: Arc::new(Box::new(method_fn)),
64        }
65    }
66}
67
68#[async_trait]
69impl<ServerContext, ConnectionContext, Req, Resp> MethodTrait<ServerContext, ConnectionContext>
70    for Method<ServerContext, ConnectionContext, Req, Resp>
71where
72    ServerContext: Clone + Send + Sync + 'static,
73    ConnectionContext: Clone + Send + Sync + 'static,
74    Req: MsgT,
75    Resp: MsgT,
76{
77    async fn call_with_borsh(
78        &self,
79        server_ctx: ServerContext,
80        connection_ctx: ConnectionContext,
81        data: &[u8],
82    ) -> ServerResult<Vec<u8>> {
83        let req = Req::try_from_slice(data)?;
84        let resp = (self.method)(server_ctx, connection_ctx, req).await;
85        let vec = borsh::to_vec(&resp)?;
86        Ok(vec)
87    }
88
89    async fn call_with_serde_json(
90        &self,
91        server_ctx: ServerContext,
92        connection_ctx: ConnectionContext,
93        value: Value,
94    ) -> ServerResult<Value> {
95        let req: Req = serde_json::from_value(value).map_err(|_| ServerError::ReqDeserialize)?;
96        let resp = (self.method)(server_ctx, connection_ctx, req).await?;
97        Ok(serde_json::to_value(resp).map_err(|_| ServerError::RespSerialize)?)
98    }
99}