1use switchback_codec_pb::canardleteer::switchback::protocol::grpc::v1alpha1::{
4 GrpcContractMeta, GrpcErrorMeta, GrpcMetadataMeta, GrpcOperationMeta, GrpcPayload,
5 GrpcStatusMeta,
6};
7use switchback_codec_pb::canardleteer::switchback::protocol::grpc::v1alpha1::__buffa::oneof::grpc_payload::Kind;
8use switchback_traits::{ProtocolAttachment, ResponseSeverity, Result};
9
10use crate::severity::{grpc_status_name_severity, grpc_status_severity};
11use crate::traits::{
12 ErrorProtocol, FieldCarrierProtocol, OperationProtocol, Protocol, ProtocolWire,
13 ResponseProtocol,
14};
15use crate::wire::{decode_message, encode_message};
16
17#[derive(Clone, Copy, Debug, Default)]
19pub struct GrpcProtocol;
20
21impl Protocol for GrpcProtocol {
22 fn id(&self) -> &'static str {
23 "grpc"
24 }
25}
26
27impl OperationProtocol for GrpcProtocol {
28 type OperationMeta = GrpcOperationMeta;
29
30 fn format_signature(&self, meta: &Self::OperationMeta) -> String {
31 let streaming = match (meta.client_streaming, meta.server_streaming) {
32 (true, true) => "stream ",
33 (true, false) => "stream ",
34 (false, true) => "",
35 (false, false) => "",
36 };
37 let out_stream = if meta.server_streaming { "stream " } else { "" };
38 format!(
39 "{} ( {streaming}… ) returns ( {out_stream}… )",
40 meta.rpc_name
41 )
42 }
43}
44
45impl ResponseProtocol for GrpcProtocol {
46 fn response_severity(&self, status_key: &str) -> ResponseSeverity {
47 grpc_status_name_severity(status_key)
48 }
49}
50
51impl ErrorProtocol for GrpcProtocol {
52 type ErrorMeta = GrpcErrorMeta;
53
54 fn error_severity(&self, error_key: &str) -> ResponseSeverity {
55 grpc_status_name_severity(error_key)
56 }
57
58 fn format_error_label(&self, error_key: &str) -> String {
59 format!("gRPC {error_key}")
60 }
61}
62
63impl FieldCarrierProtocol for GrpcProtocol {
64 fn field_carrier_kinds(&self) -> &'static [&'static str] {
65 &["metadata"]
66 }
67
68 fn valid_parameter_locations(&self) -> &'static [&'static str] {
69 &["metadata"]
70 }
71}
72
73impl GrpcProtocol {
74 pub fn attach_contract(&self, meta: &GrpcContractMeta) -> ProtocolAttachment {
76 attachment_from_payload(GrpcPayload {
77 kind: Some(Kind::Contract(Box::new(meta.clone()))),
78 ..Default::default()
79 })
80 }
81
82 pub fn attach_operation(&self, meta: &GrpcOperationMeta) -> ProtocolAttachment {
84 attachment_from_payload(GrpcPayload {
85 kind: Some(Kind::Operation(Box::new(meta.clone()))),
86 ..Default::default()
87 })
88 }
89
90 pub fn attach_status(&self, meta: &GrpcStatusMeta) -> ProtocolAttachment {
92 attachment_from_payload(GrpcPayload {
93 kind: Some(Kind::Status(Box::new(meta.clone()))),
94 ..Default::default()
95 })
96 }
97
98 pub fn attach_error(&self, meta: &GrpcErrorMeta) -> ProtocolAttachment {
100 attachment_from_payload(GrpcPayload {
101 kind: Some(Kind::Error(Box::new(meta.clone()))),
102 ..Default::default()
103 })
104 }
105
106 pub fn attach_metadata(&self, meta: &GrpcMetadataMeta) -> ProtocolAttachment {
108 attachment_from_payload(GrpcPayload {
109 kind: Some(Kind::Metadata(Box::new(meta.clone()))),
110 ..Default::default()
111 })
112 }
113
114 pub fn operation_meta(
116 rpc_name: &str,
117 client_streaming: bool,
118 server_streaming: bool,
119 ) -> GrpcOperationMeta {
120 GrpcOperationMeta {
121 rpc_name: rpc_name.to_string(),
122 client_streaming,
123 server_streaming,
124 ..Default::default()
125 }
126 }
127
128 pub fn status_meta_ok() -> GrpcStatusMeta {
130 GrpcStatusMeta {
131 code: 0,
132 message: "OK".to_string(),
133 ..Default::default()
134 }
135 }
136
137 pub fn error_meta(code_name: &str, message: &str) -> GrpcErrorMeta {
139 let code = grpc_code_from_name(code_name);
140 GrpcErrorMeta {
141 code,
142 message: message.to_string(),
143 ..Default::default()
144 }
145 }
146
147 pub fn metadata_meta(key: &str, required: bool) -> GrpcMetadataMeta {
149 GrpcMetadataMeta {
150 key: key.to_string(),
151 required,
152 ..Default::default()
153 }
154 }
155
156 pub fn contract_meta(package_name: &str) -> GrpcContractMeta {
158 GrpcContractMeta {
159 package_name: package_name.to_string(),
160 ..Default::default()
161 }
162 }
163
164 pub fn severity_for_code(code: i32) -> ResponseSeverity {
166 grpc_status_severity(code)
167 }
168}
169
170impl ProtocolWire for GrpcOperationMeta {
171 const PROTOCOL_ID: &'static str = "grpc";
172
173 fn encode_to_vec(&self) -> Vec<u8> {
174 encode_message(&GrpcPayload {
175 kind: Some(Kind::Operation(Box::new(self.clone()))),
176 ..Default::default()
177 })
178 }
179
180 fn decode_from_bytes(bytes: &[u8]) -> Result<Self> {
181 let payload: GrpcPayload = decode_message(bytes)?;
182 match payload.kind {
183 Some(Kind::Operation(meta)) => Ok(*meta),
184 _ => Err(switchback_traits::SwitchbackError::codec(
185 "expected GrpcOperationMeta payload",
186 )),
187 }
188 }
189}
190
191impl ProtocolWire for GrpcErrorMeta {
192 const PROTOCOL_ID: &'static str = "grpc";
193
194 fn encode_to_vec(&self) -> Vec<u8> {
195 encode_message(&GrpcPayload {
196 kind: Some(Kind::Error(Box::new(self.clone()))),
197 ..Default::default()
198 })
199 }
200
201 fn decode_from_bytes(bytes: &[u8]) -> Result<Self> {
202 let payload: GrpcPayload = decode_message(bytes)?;
203 match payload.kind {
204 Some(Kind::Error(meta)) => Ok(*meta),
205 _ => Err(switchback_traits::SwitchbackError::codec(
206 "expected GrpcErrorMeta payload",
207 )),
208 }
209 }
210}
211
212fn attachment_from_payload(payload: GrpcPayload) -> ProtocolAttachment {
213 let protocol = GrpcProtocol;
214 ProtocolAttachment {
215 protocol_id: protocol.id().to_string(),
216 payload: encode_message(&payload),
217 }
218}
219
220fn grpc_code_from_name(name: &str) -> i32 {
221 match name.trim().to_ascii_uppercase().as_str() {
222 "OK" => 0,
223 "CANCELLED" => 1,
224 "UNKNOWN" => 2,
225 "INVALID_ARGUMENT" => 3,
226 "DEADLINE_EXCEEDED" => 4,
227 "NOT_FOUND" => 5,
228 "ALREADY_EXISTS" => 6,
229 "PERMISSION_DENIED" => 7,
230 "RESOURCE_EXHAUSTED" => 8,
231 "FAILED_PRECONDITION" => 9,
232 "ABORTED" => 10,
233 "OUT_OF_RANGE" => 11,
234 "UNIMPLEMENTED" => 12,
235 "INTERNAL" => 13,
236 "UNAVAILABLE" => 14,
237 "DATA_LOSS" => 15,
238 "UNAUTHENTICATED" => 16,
239 _ => 2,
240 }
241}