Files
opsxapi/packages/transport/src/tauriNative.ts
T
logan dec66db5aa feat: OpsxAPI v1.0 全协议接口工作台
- 六协议调试:HTTP/GraphQL/WebSocket/SSE/Socket.IO/MQTT
- 集合树/多标签/多环境变量/历史记录,localStorage 持久化
- 导入:OpenAPI 2/3/3.1、Postman、Apifox、Apipost、cURL、HAR、
  Insomnia、Hoppscotch、Markdown(自动识别,21 个单测覆盖)
- 导出:OpenAPI 3.0 JSON/YAML、Postman v2.1、Markdown 文档、
  全量备份;单请求生成 cURL/fetch/Python/Go 代码
- Gin 服务:HTTP 代理、NDJSON 流式代理(SSE 透传)、
  WebSocket 隧道(浏览器自定义握手 Header)
- 内置产品官网 /home 与用户文档站 /docs(SSR,随二进制交付)
- lucide 图标体系 + 品牌标识(Logo/favicon),明暗双主题
- 环境变量:彩色徽标切换器、管理弹窗、{{ 自动补全
2026-09-18 00:16:59 +08:00

69 lines
2.0 KiB
TypeScript

import type { HttpResult, HttpSpec, Transport, WsSession, WsSpec } from "@opsxapi/core";
async function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
try {
const { invoke: tauriInvoke } = await import("@tauri-apps/api/core");
return await tauriInvoke<T>(cmd, args);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
throw new Error(
`tauri-native invoke("${cmd}") failed (are you running inside OpsxAPI desktop?): ${msg}`,
);
}
}
export const tauriNativeTransport: Transport = {
async http(spec: HttpSpec): Promise<HttpResult> {
return invoke<HttpResult>("http_send", { spec });
},
ws(spec: WsSpec): WsSession {
const messageCbs: Array<(data: string) => void> = [];
const statusCbs: Array<(s: string) => void> = [];
let sessionId: string | null = null;
const emitStatus = (s: string) => statusCbs.forEach((cb) => cb(s));
void (async () => {
try {
emitStatus("connecting");
sessionId = await invoke<string>("ws_connect", { spec });
emitStatus("open");
// Full event listen pipeline is Week 2; stub keeps UI usable.
} catch (e) {
emitStatus("error");
messageCbs.forEach((cb) =>
cb(`[ws_connect error] ${e instanceof Error ? e.message : String(e)}`),
);
}
})();
return {
onMessage(cb) {
messageCbs.push(cb);
},
onStatus(cb) {
statusCbs.push(cb);
},
send(data) {
if (!sessionId) {
messageCbs.forEach((cb) => cb("[ws] not connected"));
return;
}
void invoke("ws_send", { sessionId, data }).catch((e) => {
messageCbs.forEach((cb) =>
cb(`[ws_send error] ${e instanceof Error ? e.message : String(e)}`),
);
});
},
close() {
if (!sessionId) return;
void invoke("ws_close", { sessionId }).finally(() => {
sessionId = null;
emitStatus("closed");
});
},
};
},
};