oasis_core_runtime/enclave_rpc/
dispatcher.rs1use std::collections::HashMap;
3
4use anyhow::{bail, Result};
5use thiserror::Error;
6
7use crate::{common::sgx::QuotePolicy, consensus::state::keymanager::Status as KeyManagerStatus};
8
9use super::{
10 context::Context,
11 types::{Body, Kind, Request, Response},
12};
13
14#[derive(Error, Debug)]
16enum DispatchError {
17 #[error("method not found: {method:?}")]
18 MethodNotFound { method: String },
19 #[error("invalid RPC kind: {method:?} ({kind:?})")]
20 InvalidRpcKind { method: String, kind: Kind },
21}
22
23pub trait Handler {
25 fn methods(&'static self) -> Vec<Method>;
27}
28
29#[derive(Clone, Debug)]
31pub struct MethodDescriptor {
32 pub name: String,
34 pub kind: Kind,
36}
37
38pub trait MethodHandler<Rq, Rsp> {
40 fn handle(&self, ctx: &Context, request: &Rq) -> Result<Rsp>;
42}
43
44impl<Rq, Rsp, F> MethodHandler<Rq, Rsp> for F
45where
46 Rq: 'static,
47 Rsp: 'static,
48 F: Fn(&Context, &Rq) -> Result<Rsp> + 'static,
49{
50 fn handle(&self, ctx: &Context, request: &Rq) -> Result<Rsp> {
51 (*self)(ctx, request)
52 }
53}
54
55pub trait MethodHandlerDispatch {
57 fn get_descriptor(&self) -> &MethodDescriptor;
59
60 fn dispatch(&self, ctx: &Context, request: Request) -> Result<Response>;
62}
63
64struct MethodHandlerDispatchImpl<Rq, Rsp> {
65 descriptor: MethodDescriptor,
67 handler: Box<dyn MethodHandler<Rq, Rsp> + Send + Sync>,
69}
70
71impl<Rq, Rsp> MethodHandlerDispatch for MethodHandlerDispatchImpl<Rq, Rsp>
72where
73 Rq: cbor::Decode + 'static,
74 Rsp: cbor::Encode + 'static,
75{
76 fn get_descriptor(&self) -> &MethodDescriptor {
77 &self.descriptor
78 }
79
80 fn dispatch(&self, ctx: &Context, request: Request) -> Result<Response> {
81 let request = cbor::from_value(request.args)?;
82 let response = self.handler.handle(ctx, &request)?;
83
84 Ok(Response {
85 body: Body::Success(cbor::to_value(response)),
86 })
87 }
88}
89
90pub struct Method {
92 dispatcher: Box<dyn MethodHandlerDispatch + Send + Sync>,
94}
95
96impl Method {
97 pub fn new<Rq, Rsp, Handler>(method: MethodDescriptor, handler: Handler) -> Self
99 where
100 Rq: cbor::Decode + 'static,
101 Rsp: cbor::Encode + 'static,
102 Handler: MethodHandler<Rq, Rsp> + Send + Sync + 'static,
103 {
104 Method {
105 dispatcher: Box::new(MethodHandlerDispatchImpl {
106 descriptor: method,
107 handler: Box::new(handler),
108 }),
109 }
110 }
111
112 fn get_name(&self) -> &String {
114 &self.dispatcher.get_descriptor().name
115 }
116
117 fn get_kind(&self) -> Kind {
119 self.dispatcher.get_descriptor().kind
120 }
121
122 fn dispatch(&self, ctx: &mut Context, request: Request) -> Result<Response> {
124 self.dispatcher.dispatch(ctx, request)
125 }
126}
127
128pub type KeyManagerStatusHandler = dyn Fn(KeyManagerStatus) + Send + Sync;
130pub type KeyManagerQuotePolicyHandler = dyn Fn(QuotePolicy) + Send + Sync;
132
133#[derive(Default)]
135pub struct Dispatcher {
136 methods: HashMap<String, Method>,
138 km_status_handler: Option<Box<KeyManagerStatusHandler>>,
140 km_quote_policy_handler: Option<Box<KeyManagerQuotePolicyHandler>>,
142}
143
144impl Dispatcher {
145 pub fn add_method(&mut self, method: Method) {
147 self.methods.insert(method.get_name().clone(), method);
148 }
149
150 pub fn add_methods(&mut self, methods: Vec<Method>) {
152 for method in methods {
153 self.add_method(method);
154 }
155 }
156
157 pub fn dispatch(&self, mut ctx: Context, request: Request, kind: Kind) -> Response {
159 match self.dispatch_fallible(&mut ctx, request, kind) {
160 Ok(response) => response,
161 Err(error) => Response {
162 body: Body::Error(format!("{error}")),
163 },
164 }
165 }
166
167 fn dispatch_fallible(
168 &self,
169 ctx: &mut Context,
170 request: Request,
171 kind: Kind,
172 ) -> Result<Response> {
173 let method = match self.methods.get(&request.method) {
174 Some(method) => method,
175 None => bail!(DispatchError::MethodNotFound {
176 method: request.method,
177 }),
178 };
179
180 if method.get_kind() != kind {
181 bail!(DispatchError::InvalidRpcKind {
182 method: request.method,
183 kind,
184 });
185 };
186
187 method.dispatch(ctx, request)
188 }
189
190 pub fn handle_km_status_update(&self, status: KeyManagerStatus) {
192 if let Some(handler) = self.km_status_handler.as_ref() {
193 handler(status)
194 }
195 }
196
197 pub fn handle_km_quote_policy_update(&self, policy: QuotePolicy) {
199 if let Some(handler) = self.km_quote_policy_handler.as_ref() {
200 handler(policy)
201 }
202 }
203
204 pub fn set_keymanager_status_update_handler(
206 &mut self,
207 f: Option<Box<KeyManagerStatusHandler>>,
208 ) {
209 self.km_status_handler = f;
210 }
211
212 pub fn set_keymanager_quote_policy_update_handler(
214 &mut self,
215 f: Option<Box<KeyManagerQuotePolicyHandler>>,
216 ) {
217 self.km_quote_policy_handler = f;
218 }
219}