/** * 后端命令的封装。 * * 每个函数对应 `desktop/src-tauri/src/commands.rs` 里的一个 `#[tauri::command]`。 * Tauri 会把 JS 侧的 camelCase 参数名转成 Rust 侧的 snake_case,所以这里的参数名写成 * 前端习惯的样子即可。 * * # 错误 * * 后端的 `Err(String)` 会以 rejected promise 的形式回来,字符串就是给现场的人看的那句 * 话。`call()` 把 `unknown` 归一成 `Error`,调用方只管 `catch (err) { err.message }`。 */ import { invoke } from "@tauri-apps/api/core"; import type { ConfigView, HudView, MediaFileDto, RecordingDto, Role, Snapshot, StreamInfo, } from "./types"; /** 把后端的字符串错误变成真正的 `Error`。 */ async function call(command: string, args?: Record): Promise { try { return await invoke(command, args); } catch (raw) { throw new Error(typeof raw === "string" ? raw : String(raw)); } } export const api = { // ---- 只读 ---- streamInfo: () => call("stream_info"), snapshot: () => call("get_snapshot"), config: () => call("get_config"), mediaFiles: () => call("list_media_files"), configPath: () => call("config_path"), // ---- 密码 ---- unlock: (password: string) => call("unlock", { password }), lock: () => call("lock"), setPassword: (fresh: string, current?: string) => call("set_password", { current: current ?? null, fresh }), setDiscoveryOpen: (open: boolean) => call("set_discovery_open", { open }), // ---- 绑定与身份 ---- bindCamera: (cameraId: number | null, password?: string) => call("bind_camera", { cameraId, password: password ?? null }), bindArmor: (armorId: number | null, password?: string) => call("bind_armor", { armorId, password: password ?? null }), setTeam: (team: number, password?: string) => call("set_team", { team, password: password ?? null }), setRole: (role: Role, password?: string) => call("set_role", { role, password: password ?? null }), setMirror: (mirror: boolean) => call("set_mirror", { mirror }), saveHud: (hud: HudView) => call("save_hud", { hud }), setRefereeSlots: (slots: { cameraA: number | null; cameraB: number | null; armorA: number | null; armorB: number | null; manual: boolean; }) => call("set_referee_slots", slots), setRecordingOptions: (options: { dir: string | null; ffmpeg: string | null; crf: number | null; preset: string | null; }) => call("set_recording_options", options), // ---- 截图与录制 ---- screenshot: (camera: number) => call("screenshot", { camera }), startRecording: (cameras: number[]) => call("start_recording", { cameras }), stopRecording: (cameras: number[]) => call("stop_recording", { cameras }), reveal: (path: string) => call("reveal", { path }), // ---- 退出与重置 ---- clearConfig: (password?: string) => call("clear_config", { password: password ?? null }), quit: (password?: string) => call("quit_app", { password: password ?? null }), refresh: () => call("refresh"), };