演示

WebSocket

用 @Websocket 定义 IWebsocket 处理器,按 path 注入 WebsocketServer,向已连接客户端发送或 brocast 文本与二进制帧。

定义与注册

实现带 @Websocket 的 IWebsocket 类,并在根模块的 websocket 中注册。使用相同 path 注入 WebsocketServer 以调用 send / brocast。

  • @Websocket({ path, ssl?, pingpongInterval? }) — URL 路径;pingpongInterval 为保活间隔(ms)
  • @Module({ websocket: [ChatWebsocket] }) — 注册处理器
  • @InjectWebsocketServer("/chat-websocket") — 注入该 path 的 server(处理器 / 服务 / 控制器均可)
  • onAuthenticate — 返回 ClientInfo ({ id, … }) 接受连接,返回 null 拒绝
TSXhandler + module
1import { 2 InjectWebsocketServer, 3 Module, 4 Websocket, 5 WebsocketServer, 6} from "@quan-erp/shared-backend-core"; 7import type { 8 ClientInfo, 9 IWebsocket, 10 WebsocketClient, 11 WebsocketEvents, 12} from "@quan-erp/shared-backend-core"; 13import type { IncomingMessage } from "http"; 14import type WebSocket from "ws"; 15import metadata from "../../module.metadata.json" with { type: "json" }; 16 17@Websocket({ 18 ssl: false, 19 pingpongInterval: 1000, 20 path: "/chat-websocket", 21}) 22export class ChatWebsocket implements IWebsocket { 23 @InjectWebsocketServer("/chat-websocket") 24 websocket: WebsocketServer; 25 26 onAuthenticate(ws: WebSocket, req: IncomingMessage): ClientInfo | null { 27 return { id: "user-42" }; // null rejects the connection 28 } 29 30 on( 31 event: WebsocketEvents, 32 client: WebsocketClient, 33 data: any, 34 isBinary: boolean, 35 ) { 36 // see receive section 37 } 38 39 onUpgrade() {} 40 onDestoryed() {} 41} 42 43@Module({ 44 name: metadata.name, 45 providers: [], 46 controllers: [], 47 entities: [], 48 websocket: [ChatWebsocket], 49}) 50export class MyPluginModule {}

消息包装类

出站载荷必须实现 WebsocketMessage(getMessage())。使用内置包装类——不要向 sendText / brocast 传原始字符串。

  • WebsocketTextEventMessage(event, payload) — JSON { event, payload };应用事件优先
  • WebsocketTextMessage(data) — 纯文本 / 原始 JSON 字符串
  • WebsocketBinaryMessage(payload: Buffer) — 二进制 Buffer
TSXwrappers
1import { 2 WebsocketBinaryMessage, 3 WebsocketTextEventMessage, 4 WebsocketTextMessage, 5} from "@quan-erp/shared-backend-core"; 6 7new WebsocketTextEventMessage("kitchen", { orderId: 12 }); 8// → send/brocast as JSON: {"event":"kitchen","payload":{"orderId":12}} 9 10new WebsocketTextMessage("Hello"); 11// → plain text frame 12 13new WebsocketBinaryMessage(Buffer.from([0x01, 0x02])); 14// → binary frame

发送文本(单个客户端)

用 onAuthenticate 返回的 ClientInfo.id 作为目标。sendText 接受 WebsocketTextEventMessage 或 WebsocketTextMessage。

TSXsendText
1import { 2 InjectWebsocketServer, 3 Service, 4 WebsocketServer, 5 WebsocketTextEventMessage, 6 WebsocketTextMessage, 7} from "@quan-erp/shared-backend-core"; 8 9@Service() 10export class ChatPushService { 11 @InjectWebsocketServer("/chat-websocket") 12 private ws: WebsocketServer; 13 14 notifyUser(userId: string) { 15 this.ws.sendText( 16 userId, 17 new WebsocketTextEventMessage("inbox", { 18 title: "New message", 19 }), 20 ); 21 22 this.ws.sendText( 23 userId, 24 new WebsocketTextMessage("ping"), 25 ); 26 } 27}

发送二进制(单个客户端)

Buffer 载荷使用 sendBinary + WebsocketBinaryMessage。

TSXsendBinary
1import { 2 InjectWebsocketServer, 3 Service, 4 WebsocketBinaryMessage, 5 WebsocketServer, 6} from "@quan-erp/shared-backend-core"; 7 8@Service() 9export class FileStreamService { 10 @InjectWebsocketServer("/chat-websocket") 11 private ws: WebsocketServer; 12 13 pushChunk(clientId: string, chunk: Buffer) { 14 this.ws.sendBinary( 15 clientId, 16 new WebsocketBinaryMessage(chunk), 17 ); 18 } 19}

Brocast(全部客户端)

WebsocketServer.brocast(API 拼写为 brocast)向该 path 上每个已连接客户端发送一条 WebsocketMessage。

  • 方法名是 brocast——不是 broadcast
  • 可在控制器/服务完成业务写入后调用
  • 载荷必须是 WebsocketMessage 包装类
TSXbrocast from controller
1import { 2 Controller, 3 InjectWebsocketServer, 4 Post, 5 ResponseDto, 6 WebsocketServer, 7 WebsocketTextEventMessage, 8} from "@quan-erp/shared-backend-core"; 9 10@Controller("/order") 11export class OrderController { 12 @InjectWebsocketServer("/chat-websocket") 13 private wsServer: WebsocketServer; 14 15 @Post("/") 16 async create() { 17 // … persist order … 18 this.wsServer.brocast( 19 new WebsocketTextEventMessage("kitchen", "New Order"), 20 ); 21 return ResponseDto.ok({ ok: true }); 22 } 23}
TSXbrocast binary
1import { 2 WebsocketBinaryMessage, 3 WebsocketServer, 4} from "@quan-erp/shared-backend-core"; 5 6declare const ws: WebsocketServer; 7ws.brocast(new WebsocketBinaryMessage(Buffer.from("raw-bytes")));

向当前客户端原始发送

在 on() 内也可使用 client.getWebsocket().send(...)。按 client id 或全体广播时优先用 WebsocketServer 辅助方法。

TSXraw send
1import type { WebsocketClient } from "@quan-erp/shared-backend-core"; 2import { WebsocketTextEventMessage } from "@quan-erp/shared-backend-core"; 3 4function reply(client: WebsocketClient) { 5 client 6 .getWebsocket() 7 .send(new WebsocketTextEventMessage("ack", { ok: true }).getMessage()); 8}

接收文本与二进制

连接生命周期与帧都会调用 on(event, client, data, isBinary)。用 WebsocketMessageHandler 路由结构化文本事件({ event, payload })与通用 message/close。二进制帧不会做 JSON 事件解析。

  • isBinary === false — data 为字符串;带 event 字段的 JSON 可匹配 onTextEvent("name")
  • isBinary === true — 二进制;使用 .on("message", …)
  • onTextEvent 回调无参数——需要载荷时从 on() 闭包 data / client
  • 链式调用末尾务必 .execute()
TSXreceive
1import { 2 InjectWebsocketServer, 3 Websocket, 4 WebsocketMessageHandler, 5 WebsocketServer, 6 WebsocketTextEventMessage, 7} from "@quan-erp/shared-backend-core"; 8import type { 9 IWebsocket, 10 WebsocketClient, 11 WebsocketEvents, 12} from "@quan-erp/shared-backend-core"; 13 14@Websocket({ ssl: false, pingpongInterval: 1000, path: "/chat-websocket" }) 15export class ChatWebsocket implements IWebsocket { 16 @InjectWebsocketServer("/chat-websocket") 17 websocket: WebsocketServer; 18 19 onAuthenticate() { 20 return { id: "user-42" }; 21 } 22 23 on( 24 event: WebsocketEvents, 25 client: WebsocketClient, 26 data: any, 27 isBinary: boolean, 28 ) { 29 new WebsocketMessageHandler(event, data, isBinary) 30 .onTextEvent("chat-room", () => { 31 const parsed = JSON.parse(String(data)); 32 this.websocket.brocast( 33 new WebsocketTextEventMessage("chat-room", parsed.payload), 34 ); 35 }) 36 .on("message", () => { 37 if (isBinary) { 38 // Buffer / ArrayBuffer-like frame in data 39 return; 40 } 41 // plain text or non-event JSON 42 }) 43 .on("close", () => { 44 // client disconnected 45 }) 46 .execute(); 47 } 48 49 onUpgrade() {} 50 onDestoryed() {} 51}

查看客户端

  • getAllClients() — 该 path 上的全部 WebsocketClient
  • getByClientId(id) — 该认证 id 的 socket(数组或 null)
  • client.getClientId() / getClientData() — 来自 onAuthenticate 的身份

WebsocketServer API

  • sendText(clientId, WebsocketTextEventMessage | WebsocketTextMessage)
  • sendBinary(clientId, WebsocketBinaryMessage)
  • brocast(WebsocketMessage) — 该 path 全部客户端
  • getByClientId(clientId) / getAllClients()