定义与注册
实现带 @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()