grpc_webnext/
transcode.rs1use prost_reflect::prost::Message;
11use prost_reflect::{DescriptorPool, DynamicMessage, MessageDescriptor};
12use serde::Serialize;
13
14use crate::httprule::HttpRouter;
15pub use crate::httprule::{HttpCall, WsBinding};
16
17#[derive(Debug, thiserror::Error)]
18pub enum TranscodeError {
19 #[error("failed to load descriptor set: {0}")]
20 Descriptor(String),
21 #[error("unknown method: {0}")]
22 UnknownMethod(String),
23 #[error("json error: {0}")]
24 Json(#[from] serde_json::Error),
25 #[error("protobuf decode error: {0}")]
26 Decode(String),
27 #[error("http transcoding: {0}")]
28 Http(String),
29}
30
31#[derive(Clone)]
35pub struct Transcoder {
36 pool: DescriptorPool,
37 router: HttpRouter,
38}
39
40impl Transcoder {
41 pub fn from_file_descriptor_set(bytes: &[u8]) -> Result<Self, TranscodeError> {
43 let pool = DescriptorPool::decode(bytes)
44 .map_err(|e| TranscodeError::Descriptor(e.to_string()))?;
45 let router = HttpRouter::from_pool(&pool);
46 Ok(Self { pool, router })
47 }
48
49 pub fn has_http_rules(&self) -> bool {
51 !self.router.is_empty()
52 }
53
54 pub fn transcode_http_request(
57 &self,
58 method: &str,
59 path: &str,
60 query: Option<&str>,
61 body: &[u8],
62 ) -> Result<Option<HttpCall>, TranscodeError> {
63 self.router.transcode(method, path, query, body)
64 }
65
66 pub fn match_ws(&self, path: &str, query: Option<&str>) -> Option<WsBinding> {
69 self.router.match_ws(path, query)
70 }
71
72 pub fn is_annotated_method(&self, grpc_method: &str) -> bool {
75 self.router.is_annotated(grpc_method)
76 }
77
78 fn io_types(&self, path: &str) -> Result<(MessageDescriptor, MessageDescriptor), TranscodeError> {
80 let (service, method) = path
81 .trim_start_matches('/')
82 .split_once('/')
83 .ok_or_else(|| TranscodeError::UnknownMethod(path.to_string()))?;
84 let svc = self
85 .pool
86 .get_service_by_name(service)
87 .ok_or_else(|| TranscodeError::UnknownMethod(path.to_string()))?;
88 let m = svc
89 .methods()
90 .find(|m| m.name() == method)
91 .ok_or_else(|| TranscodeError::UnknownMethod(path.to_string()))?;
92 Ok((m.input(), m.output()))
93 }
94
95 pub fn has_method(&self, path: &str) -> bool {
99 self.io_types(path).is_ok()
100 }
101
102 pub fn request_json_to_proto(&self, path: &str, json: &[u8]) -> Result<Vec<u8>, TranscodeError> {
104 let (input, _) = self.io_types(path)?;
105 Ok(self.json_to_proto(input, json)?.encode_to_vec())
106 }
107
108 pub fn response_proto_to_json(&self, path: &str, proto: &[u8]) -> Result<Vec<u8>, TranscodeError> {
110 let (_, output) = self.io_types(path)?;
111 self.proto_to_json(output, proto)
112 }
113
114 fn json_to_proto(
115 &self,
116 desc: MessageDescriptor,
117 json: &[u8],
118 ) -> Result<DynamicMessage, TranscodeError> {
119 if json.is_empty() {
120 return Ok(DynamicMessage::new(desc));
121 }
122 let mut de = serde_json::Deserializer::from_slice(json);
123 let msg = DynamicMessage::deserialize(desc, &mut de)?;
124 de.end()?;
125 Ok(msg)
126 }
127
128 fn proto_to_json(&self, desc: MessageDescriptor, proto: &[u8]) -> Result<Vec<u8>, TranscodeError> {
129 let msg =
130 DynamicMessage::decode(desc, proto).map_err(|e| TranscodeError::Decode(e.to_string()))?;
131 let mut buf = Vec::new();
132 let mut ser = serde_json::Serializer::new(&mut buf);
133 msg.serialize(&mut ser)?;
134 Ok(buf)
135 }
136}