use std::collections::HashMap; use anyhow::anyhow; use rhai::{Dynamic, Engine, Map, Scope}; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] pub struct ReactionResult { pub channel_id: String, pub count: i64, pub icon: String, } pub fn check( script: &str, reactions: HashMap, channel: String, ) -> anyhow::Result> { let mut engine = Engine::new(); engine.set_max_operations(1000); engine.register_type::(); engine.register_fn("result", |webhook_url: String, count: i64, icon: String| { ReactionResult { channel_id: webhook_url, count, icon, } }); engine .disable_symbol("for") .disable_symbol("while") .disable_symbol("loop") .set_max_expr_depths(50, 5) .set_max_string_size(60) .set_max_map_size(512) .set_max_array_size(512); let mut emotes_input = Map::new(); for (emoji, count) in reactions { emotes_input.insert(emoji.into(), Dynamic::from(count)); } let mut scope = Scope::new(); scope.set_value("reactions", Dynamic::from(emotes_input)); scope.set_value("channel", Dynamic::from(channel)); let result: Dynamic = engine .eval_with_scope(&mut scope, script) .map_err(|e| anyhow!("{e:?}"))?; let result: Option = if result.is_unit() { None } else { Some( result .try_cast_result() .map_err(|e| anyhow!("failed to cast: {e:?}"))?, ) }; return Ok(result); }