From 871c9a6d1ed014c93da2436a437df03734e9f76c Mon Sep 17 00:00:00 2001
From: MystiPanda <mystipanda@proton.me>
Date: Sun, 10 Dec 2023 19:47:45 +0800
Subject: [PATCH] feat: Support windows aarch64

---
 .gitmodules                     |   3 +
 src-tauri/Cargo.toml            |   2 +-
 src-tauri/quick-rs              |   1 +
 src-tauri/src/enhance/script.rs | 130 +++++++++++++++++++-------------
 4 files changed, 81 insertions(+), 55 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 src-tauri/quick-rs

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..2eda7e4
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src-tauri/quick-rs"]
+	path = src-tauri/quick-rs
+	url = https://github.com/clash-verge-rev/quick-rs.git
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 2f1a3be..d67f6ed 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -25,7 +25,6 @@ log4rs = "1"
 nanoid = "0.4"
 chrono = "0.4"
 sysinfo = "0.30"
-rquickjs = "0.3" # 高版本不支持 Linux aarch64
 serde_json = "1.0"
 serde_yaml = "0.9"
 once_cell = "1.18"
@@ -33,6 +32,7 @@ port_scanner = "0.1.5"
 delay_timer = "0.11.5"
 parking_lot = "0.12"
 percent-encoding = "2.3.1"
+quick-rs = { path = "quick-rs" }
 window-shadows = { version = "0.2" }
 tokio = { version = "1", features = ["full"] }
 serde = { version = "1.0", features = ["derive"] }
diff --git a/src-tauri/quick-rs b/src-tauri/quick-rs
new file mode 160000
index 0000000..78277c4
--- /dev/null
+++ b/src-tauri/quick-rs
@@ -0,0 +1 @@
+Subproject commit 78277c4509c64f18c0fc5c9f2b84671de7c83343
diff --git a/src-tauri/src/enhance/script.rs b/src-tauri/src/enhance/script.rs
index 30a922f..d47dc33 100644
--- a/src-tauri/src/enhance/script.rs
+++ b/src-tauri/src/enhance/script.rs
@@ -3,61 +3,83 @@ use anyhow::Result;
 use serde_yaml::Mapping;
 
 pub fn use_script(script: String, config: Mapping) -> Result<(Mapping, Vec<(String, String)>)> {
-    use rquickjs::{function::Func, Context, Runtime};
-    use std::sync::{Arc, Mutex};
-
-    let runtime = Runtime::new().unwrap();
-    let context = Context::full(&runtime).unwrap();
-    let outputs = Arc::new(Mutex::new(vec![]));
-
-    let copy_outputs = outputs.clone();
-    let result = context.with(|ctx| -> Result<Mapping> {
-        ctx.globals().set(
-            "__verge_log__",
-            Func::from(move |level: String, data: String| {
-                let mut out = copy_outputs.lock().unwrap();
-                out.push((level, data));
-            }),
-        )?;
-
-        ctx.eval(
-            r#"var console = Object.freeze({
-        log(data){__verge_log__("log",JSON.stringify(data))}, 
-        info(data){__verge_log__("info",JSON.stringify(data))}, 
-        error(data){__verge_log__("error",JSON.stringify(data))},
-        debug(data){__verge_log__("debug",JSON.stringify(data))},
-      });"#,
-        )?;
-
-        let config = use_lowercase(config.clone());
-        let config_str = serde_json::to_string(&config)?;
-
-        let code = format!(
-            r#"try{{
+    use quick_rs::{context::Context, function::Function, module::Module, runtime::Runtime};
+
+    let config = use_lowercase(config.clone());
+    let config_str = serde_json::to_string(&config)?;
+
+    let runtime = Runtime::new();
+    let context = Context::from(&runtime);
+
+    let code = format!(
+        r#"
+        let output = [];
+
+        function __verge_log__(type, data) {{
+          output.push([type, data]);
+        }}
+
+        var console = Object.freeze({{
+          log(data) {{ __verge_log__("log", JSON.stringify(data)) }},
+          info(data) {{ __verge_log__("info", JSON.stringify(data)) }},
+          error(data) {{ __verge_log__("error", JSON.stringify(data)) }},
+          debug(data) {{ __verge_log__("debug", JSON.stringify(data)) }},
+        }});
+
         {script};
-        JSON.stringify(main({config_str})||'')
-      }} catch(err) {{
-        `__error_flag__ ${{err.toString()}}`
-      }}"#
-        );
-        let result: String = ctx.eval(code.as_str())?;
-        if result.starts_with("__error_flag__") {
-            anyhow::bail!(result[15..].to_owned());
-        }
-        if result == "\"\"" {
-            anyhow::bail!("main function should return object");
-        }
-        Ok(serde_json::from_str::<Mapping>(result.as_str())?)
-    });
-
-    let mut out = outputs.lock().unwrap();
-    match result {
-        Ok(config) => Ok((use_lowercase(config), out.to_vec())),
-        Err(err) => {
-            out.push(("exception".into(), err.to_string()));
-            Ok((config, out.to_vec()))
-        }
-    }
+
+        export function _main(){{
+          try{{
+            let result = JSON.stringify(main({config_str})||"");
+            return JSON.stringify({{result, output}});
+          }} catch(err) {{
+            output.push(["exception", err.toString()]);
+            return JSON.stringify({{result: "__error__", output}});
+          }}
+        }}
+        "#
+    );
+    let value = context.eval_module(&code, "_main")?;
+    let module = Module::new(value)?;
+    let value = module.get("_main")?;
+    let function = Function::new(value)?;
+    let value = function.call(vec![])?;
+    let result = serde_json::from_str::<serde_json::Value>(&value.to_string()?)?;
+    result
+        .as_object()
+        .map(|obj| {
+            let result = obj.get("result").unwrap().as_str().unwrap();
+            let output = obj.get("output").unwrap();
+
+            let mut out = output
+                .as_array()
+                .unwrap()
+                .iter()
+                .map(|item| {
+                    let item = item.as_array().unwrap();
+                    (
+                        item[0].as_str().unwrap().into(),
+                        item[1].as_str().unwrap().into(),
+                    )
+                })
+                .collect::<Vec<_>>();
+            if result.is_empty() {
+                anyhow::bail!("main function should return object");
+            }
+            if result == "__error__" {
+                return Ok((config, out.to_vec()));
+            }
+            let result = serde_json::from_str::<Mapping>(result);
+
+            match result {
+                Ok(config) => Ok((use_lowercase(config), out.to_vec())),
+                Err(err) => {
+                    out.push(("exception".into(), err.to_string()));
+                    Ok((config, out.to_vec()))
+                }
+            }
+        })
+        .unwrap_or_else(|| anyhow::bail!("Unknown result"))
 }
 
 #[test]
-- 
2.43.0.windows.1