@xmobitea/gn-server
Version:
GearN Server by XmobiTea (Pro)
176 lines (130 loc) • 5.72 kB
Markdown
File này chỉ tập trung vào `socket` trong cloud script.
Nếu bạn cần tài liệu tổng quan cloud script, xem:
- [CLOUDSCRIPT_USAGE.md](../CLOUDSCRIPT_USAGE.md)
Dùng `socket` khi:
- Bạn cần gửi realtime event cho một user.
- Bạn cần gửi realtime event cho nhiều user hoặc toàn bộ player online.
- Bạn cần join room, leave room, hoặc broadcast vào room.
Không nên dùng `socket` khi:
- Người nhận có thể offline và bạn cần cách báo tin bền hơn. Trường hợp đó cân nhắc `pushNotification` hoặc lưu DB.
- Bạn cần response business detail từ client. `socket` trong cloud script chỉ là server-side bridge.
- Bạn chỉ cần xử lý DB nội bộ. Trường hợp đó dùng `database`.
Đọc theo thứ tự này:
1. [CloudScriptSocket.ts](../src/GN-startup/cloudScript/CloudScriptSocket.ts)
Wrapper `socket` đang expose:
- `socket.sendEventTo(userId, operationEvent)`
- `socket.sendEventToMoreUser(userIds, operationEvent)`
- `socket.sendEventToAllPlayer(operationEvent)`
- `socket.joinRoom(userId, roomId)`
- `socket.leaveRoom(userId, roomId)`
- `socket.sendEventToRoom(roomId, operationEvent)`
- Đây là fire-and-forget side effect.
- `await` ở đây chỉ chờ event bridge phía server, không phải client ACK.
- Payload event nên giữ gọn.
- Dữ liệu event nên là JSON plain hoặc `GNHashtable`.
- `log` là tham số thứ 3 của handler, không phải global logger hoặc `console.log`.
- Không bắt buộc gọi `log` trong mỗi function. Chỉ dùng khi cần debug số liệu, trace luồng đi, hoặc kiểm tra payload tạm thời.
- Runtime lưu `log(value)` bằng `JSON.stringify(value)` và trả về caller qua `functionLogs` dưới dạng mảng string.
- Chỉ log dữ liệu JSON-safe. Không dùng `functionLogs` để xác nhận client đã nhận event.
```ts
const requireString = (value: unknown, fieldName: string): string => {
if (typeof value !== "string" || value.trim().length === 0) {
throw new Error(fieldName + " is required");
}
return value.trim();
};
const createDemoOperationEvent = (message: string, userId: string) => {
return new OperationEvent(
"cloudScriptDemo",
GNHashtable.builder()
.add("message", message)
.add("sourceUserId", userId)
.add("ts", Date.now())
.build()
);
};
handlers["socketNotifyUser"] = async (args: any, context, log) => {
const targetUserId = typeof args?.userId === "string" && args.userId.length > 0 ? args.userId : context.userId;
const operationEvent = createDemoOperationEvent("Hello from cloud script", context.userId);
await socket.sendEventTo(targetUserId, operationEvent);
return {
sent: true,
targetUserId: targetUserId
};
};
```
```ts
const requireString = (value: unknown, fieldName: string): string => {
if (typeof value !== "string" || value.trim().length === 0) {
throw new Error(fieldName + " is required");
}
return value.trim();
};
const createDemoOperationEvent = (eventCode: string, payload: { [k: string]: any }) => {
return new OperationEvent(
eventCode,
GNHashtable.builder().addAll(payload).build()
);
};
handlers["socketNotifyManyUsers"] = async (args: any, context, log) => {
if (!Array.isArray(args?.userIds) || args.userIds.length === 0) {
throw new Error("userIds is required");
}
const operationEvent = createDemoOperationEvent("cloudScriptMultiCast", {
sourceUserId: context.userId,
ts: Date.now()
});
await socket.sendEventToMoreUser(args.userIds, operationEvent);
return {
sent: true,
count: args.userIds.length
};
};
handlers["socketBroadcastAll"] = async (args: any, context, log) => {
const operationEvent = createDemoOperationEvent("cloudScriptBroadcast", {
message: typeof args?.message === "string" ? args.message : "Broadcast from cloud script",
sourceUserId: context.userId,
ts: Date.now()
});
await socket.sendEventToAllPlayer(operationEvent);
return {
broadcasted: true
};
};
handlers["socketRoomWorkflow"] = async (args: any, context, log) => {
const userId = typeof args?.userId === "string" && args.userId.length > 0 ? args.userId : context.userId;
const roomId = requireString(args?.roomId, "roomId");
const mode = typeof args?.mode === "string" ? args.mode : "joinAndSend";
if (mode === "leave") {
await socket.leaveRoom(userId, roomId);
return {
left: true,
userId: userId,
roomId: roomId
};
}
await socket.joinRoom(userId, roomId);
const operationEvent = createDemoOperationEvent("cloudScriptRoomMessage", {
roomId: roomId,
sourceUserId: context.userId,
ts: Date.now()
});
await socket.sendEventToRoom(roomId, operationEvent);
return {
joined: true,
roomId: roomId,
userId: userId
};
};
```
Nếu bạn cần realtime cho client đang online, dùng `socket`.
Nếu bạn cần delivery bền hơn khi client offline, `socket` không đủ. Khi đó cân nhắc `pushNotification` hoặc ghi trạng thái vào DB.