BaseSocketEventService
Tổng quan
BaseSocketEventService là lớp cơ sở dùng chung cho các service WebSocket event trên tất cả các gói backend BANA. Nó kế thừa BaseService của IGNIS và cung cấp API thống nhất để broadcast thông điệp và gửi đến các room cụ thể thông qua WebSocketEmitter của IGNIS.
Mỗi gói downstream tạo lớp con cụ thể riêng (ví dụ: SaleSocketEventService, IdentitySocketEventService) bổ sung các phương thức thông báo theo từng miền nghiệp vụ.
| Thuộc tính | Giá trị |
|---|---|
| Nguồn | packages/core/src/base/service/base-socket-event.service.ts |
| Kế thừa | BaseService (từ @venizia/ignis) |
| Phụ thuộc | BaseApplication, WebSocketEmitter |
Định nghĩa Lớp
import { BaseApplication, BaseService, WebSocketDefaults, WebSocketEmitter } from '@venizia/ignis';
export class BaseSocketEventService extends BaseService {
private _emitter: WebSocketEmitter | null = null;
private _emitterBindingKey: string;
constructor(
protected application: BaseApplication,
opts: { scope: string; emitterBindingKey: string },
) {
super({ scope: opts.scope });
this._emitterBindingKey = opts.emitterBindingKey;
}
get emitter(): WebSocketEmitter { /* lazy lookup from DI container */ }
isReady(): boolean;
async broadcast<PayloadType>(opts: { topic: string; data: PayloadType }): Promise<void>;
async sendToRoom<PayloadType>(opts: { room: string; topic: string; data: PayloadType }): Promise<void>;
}Tham số Constructor
| Tham số | Kiểu | Mô tả |
|---|---|---|
application | BaseApplication | Instance ứng dụng IGNIS (được inject qua CoreBindings.APPLICATION_INSTANCE) |
opts.scope | string | Tên scope logger, thường là ClassName.name |
opts.emitterBindingKey | string | Khóa binding DI nơi WebSocketEmitter được đăng ký |
Mẫu Emitter Lazy
WebSocketEmitter không khả dụng tại thời điểm khởi tạo vì các thành phần WebSocket bind nó trong pha binding(), chạy sau khi service được tạo. Getter sử dụng mẫu tra cứu lazy:
Mẫu này đảm bảo service hoạt động chính xác bất kể thứ tự binding DI.
API
isReady()
Kiểm tra xem WebSocketEmitter đã được bind trong DI container chưa. Sử dụng trước khi gọi broadcast() hoặc sendToRoom() để bỏ qua thông báo một cách nhẹ nhàng khi hạ tầng WebSocket không khả dụng.
isReady(): booleanTrả về: true nếu emitter đã được bind và có thể truy xuất, false trong trường hợp ngược lại.
broadcast()
Gửi thông điệp đến tất cả client WebSocket đã kết nối bằng cách xuất bản đến room mặc định (WebSocketDefaults.ROOM).
async broadcast<PayloadType = unknown>(opts: {
topic: string;
data: PayloadType;
}): Promise<void>| Tham số | Kiểu | Mô tả |
|---|---|---|
topic | string | Tên sự kiện mà client sẽ nhận được |
data | PayloadType | Dữ liệu payload cần gửi |
sendToRoom()
Gửi thông điệp đến tất cả client WebSocket trong một room cụ thể.
async sendToRoom<PayloadType = unknown>(opts: {
room: string;
topic: string;
data: PayloadType;
}): Promise<void>| Tham số | Kiểu | Mô tả |
|---|---|---|
room | string | Tên room đích |
topic | string | Tên sự kiện mà client sẽ nhận được |
data | PayloadType | Dữ liệu payload cần gửi |
Sử dụng Downstream
Sáu gói kế thừa BaseSocketEventService:
| Gói | Lớp Cụ thể | Khóa Binding |
|---|---|---|
@nx/sale | SaleSocketEventService | SaleWebSocketBindingKeys.WEBSOCKET_EMITTER |
@nx/identity | IdentitySocketEventService | Khóa riêng của Identity |
@nx/commerce | CommerceSocketEventService | Khóa riêng của Commerce |
@nx/inventory | InventorySocketEventService | Khóa riêng của Inventory |
@nx/finance | FinanceSocketEventService | Khóa riêng của Finance |
@nx/payment | PaymentSocketEventService | Khóa riêng của Payment |
Ví dụ: SaleSocketEventService
import { BaseSocketEventService, TSaleOrder } from '@nx/core';
import { SaleWebSocketRooms, SaleWebSocketTopics } from '@/common';
import { BaseApplication, CoreBindings, inject } from '@venizia/ignis';
import { SaleWebSocketBindingKeys } from './keys';
export class SaleSocketEventService extends BaseSocketEventService {
constructor(
@inject({ key: CoreBindings.APPLICATION_INSTANCE })
application: BaseApplication,
) {
super(application, {
scope: SaleSocketEventService.name,
emitterBindingKey: SaleWebSocketBindingKeys.WEBSOCKET_EMITTER,
});
}
notifyOrderUpdate(opts: { order: TSaleOrder }): void {
const { order } = opts;
if (!this.isReady()) {
this.logger.warn('Socket event service not ready | SKIP notify order WS');
return;
}
const rooms = SaleWebSocketRooms.getSaleOrderRooms({
saleOrderId: order.id,
merchantId: order.merchantId,
});
Promise.allSettled(
rooms.map(room =>
this.sendToRoom({
room,
topic: SaleWebSocketTopics.ORDER,
data: order,
}),
),
);
}
}Mẫu Đăng ký
Mỗi gói đăng ký socket event service bên trong một WebSocketComponent:
export class ApplicationWebSocketComponent extends BaseComponent {
override async binding(): Promise<void> {
const redis = RedisConnectionFactory.create({ /* ... */ });
const emitter = new WebSocketEmitter({
identifier: 'my-ws-emitter',
redisConnection: redis,
});
this.application.bind({ key: MyBindingKeys.WEBSOCKET_EMITTER }).toValue(emitter);
this.application.service(MySocketEventService);
}
}Sơ đồ Kiến trúc
Tài liệu Liên quan
- Thiết lập & Cấu hình IGNIS WebSocket -- Thành phần WebSocket, emitter và mở rộng Redis
- Tham chiếu API IGNIS WebSocket -- API WebSocketEmitter và kiến trúc
- Tham chiếu IGNIS Services -- Tài liệu lớp BaseService
- RedisConnectionFactory -- Tạo kết nối Redis cho emitter
- Gói Signal -- Dịch vụ WebSocket tập trung (sử dụng
SignalEventServiceriêng)