This commit is contained in:
fengchuanhn@gmail.com
2026-05-16 11:24:18 +08:00
parent 491231bdd5
commit c88b2d0f3d
17 changed files with 2401 additions and 16 deletions

View File

@@ -0,0 +1 @@
pub mod quickjs;

View File

@@ -0,0 +1,99 @@
//! Generic Tauri commands for invoking any JS script registered in the
//! embedded QuickJS runtime. Replaces the per-pipeline command so adding a
//! new flow only requires:
//!
//! 1. Drop a new `.js` file into `src-tauri/js/`.
//! 2. Add it to `js_runtime::SCRIPT_FILES`.
//! 3. Inside the JS file, register one or more entries on
//! `globalThis.__scripts[<scriptName>]`.
//!
//! Frontend usage:
//!
//! ```ts
//! import { invoke } from "@tauri-apps/api/core";
//! import { listen } from "@tauri-apps/api/event";
//!
//! const off = await listen("quickjs:event", (e) => console.log(e.payload));
//! const result = await invoke("run_quickjs_script", {
//! scriptName: "process_douyin_share",
//! params: { shareText: "...", modelConfig: {...}, ... },
//! });
//! off();
//! ```
use serde::Serialize;
use serde_json::Value;
use tauri::{AppHandle, Emitter, Window};
use tokio::sync::mpsc;
use crate::js_runtime::{self, PipelineEvent};
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum FrontendEvent {
Progress {
#[serde(rename = "scriptName")]
script_name: String,
status: String,
},
Log {
#[serde(rename = "scriptName")]
script_name: String,
level: String,
msg: String,
#[serde(skip_serializing_if = "Option::is_none")]
fields: Option<Value>,
},
}
const EVENT_NAME: &str = "quickjs:event";
/// Run an arbitrary registered QuickJS script by name.
///
/// `script_name` must already be registered on `globalThis.__scripts` by
/// one of the bundled `js/*.js` files. `params` is forwarded as-is to the
/// script entry function.
#[tauri::command]
pub async fn run_quickjs_script(
app: AppHandle,
window: Window,
script_name: String,
params: Value,
) -> Result<Value, String> {
let (tx, mut rx) = mpsc::unbounded_channel::<PipelineEvent>();
// Forward script events to the frontend window.
let app_for_emit = app.clone();
let win_label = window.label().to_string();
let script_for_emit = script_name.clone();
let pump = tokio::spawn(async move {
while let Some(ev) = rx.recv().await {
let payload: FrontendEvent = match ev {
PipelineEvent::Progress(s) => FrontendEvent::Progress {
script_name: script_for_emit.clone(),
status: s,
},
PipelineEvent::Log { level, msg, fields } => FrontendEvent::Log {
script_name: script_for_emit.clone(),
level,
msg,
fields,
},
};
let _ = app_for_emit.emit_to(&win_label, EVENT_NAME, payload);
}
});
let result = js_runtime::run_script(script_name, params, tx)
.await
.map_err(|e| e.to_string())?;
pump.await.ok();
Ok(result)
}
/// Diagnostic helper — returns the list of registered script names.
#[tauri::command]
pub async fn list_quickjs_scripts() -> Result<Vec<String>, String> {
js_runtime::list_scripts().await.map_err(|e| e.to_string())
}