script.rs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. use super::use_lowercase;
  2. use anyhow::Result;
  3. use serde_yaml::Mapping;
  4. pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(String, String)>)> {
  5. use rquickjs::{Context, Func, Runtime};
  6. use std::sync::{Arc, Mutex};
  7. let runtime = Runtime::new().unwrap();
  8. let context = Context::full(&runtime).unwrap();
  9. let outputs = Arc::new(Mutex::new(vec![]));
  10. let copy_outputs = outputs.clone();
  11. let result = context.with(|ctx| -> Result<Mapping> {
  12. ctx.globals().set(
  13. "__verge_log__",
  14. Func::from(move |level: String, data: String| {
  15. let mut out = copy_outputs.lock().unwrap();
  16. out.push((level, data));
  17. }),
  18. )?;
  19. ctx.eval(
  20. r#"var console = Object.freeze({
  21. log(data){__verge_log__("log",JSON.stringify(data))},
  22. info(data){__verge_log__("info",JSON.stringify(data))},
  23. error(data){__verge_log__("error",JSON.stringify(data))},
  24. debug(data){__verge_log__("debug",JSON.stringify(data))},
  25. });"#,
  26. )?;
  27. let config = use_lowercase(config.clone());
  28. let config_str = serde_json::to_string(&config)?;
  29. let code = format!(
  30. r#"try{{
  31. {script};
  32. JSON.stringify(main({config_str})||'')
  33. }} catch(err) {{
  34. `__error_flag__ ${{err.toString()}}`
  35. }}"#
  36. );
  37. let result: String = ctx.eval(code.as_str())?;
  38. if result.starts_with("__error_flag__") {
  39. anyhow::bail!(result[15..].to_owned());
  40. }
  41. if result == "\"\"" {
  42. anyhow::bail!("main function should return object");
  43. }
  44. return Ok(serde_json::from_str::<Mapping>(result.as_str())?);
  45. });
  46. let mut out = outputs.lock().unwrap();
  47. match result {
  48. Ok(config) => Ok((use_lowercase(config), out.to_vec())),
  49. Err(err) => {
  50. out.push(("exception".into(), err.to_string()));
  51. Ok((config, out.to_vec()))
  52. }
  53. }
  54. }
  55. #[test]
  56. fn test_script() {
  57. let script = r#"
  58. function main(config) {
  59. if (Array.isArray(config.rules)) {
  60. config.rules = [...config.rules, "add"];
  61. }
  62. console.log(config);
  63. config.proxies = ["111"];
  64. return config;
  65. }
  66. "#;
  67. let config = r#"
  68. rules:
  69. - 111
  70. - 222
  71. tun:
  72. enable: false
  73. dns:
  74. enable: false
  75. "#;
  76. let config = serde_yaml::from_str(config).unwrap();
  77. let (config, results) = use_script(script.into(), config).unwrap();
  78. let config_str = serde_yaml::to_string(&config).unwrap();
  79. println!("{config_str}");
  80. dbg!(results);
  81. }