Files
opsxapi/packages/transport/src/socketio.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

93 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Socket.IO 客户端封装(动态加载 socket.io-client)。
*/
export type SocketIoStatus = "connecting" | "open" | "closed" | "error";
export type SocketIoSession = {
emit(event: string, args: unknown[]): void;
close(): void;
};
export type SocketIoOptions = {
url: string;
/** 附加选项 JSON:{ path?, transports?, auth?, ... } */
optionsJson?: string;
/** 监听事件列表;空数组 = onAny 全收 */
listenEvents: string[];
onEvent(event: string, args: unknown[]): void;
onStatus?(s: SocketIoStatus, detail?: string): void;
onError?(msg: string): void;
};
type IoSocket = {
emit(ev: string, ...args: unknown[]): void;
on(ev: string, cb: (...args: unknown[]) => void): void;
onAny(cb: (ev: string, ...args: unknown[]) => void): void;
disconnect(): void;
};
export function connectSocketIo(opts: SocketIoOptions): SocketIoSession {
let socket: IoSocket | null = null;
let disposed = false;
void (async () => {
try {
opts.onStatus?.("connecting");
const { io } = await import("socket.io-client");
const extra: Record<string, unknown> = {};
if (opts.optionsJson?.trim()) {
try {
Object.assign(extra, JSON.parse(opts.optionsJson));
} catch {
opts.onError?.("连接选项不是合法 JSON,已忽略");
}
}
const s: IoSocket = io(opts.url, {
transports: ["websocket", "polling"],
reconnection: false,
...extra,
}) as unknown as IoSocket;
socket = s;
s.on("connect", () => opts.onStatus?.("open"));
s.on("disconnect", (...args: unknown[]) =>
opts.onStatus?.("closed", String(args[0] ?? "")),
);
s.on("connect_error", (...args: unknown[]) => {
const err = args[0];
const msg = err instanceof Error ? err.message : String(err);
opts.onError?.(msg);
opts.onStatus?.("error", msg);
});
const events = opts.listenEvents.map((e) => e.trim()).filter(Boolean);
if (events.length === 0 || events.includes("*")) {
s.onAny((ev, ...args) => opts.onEvent(ev, args));
} else {
for (const ev of events) {
s.on(ev, (...args: unknown[]) => opts.onEvent(ev, args));
}
}
if (disposed) s.disconnect();
} catch (e) {
opts.onError?.(`socket.io-client 加载/连接失败:${e instanceof Error ? e.message : String(e)}`);
opts.onStatus?.("error");
}
})();
return {
emit(event, args) {
if (!socket) {
opts.onError?.("Socket.IO 尚未连接");
return;
}
socket.emit(event, ...args);
},
close() {
disposed = true;
socket?.disconnect();
opts.onStatus?.("closed");
},
};
}