1use crate::{PluginCapabilities, PluginContext, PluginResult, Result};
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use std::collections::HashMap;
11
12#[async_trait::async_trait]
18pub trait TemplatePlugin: Send + Sync {
19 fn capabilities(&self) -> PluginCapabilities;
21
22 async fn initialize(&self, config: &TemplatePluginConfig) -> Result<()>;
24
25 async fn register_functions(
38 &self,
39 context: &PluginContext,
40 config: &TemplatePluginConfig,
41 ) -> Result<PluginResult<HashMap<String, TemplateFunction>>>;
42
43 async fn execute_function(
57 &self,
58 context: &PluginContext,
59 function_name: &str,
60 args: &[Value],
61 config: &TemplatePluginConfig,
62 ) -> Result<PluginResult<Value>>;
63
64 async fn get_data_source(
77 &self,
78 context: &PluginContext,
79 data_source: &str,
80 config: &TemplatePluginConfig,
81 ) -> Result<PluginResult<Value>>;
82
83 fn validate_config(&self, config: &TemplatePluginConfig) -> Result<()>;
85
86 fn available_data_sources(&self) -> Vec<String>;
88
89 async fn cleanup(&self) -> Result<()>;
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct TemplatePluginConfig {
96 pub config: HashMap<String, serde_json::Value>,
98 pub enabled: bool,
100 pub function_prefix: Option<String>,
102 pub data_refresh_interval_secs: Option<u64>,
104 pub settings: HashMap<String, serde_json::Value>,
106}
107
108impl Default for TemplatePluginConfig {
109 fn default() -> Self {
110 Self {
111 config: HashMap::new(),
112 enabled: true,
113 function_prefix: None,
114 data_refresh_interval_secs: Some(300), settings: HashMap::new(),
116 }
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct TemplateFunction {
123 pub name: String,
125 pub description: String,
127 pub parameters: Vec<FunctionParameter>,
129 pub return_type: String,
131 pub examples: Vec<String>,
133 pub category: Option<String>,
135 pub pure: bool,
137}
138
139impl TemplateFunction {
140 pub fn new<S: Into<String>>(name: S, description: S, return_type: S) -> Self {
142 Self {
143 name: name.into(),
144 description: description.into(),
145 parameters: Vec::new(),
146 return_type: return_type.into(),
147 examples: Vec::new(),
148 category: None,
149 pure: true,
150 }
151 }
152
153 pub fn with_parameter(mut self, param: FunctionParameter) -> Self {
155 self.parameters.push(param);
156 self
157 }
158
159 pub fn with_parameters(mut self, params: Vec<FunctionParameter>) -> Self {
161 self.parameters.extend(params);
162 self
163 }
164
165 pub fn with_example<S: Into<String>>(mut self, example: S) -> Self {
167 self.examples.push(example.into());
168 self
169 }
170
171 pub fn with_category<S: Into<String>>(mut self, category: S) -> Self {
173 self.category = Some(category.into());
174 self
175 }
176
177 pub fn impure(mut self) -> Self {
179 self.pure = false;
180 self
181 }
182
183 pub fn param_count(&self) -> usize {
185 self.parameters.len()
186 }
187
188 pub fn has_var_args(&self) -> bool {
190 self.parameters.iter().any(|p| p.var_args)
191 }
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct FunctionParameter {
197 pub name: String,
199 pub param_type: String,
201 pub description: String,
203 pub required: bool,
205 pub default_value: Option<Value>,
207 pub var_args: bool,
209}
210
211impl FunctionParameter {
212 pub fn required<S: Into<String>>(name: S, param_type: S, description: S) -> Self {
214 Self {
215 name: name.into(),
216 param_type: param_type.into(),
217 description: description.into(),
218 required: true,
219 default_value: None,
220 var_args: false,
221 }
222 }
223
224 pub fn optional<S: Into<String>>(name: S, param_type: S, description: S) -> Self {
226 Self {
227 name: name.into(),
228 param_type: param_type.into(),
229 description: description.into(),
230 required: false,
231 default_value: None,
232 var_args: false,
233 }
234 }
235
236 pub fn with_default<S: Into<String>>(
238 name: S,
239 param_type: S,
240 description: S,
241 default: Value,
242 ) -> Self {
243 Self {
244 name: name.into(),
245 param_type: param_type.into(),
246 description: description.into(),
247 required: false,
248 default_value: Some(default),
249 var_args: false,
250 }
251 }
252
253 pub fn var_args<S: Into<String>>(name: S, param_type: S, description: S) -> Self {
255 Self {
256 name: name.into(),
257 param_type: param_type.into(),
258 description: description.into(),
259 required: false,
260 default_value: None,
261 var_args: true,
262 }
263 }
264}
265
266#[derive(Debug, Clone)]
268pub struct TemplateExecutionContext {
269 pub template: String,
271 pub position: usize,
273 pub variables: HashMap<String, Value>,
275 pub request_context: Option<HashMap<String, Value>>,
277 pub custom: HashMap<String, Value>,
279}
280
281impl TemplateExecutionContext {
282 pub fn new<S: Into<String>>(template: S) -> Self {
284 Self {
285 template: template.into(),
286 position: 0,
287 variables: HashMap::new(),
288 request_context: None,
289 custom: HashMap::new(),
290 }
291 }
292
293 pub fn with_position(mut self, position: usize) -> Self {
295 self.position = position;
296 self
297 }
298
299 pub fn with_variable<S: Into<String>>(mut self, key: S, value: Value) -> Self {
301 self.variables.insert(key.into(), value);
302 self
303 }
304
305 pub fn with_request_context(mut self, context: HashMap<String, Value>) -> Self {
307 self.request_context = Some(context);
308 self
309 }
310
311 pub fn with_custom<S: Into<String>>(mut self, key: S, value: Value) -> Self {
313 self.custom.insert(key.into(), value);
314 self
315 }
316
317 pub fn get_variable(&self, key: &str) -> Option<&Value> {
319 self.variables.get(key)
320 }
321
322 pub fn get_request_value(&self, key: &str) -> Option<&Value> {
324 self.request_context.as_ref()?.get(key)
325 }
326
327 pub fn get_custom_value(&self, key: &str) -> Option<&Value> {
329 self.custom.get(key)
330 }
331}
332
333pub struct TemplateFunctionEntry {
335 pub plugin_id: crate::PluginId,
337 pub function: TemplateFunction,
339 pub plugin: std::sync::Arc<dyn TemplatePlugin>,
341 pub config: TemplatePluginConfig,
343}
344
345impl TemplateFunctionEntry {
346 pub fn new(
348 plugin_id: crate::PluginId,
349 function: TemplateFunction,
350 plugin: std::sync::Arc<dyn TemplatePlugin>,
351 config: TemplatePluginConfig,
352 ) -> Self {
353 Self {
354 plugin_id,
355 function,
356 plugin,
357 config,
358 }
359 }
360
361 pub fn full_name(&self) -> String {
363 if let Some(prefix) = &self.config.function_prefix {
364 format!("{}_{}", prefix, self.function.name)
365 } else {
366 self.function.name.clone()
367 }
368 }
369
370 pub fn is_enabled(&self) -> bool {
372 self.config.enabled
373 }
374}
375
376pub trait TemplatePluginFactory: Send + Sync {
378 fn create_plugin(&self) -> Result<Box<dyn TemplatePlugin>>;
380}
381
382pub mod builtin {
384 use super::*;
385
386 pub fn uuid_v4() -> String {
388 uuid::Uuid::new_v4().to_string()
389 }
390
391 pub fn now_rfc3339() -> String {
393 chrono::Utc::now().to_rfc3339()
394 }
395
396 pub fn random_int(min: i64, max: i64) -> i64 {
398 use rand::Rng;
399 rand::rng().random_range(min..=max)
400 }
401
402 pub fn random_float() -> f64 {
404 rand::random::<f64>()
405 }
406
407 pub fn url_encode(input: &str) -> String {
409 urlencoding::encode(input).to_string()
410 }
411
412 pub fn url_decode(input: &str) -> Result<String> {
414 urlencoding::decode(input)
415 .map(|s| s.to_string())
416 .map_err(|e| crate::PluginError::execution(format!("URL decode error: {}", e)))
417 }
418
419 pub fn json_stringify(value: &Value) -> Result<String> {
421 serde_json::to_string(value)
422 .map_err(|e| crate::PluginError::execution(format!("JSON stringify error: {}", e)))
423 }
424
425 pub fn json_parse(input: &str) -> Result<Value> {
427 serde_json::from_str(input)
428 .map_err(|e| crate::PluginError::execution(format!("JSON parse error: {}", e)))
429 }
430}
431
432#[cfg(test)]
433mod tests {
434
435 #[test]
436 fn test_module_compiles() {
437 }
439}