grpc_webnext/
json_frame.rs1use std::collections::BTreeMap;
19
20use serde::{Deserialize, Serialize};
21use serde_json::Value;
22
23pub type JsonMeta = BTreeMap<String, String>;
25
26#[derive(Debug, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct JsonStatus {
29 pub code: u32,
30 #[serde(default, skip_serializing_if = "String::is_empty")]
31 pub message: String,
32}
33
34#[derive(Debug, Default, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct JsonFrame {
39 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub metadata: Option<JsonMeta>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub timeout_millis: Option<u32>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub message: Option<Value>,
48 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub half_close: Option<bool>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub status: Option<JsonStatus>,
54}
55
56pub fn decode_json_frame(text: &str) -> Result<JsonFrame, serde_json::Error> {
58 serde_json::from_str(text)
59}
60
61pub fn encode_json_frame(frame: &JsonFrame) -> String {
63 serde_json::to_string(frame).expect("JsonFrame serializes")
64}
65
66use crate::pb::{frame::Kind, metadatum, Frame, HalfClose, Message, Metadatum, Reset, Subscribe};
69
70fn meta_vec_to_json(items: &[Metadatum]) -> Option<JsonMeta> {
71 let map: JsonMeta = items
72 .iter()
73 .filter_map(|m| match &m.value {
74 Some(metadatum::Value::AsciiValue(s)) => Some((m.key.clone(), s.clone())),
75 _ => None, })
77 .collect();
78 (!map.is_empty()).then_some(map)
79}
80
81fn json_to_meta_vec(meta: &Option<JsonMeta>) -> Vec<Metadatum> {
82 meta.iter()
83 .flatten()
84 .map(|(k, v)| Metadatum {
85 key: k.clone(),
86 value: Some(metadatum::Value::AsciiValue(v.clone())),
87 })
88 .collect()
89}
90
91fn to_bytes(v: &Value) -> bytes::Bytes {
92 serde_json::to_vec(v).unwrap_or_default().into()
93}
94
95pub fn json_open_to_subscribe(f: JsonFrame, method: String) -> Subscribe {
98 Subscribe {
99 method,
100 headers: json_to_meta_vec(&f.metadata),
101 timeout_millis: f.timeout_millis.unwrap_or(0),
102 initial_payload: f.message.as_ref().map(to_bytes).unwrap_or_default(),
103 }
104}
105
106pub fn json_frame_to_proto(f: JsonFrame) -> Frame {
109 let kind = if let Some(status) = f.status {
110 Kind::Reset(Reset { status_code: status.code, status_message: status.message })
112 } else if f.half_close == Some(true) {
113 Kind::HalfClose(HalfClose {})
114 } else if let Some(message) = f.message {
115 Kind::Message(Message { payload: to_bytes(&message) })
116 } else {
117 Kind::HalfClose(HalfClose {})
119 };
120 Frame { kind: Some(kind) }
121}
122
123pub fn proto_frame_to_json(frame: &Frame) -> Option<JsonFrame> {
126 let from_bytes = |b: &[u8]| serde_json::from_slice::<Value>(b).unwrap_or(Value::Null);
127 Some(match frame.kind.as_ref()? {
128 Kind::Message(m) => JsonFrame {
129 message: Some(from_bytes(&m.payload)),
130 ..Default::default()
131 },
132 Kind::Header(h) => JsonFrame {
133 metadata: Some(meta_vec_to_json(&h.headers).unwrap_or_default()),
134 ..Default::default()
135 },
136 Kind::Trailer(t) => JsonFrame {
137 status: Some(JsonStatus { code: t.status_code, message: t.status_message.clone() }),
138 metadata: meta_vec_to_json(&t.trailers),
139 ..Default::default()
140 },
141 Kind::Reset(r) => JsonFrame {
142 status: Some(JsonStatus { code: r.status_code, message: r.status_message.clone() }),
143 ..Default::default()
144 },
145 _ => return None,
146 })
147}