1use std::collections::BTreeMap;
2
3use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::with::AsJson;
8
9#[derive(
10 Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize,
11)]
12#[serde(deny_unknown_fields)]
13pub struct AllowRule {
14 pub scheme: String,
15 pub host: String,
16 pub port: u16,
17 pub path_prefix: String,
18}
19
20#[derive(
21 Debug,
22 Clone,
23 Copy,
24 Default,
25 Deserialize,
26 Serialize,
27 PartialEq,
28 Eq,
29 Archive,
30 RkyvSerialize,
31 RkyvDeserialize,
32)]
33pub enum CommandMode {
34 #[serde(rename = "read")]
35 Read,
36 #[default]
37 #[serde(rename = "write")]
38 Write,
39}
40
41impl CommandMode {
42 pub fn as_str(&self) -> &'static str {
43 match self {
44 CommandMode::Read => "read",
45 CommandMode::Write => "write",
46 }
47 }
48}
49
50#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
51#[serde(deny_unknown_fields)]
52pub struct ParamSpec {
53 pub name: String,
54 #[serde(rename = "type")]
55 pub r#type: ParamType,
56 #[serde(default)]
57 pub required: bool,
58 #[rkyv(with = AsJson)]
59 pub default: Option<Value>,
60 pub description: Option<String>,
61}
62
63#[derive(
64 Debug,
65 Clone,
66 Copy,
67 Deserialize,
68 Serialize,
69 PartialEq,
70 Eq,
71 Archive,
72 RkyvSerialize,
73 RkyvDeserialize,
74)]
75#[serde(rename_all = "lowercase")]
76pub enum ParamType {
77 String,
78 Integer,
79 Number,
80 Boolean,
81 Null,
82 Array,
83 Object,
84}
85
86impl std::fmt::Display for ParamType {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 let label = match self {
89 ParamType::String => "string",
90 ParamType::Integer => "integer",
91 ParamType::Number => "number",
92 ParamType::Boolean => "boolean",
93 ParamType::Null => "null",
94 ParamType::Array => "array",
95 ParamType::Object => "object",
96 };
97 write!(f, "{label}")
98 }
99}
100
101#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
102#[serde(tag = "kind", rename_all = "snake_case")]
103pub enum AuthTemplate {
104 None,
105 ApiKey {
106 location: ApiKeyLocation,
107 name: String,
108 secret: String,
109 },
110 Bearer {
111 secret: String,
112 },
113 Basic {
114 username: String,
115 password_secret: String,
116 },
117 OAuth2Profile {
118 profile: String,
119 },
120}
121
122#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
123#[serde(rename_all = "snake_case")]
124pub enum ApiKeyLocation {
125 Header,
126 Query,
127 Cookie,
128}
129
130#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
131#[serde(tag = "kind", rename_all = "snake_case")]
132pub enum BodyTemplate {
133 None,
134 Json {
135 #[rkyv(with = AsJson)]
136 value: Value,
137 },
138 FormUrlencoded {
139 #[rkyv(with = AsJson)]
140 fields: BTreeMap<String, Value>,
141 },
142 Multipart {
143 parts: Vec<MultipartPartTemplate>,
144 },
145 RawText {
146 value: String,
147 content_type: Option<String>,
148 },
149 RawBytesBase64 {
150 value: String,
151 content_type: Option<String>,
152 },
153 FileStream {
154 path: String,
155 content_type: Option<String>,
156 },
157}
158
159#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
160#[serde(deny_unknown_fields)]
161pub struct MultipartPartTemplate {
162 pub name: String,
163 pub value: Option<String>,
164 pub bytes_base64: Option<String>,
165 pub file_path: Option<String>,
166 pub content_type: Option<String>,
167 pub filename: Option<String>,
168}
169
170#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
171#[serde(deny_unknown_fields)]
172pub struct TransportTemplate {
173 pub timeout_ms: Option<u64>,
174 pub max_response_bytes: Option<u64>,
175 pub redirects: Option<RedirectTemplate>,
176 pub retry: Option<RetryTemplate>,
177 pub compression: Option<bool>,
178 pub tls: Option<TlsTemplate>,
179 pub proxy_profile: Option<String>,
180}
181
182#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
183#[serde(deny_unknown_fields)]
184pub struct RedirectTemplate {
185 #[serde(default = "default_follow_redirects")]
186 pub follow: bool,
187 #[serde(default = "default_redirect_hops")]
188 pub max_hops: usize,
189}
190
191#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
192#[serde(deny_unknown_fields)]
193pub struct RetryTemplate {
194 #[serde(default)]
195 pub max_attempts: usize,
196 #[serde(default = "default_backoff_ms")]
197 pub backoff_ms: u64,
198 #[serde(default)]
199 pub retry_on_status: Vec<u16>,
200}
201
202#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
203#[serde(deny_unknown_fields)]
204pub struct TlsTemplate {
205 pub min_version: Option<String>,
206}
207
208#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
209#[serde(deny_unknown_fields)]
210pub struct ResultTemplate {
211 #[serde(default)]
212 pub decode: ResultDecode,
213 pub extract: Option<ResultExtract>,
214 #[serde(default = "default_result_output")]
215 pub output: String,
216 pub result_alias: Option<String>,
217}
218
219impl Default for ResultTemplate {
220 fn default() -> Self {
221 Self {
222 decode: ResultDecode::default(),
223 extract: None,
224 output: default_result_output(),
225 result_alias: None,
226 }
227 }
228}
229
230fn default_result_output() -> String {
231 "{{ result }}".to_string()
232}
233
234#[derive(
235 Debug, Clone, Copy, Default, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize,
236)]
237#[serde(rename_all = "snake_case")]
238pub enum ResultDecode {
239 #[default]
240 Auto,
241 Json,
242 Text,
243 Html,
244 Xml,
245 Binary,
246}
247
248#[derive(Debug, Clone, Deserialize, Serialize, Archive, RkyvSerialize, RkyvDeserialize)]
249#[serde(untagged)]
250pub enum ResultExtract {
251 JsonPointer { json_pointer: String },
252 Regex { regex: String },
253 XPath { xpath: String },
254 CssSelector { css_selector: String },
255}
256
257pub fn default_follow_redirects() -> bool {
258 true
259}
260
261pub fn default_redirect_hops() -> usize {
262 5
263}
264
265pub fn default_backoff_ms() -> u64 {
266 250
267}