2026-03-15 21:50:45 +08:00

110 lines
2.9 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.

import type { OpenClawPluginApi } from 'openclaw/plugin-sdk/core';
import WebSocket from 'ws';
import type { VoceChatAccount } from './types/index.js';
// VoceChat 消息类型定义(保留现有结构,待讨论后更新)
interface VoceChatMessage {
mid: number;
messageId: string;
fromUid: number;
fromName?: string;
channelId: number;
channelType: 'direct' | 'group';
content: string;
createdAt: number;
contentType?: 'text' | 'image' | 'file';
attachments?: Array<{
name: string;
url: string;
size: number;
}>;
}
/**
* 启动入站消息监听
*
* TODO: 当前使用 WebSocket 实现,待讨论 Webhook 方案后更新
* Webhook 方案需要:
* 1. 插件注册 HTTP 路由接收 Webhook 推送
* 2. 在 VoceChat 后台配置 Webhook URL
* 3. 处理 Webhook 的校验GET 请求返回 200
* 4. 解析 POST 推送的消息数据
*/
export async function startInbound(
api: OpenClawPluginApi,
account: VoceChatAccount,
onMessage: (message: any) => Promise<void>,
onError: (error: Error) => void
): Promise<{ stop: () => void }> {
const { serverUrl, botApiToken } = account;
const accountId = account.accountId;
if (!serverUrl || !botApiToken) {
throw new Error('VoceChat: serverUrl and botApiToken are required');
}
// 注意:当前使用 WebSocket 连接,后续应改为 Webhook
const wsUrl = serverUrl.replace(/^http/, 'ws') + '/ws';
api.logger.info(`VoceChat [${accountId}]: Connecting to ${wsUrl}`);
api.logger.warn(`VoceChat [${accountId}]: 当前使用 WebSocket建议迁移到 Webhook 方案`);
const ws = new WebSocket(wsUrl, {
headers: {
'Authorization': `Bearer ${botApiToken}`,
},
});
ws.on('open', () => {
api.logger.info(`VoceChat [${accountId}]: WebSocket connected`);
});
ws.on('message', async (data: WebSocket.Data) => {
try {
const event = JSON.parse(data.toString());
// 只处理消息事件
if (event.type !== 'message' || !event.data) {
return;
}
const msg: VoceChatMessage = event.data;
// 转换为 OpenClaw 标准消息格式
const message = {
id: msg.messageId || String(msg.mid),
text: msg.content,
sender: {
id: String(msg.fromUid),
name: msg.fromName || `User-${msg.fromUid}`,
},
chat: {
id: String(msg.channelId),
type: msg.channelType,
},
timestamp: msg.createdAt,
attachments: msg.attachments,
};
await onMessage(message);
} catch (err) {
api.logger.error('VoceChat: Failed to process message\n' + err);
}
});
ws.on('error', (err) => {
api.logger.error(`VoceChat [${accountId}]: WebSocket error\n` + err);
onError(err);
});
ws.on('close', () => {
api.logger.info(`VoceChat [${accountId}]: WebSocket closed`);
});
return {
stop: () => {
ws.close();
},
};
}