1use std::fmt::Debug;
2
3use http::Extensions;
4use serde::{Deserialize, Serialize};
5use tonic::metadata::MetadataMap;
6
7use relentless::{
8 assault::{
9 destinations::Destinations,
10 evaluate::{Acceptable, Evaluate},
11 evaluator::{json::JsonEvaluator, plaintext::PlaintextEvaluator},
12 messages::Messages,
13 result::RequestResult,
14 },
15 interface::helper::{coalesce::Coalesce, is_default::IsDefault},
16};
17
18use super::error::GrpcEvaluateError;
19
20#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
21#[serde(deny_unknown_fields, rename_all = "kebab-case")]
22pub struct GrpcResponse {
23 #[serde(default, skip_serializing_if = "IsDefault::is_default")]
24 #[cfg_attr(feature = "yaml", serde(with = "serde_yaml::with::singleton_map_recursive"))]
25 pub metadata_map: GrpcMetadataMap,
26 #[serde(default, skip_serializing_if = "IsDefault::is_default")]
27 #[cfg_attr(feature = "yaml", serde(with = "serde_yaml::with::singleton_map_recursive"))]
28 pub extensions: GrpcExtensions,
29 #[serde(default, skip_serializing_if = "IsDefault::is_default")]
30 #[cfg_attr(feature = "yaml", serde(with = "serde_yaml::with::singleton_map_recursive"))]
31 pub message: GrpcMessage,
32}
33#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
34#[serde(deny_unknown_fields, rename_all = "kebab-case")]
35pub enum GrpcMetadataMap {
36 #[default]
37 AnyOrEqual,
38 Ignore,
40}
41#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
42#[serde(deny_unknown_fields, rename_all = "kebab-case")]
43pub enum GrpcExtensions {
44 #[default]
45 AnyOrEqual,
46 Ignore,
48}
49#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
50#[serde(deny_unknown_fields, rename_all = "kebab-case")]
51pub enum GrpcMessage {
52 #[default]
53 AnyOrEqual,
54 Plaintext(PlaintextEvaluator),
55 Json(JsonEvaluator),
56}
57impl Coalesce for GrpcResponse {
58 fn coalesce(self, other: &Self) -> Self {
59 Self {
60 metadata_map: self.metadata_map.coalesce(&other.metadata_map),
61 extensions: self.extensions.coalesce(&other.extensions),
62 message: self.message.coalesce(&other.message),
63 }
64 }
65}
66impl Coalesce for GrpcMetadataMap {
67 fn coalesce(self, other: &Self) -> Self {
68 if self.is_default() {
69 other.clone()
70 } else {
71 self
72 }
73 }
74}
75impl Coalesce for GrpcMessage {
76 fn coalesce(self, other: &Self) -> Self {
77 if self.is_default() {
78 other.clone()
79 } else {
80 self
81 }
82 }
83}
84impl Coalesce for GrpcExtensions {
85 fn coalesce(self, other: &Self) -> Self {
86 if self.is_default() {
87 other.clone()
88 } else {
89 self
90 }
91 }
92}
93
94impl Evaluate<tonic::Response<serde_json::Value>> for GrpcResponse {
95 type Message = GrpcEvaluateError;
96 async fn evaluate(
97 &self,
98 res: Destinations<RequestResult<tonic::Response<serde_json::Value>>>,
99 msg: &mut Messages<Self::Message>,
100 ) -> bool {
101 let Some(responses) = msg.response_destinations_with(res, GrpcEvaluateError::RequestError) else {
102 return false;
103 };
104 let Some(parts) = msg.push_if_err(GrpcResponse::unzip_parts(responses).await) else {
105 return false;
106 };
107
108 self.accept(&parts, msg)
109 }
110}
111
112impl Acceptable<(MetadataMap, serde_json::Value, Extensions)> for GrpcResponse {
113 type Message = GrpcEvaluateError;
114 fn accept(
115 &self,
116 parts: &Destinations<(MetadataMap, serde_json::Value, Extensions)>,
117 msg: &mut Messages<Self::Message>,
118 ) -> bool {
119 let (mut metadata, mut message, mut extensions) =
120 (Destinations::new(), Destinations::new(), Destinations::new());
121 for (name, (d, m, e)) in parts {
122 metadata.insert(name.clone(), d.clone().into_headers());
123 message.insert(name.clone(), m);
124 extensions.insert(name.clone(), e);
125 }
126 self.metadata_map.accept(&metadata, msg)
127 && self.message.accept(&message, msg)
128 && self.extensions.accept(&extensions, msg)
129 }
130}
131
132impl GrpcResponse {
133 pub async fn unzip_parts(
134 responses: Destinations<tonic::Response<serde_json::Value>>,
135 ) -> Result<Destinations<(MetadataMap, serde_json::Value, Extensions)>, GrpcEvaluateError> {
136 let mut parts = Destinations::new();
137 for (name, response) in responses {
138 let (metadata, message, extensions) = response.into_parts();
139 parts.insert(name, (metadata, message, extensions));
140 }
141 Ok(parts)
142 }
143}
144
145impl Acceptable<&serde_json::Value> for GrpcMessage {
146 type Message = GrpcEvaluateError;
147 fn accept(&self, values: &Destinations<&serde_json::Value>, msg: &mut Messages<Self::Message>) -> bool {
148 match self {
149 GrpcMessage::AnyOrEqual => Self::assault_or_compare(values, |_| true),
150 GrpcMessage::Plaintext(_plaintext) => unimplemented!(),
151 GrpcMessage::Json(json) => Self::sub_accept(json, values, msg, GrpcEvaluateError::JsonEvaluateError),
152 }
153 }
154}
155
156impl Acceptable<http::HeaderMap> for GrpcMetadataMap {
157 type Message = GrpcEvaluateError;
158 fn accept(&self, maps: &Destinations<http::HeaderMap>, msg: &mut Messages<Self::Message>) -> bool {
159 let acceptable = match self {
160 GrpcMetadataMap::AnyOrEqual => Self::assault_or_compare(maps, |_| true),
161 GrpcMetadataMap::Ignore => true,
162 };
163 if !acceptable {
164 msg.push_err(GrpcEvaluateError::UnacceptableMetadataMap);
165 }
166 acceptable
167 }
168}
169
170impl Acceptable<&Extensions> for GrpcExtensions {
171 type Message = GrpcEvaluateError;
172 fn accept(&self, _extensions: &Destinations<&Extensions>, msg: &mut Messages<Self::Message>) -> bool {
173 let acceptable = match self {
174 GrpcExtensions::AnyOrEqual => true, GrpcExtensions::Ignore => true,
176 };
177 if !acceptable {
178 msg.push_err(GrpcEvaluateError::UnacceptableExtensions);
179 }
180 acceptable
181 }
182}