You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
multihook/src/server/action/template.rs

74 lines
2.0 KiB
Rust

use jsonpath::Selector;
use lazy_static::lazy_static;
use regex::{Match, Regex};
use serde_json::Value;
#[derive(Clone)]
pub struct ActionTemplate {
src: String,
matches: Vec<(usize, usize)>,
}
impl ActionTemplate {
pub fn new<S: ToString>(command: S) -> Self {
lazy_static! {
static ref PLACEHOLDER_REGEX: Regex = Regex::new(r"\{\{(.*?)\}\}").unwrap();
}
let command = command.to_string();
let matches = PLACEHOLDER_REGEX
.find_iter(&command)
.map(|m: Match| (m.start(), m.end()))
.collect();
Self {
src: command,
matches,
}
}
pub fn evaluate(&self, json: &Value) -> String {
let mut result_string = String::with_capacity(self.src.len());
let mut last_index = 0;
for (start, end) in &self.matches {
let before = &self.src[last_index..*start];
let query = &self.src[*start + 2..*end - 2];
result_string.push_str(before);
result_string.push_str(&evaluate_path(query, json).unwrap_or_default());
last_index = *end;
}
result_string.push_str(&self.src[last_index..]);
result_string
}
}
fn evaluate_path(query: &str, json: &Value) -> Option<String> {
let selector = Selector::new(query).ok()?;
let results = selector
.find(json)
.map(json_to_string)
.collect::<Vec<String>>();
Some(results.join("\n"))
}
fn json_to_string(value: &Value) -> String {
match value {
Value::Null => String::with_capacity(0),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => s.to_owned(),
Value::Array(a) => a
.iter()
.map(|v| json_to_string(v))
.collect::<Vec<String>>()
.join("\n"),
Value::Object(o) => o
.iter()
.map(|(k, v)| format!("{} = {}", k, json_to_string(v)))
.collect::<Vec<String>>()
.join("\n"),
}
}