relentless_grpc/
evaluate.rs

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    // Expect(AllOr<tonic::metadata::MetadataMap>), // TODO
39    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    // Expect(AllOr<http_serde_priv::Extensions>), // TODO
47    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, // TODO Self::assault_or_compare(extensions, |_| true),
175            GrpcExtensions::Ignore => true,
176        };
177        if !acceptable {
178            msg.push_err(GrpcEvaluateError::UnacceptableExtensions);
179        }
180        acceptable
181    }
182}