@roomkit/worker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +122 -0
  2. package/dist/src/admin/admin.controller.d.ts +275 -0
  3. package/dist/src/admin/admin.controller.d.ts.map +1 -0
  4. package/dist/src/admin/admin.controller.js +296 -0
  5. package/dist/src/admin/admin.controller.js.map +1 -0
  6. package/dist/src/admin/admin.module.d.ts +3 -0
  7. package/dist/src/admin/admin.module.d.ts.map +1 -0
  8. package/dist/src/admin/admin.module.js +35 -0
  9. package/dist/src/admin/admin.module.js.map +1 -0
  10. package/dist/src/admin/admin.service.d.ts +282 -0
  11. package/dist/src/admin/admin.service.d.ts.map +1 -0
  12. package/dist/src/admin/admin.service.js +508 -0
  13. package/dist/src/admin/admin.service.js.map +1 -0
  14. package/dist/src/auth/auth.module.d.ts +10 -0
  15. package/dist/src/auth/auth.module.d.ts.map +1 -0
  16. package/dist/src/auth/auth.module.js +37 -0
  17. package/dist/src/auth/auth.module.js.map +1 -0
  18. package/dist/src/auth/auth.service.d.ts +21 -0
  19. package/dist/src/auth/auth.service.d.ts.map +1 -0
  20. package/dist/src/auth/auth.service.js +69 -0
  21. package/dist/src/auth/auth.service.js.map +1 -0
  22. package/dist/src/circuit-breaker/circuit-breaker.module.d.ts +3 -0
  23. package/dist/src/circuit-breaker/circuit-breaker.module.d.ts.map +1 -0
  24. package/dist/src/circuit-breaker/circuit-breaker.module.js +24 -0
  25. package/dist/src/circuit-breaker/circuit-breaker.module.js.map +1 -0
  26. package/dist/src/circuit-breaker/circuit-breaker.service.d.ts +89 -0
  27. package/dist/src/circuit-breaker/circuit-breaker.service.d.ts.map +1 -0
  28. package/dist/src/circuit-breaker/circuit-breaker.service.js +207 -0
  29. package/dist/src/circuit-breaker/circuit-breaker.service.js.map +1 -0
  30. package/dist/src/config/config.module.d.ts +3 -0
  31. package/dist/src/config/config.module.d.ts.map +1 -0
  32. package/dist/src/config/config.module.js +22 -0
  33. package/dist/src/config/config.module.js.map +1 -0
  34. package/dist/src/config/config.service.d.ts +19 -0
  35. package/dist/src/config/config.service.d.ts.map +1 -0
  36. package/dist/src/config/config.service.js +58 -0
  37. package/dist/src/config/config.service.js.map +1 -0
  38. package/dist/src/config/worker.config.d.ts +82 -0
  39. package/dist/src/config/worker.config.d.ts.map +1 -0
  40. package/dist/src/config/worker.config.js +35 -0
  41. package/dist/src/config/worker.config.js.map +1 -0
  42. package/dist/src/index.d.ts +48 -0
  43. package/dist/src/index.d.ts.map +1 -0
  44. package/dist/src/index.js +108 -0
  45. package/dist/src/index.js.map +1 -0
  46. package/dist/src/lifecycle/graceful-shutdown.service.d.ts +71 -0
  47. package/dist/src/lifecycle/graceful-shutdown.service.d.ts.map +1 -0
  48. package/dist/src/lifecycle/graceful-shutdown.service.js +221 -0
  49. package/dist/src/lifecycle/graceful-shutdown.service.js.map +1 -0
  50. package/dist/src/lifecycle/index.d.ts +2 -0
  51. package/dist/src/lifecycle/index.d.ts.map +1 -0
  52. package/dist/src/lifecycle/index.js +18 -0
  53. package/dist/src/lifecycle/index.js.map +1 -0
  54. package/dist/src/main.d.ts +2 -0
  55. package/dist/src/main.d.ts.map +1 -0
  56. package/dist/src/main.js +54 -0
  57. package/dist/src/main.js.map +1 -0
  58. package/dist/src/metrics/metrics.controller.d.ts +15 -0
  59. package/dist/src/metrics/metrics.controller.d.ts.map +1 -0
  60. package/dist/src/metrics/metrics.controller.js +44 -0
  61. package/dist/src/metrics/metrics.controller.js.map +1 -0
  62. package/dist/src/metrics/metrics.module.d.ts +7 -0
  63. package/dist/src/metrics/metrics.module.d.ts.map +1 -0
  64. package/dist/src/metrics/metrics.module.js +28 -0
  65. package/dist/src/metrics/metrics.module.js.map +1 -0
  66. package/dist/src/metrics/metrics.service.d.ts +65 -0
  67. package/dist/src/metrics/metrics.service.d.ts.map +1 -0
  68. package/dist/src/metrics/metrics.service.js +306 -0
  69. package/dist/src/metrics/metrics.service.js.map +1 -0
  70. package/dist/src/migration/migration.module.d.ts +3 -0
  71. package/dist/src/migration/migration.module.d.ts.map +1 -0
  72. package/dist/src/migration/migration.module.js +30 -0
  73. package/dist/src/migration/migration.module.js.map +1 -0
  74. package/dist/src/migration/migration.service.d.ts +68 -0
  75. package/dist/src/migration/migration.service.d.ts.map +1 -0
  76. package/dist/src/migration/migration.service.js +295 -0
  77. package/dist/src/migration/migration.service.js.map +1 -0
  78. package/dist/src/migration/room-migration.service.d.ts +92 -0
  79. package/dist/src/migration/room-migration.service.d.ts.map +1 -0
  80. package/dist/src/migration/room-migration.service.js +297 -0
  81. package/dist/src/migration/room-migration.service.js.map +1 -0
  82. package/dist/src/redis/redis.module.d.ts +3 -0
  83. package/dist/src/redis/redis.module.d.ts.map +1 -0
  84. package/dist/src/redis/redis.module.js +22 -0
  85. package/dist/src/redis/redis.module.js.map +1 -0
  86. package/dist/src/redis/redis.service.d.ts +68 -0
  87. package/dist/src/redis/redis.service.d.ts.map +1 -0
  88. package/dist/src/redis/redis.service.js +260 -0
  89. package/dist/src/redis/redis.service.js.map +1 -0
  90. package/dist/src/room/client-proxy.d.ts +43 -0
  91. package/dist/src/room/client-proxy.d.ts.map +1 -0
  92. package/dist/src/room/client-proxy.js +91 -0
  93. package/dist/src/room/client-proxy.js.map +1 -0
  94. package/dist/src/room/game-room.d.ts +243 -0
  95. package/dist/src/room/game-room.d.ts.map +1 -0
  96. package/dist/src/room/game-room.js +434 -0
  97. package/dist/src/room/game-room.js.map +1 -0
  98. package/dist/src/room/message-handler.service.d.ts +70 -0
  99. package/dist/src/room/message-handler.service.d.ts.map +1 -0
  100. package/dist/src/room/message-handler.service.js +541 -0
  101. package/dist/src/room/message-handler.service.js.map +1 -0
  102. package/dist/src/room/room-manager.service.d.ts +132 -0
  103. package/dist/src/room/room-manager.service.d.ts.map +1 -0
  104. package/dist/src/room/room-manager.service.js +571 -0
  105. package/dist/src/room/room-manager.service.js.map +1 -0
  106. package/dist/src/room/room-persistence.service.d.ts +101 -0
  107. package/dist/src/room/room-persistence.service.d.ts.map +1 -0
  108. package/dist/src/room/room-persistence.service.js +307 -0
  109. package/dist/src/room/room-persistence.service.js.map +1 -0
  110. package/dist/src/room/room-registry.service.d.ts +16 -0
  111. package/dist/src/room/room-registry.service.d.ts.map +1 -0
  112. package/dist/src/room/room-registry.service.js +60 -0
  113. package/dist/src/room/room-registry.service.js.map +1 -0
  114. package/dist/src/room/room.module.d.ts +15 -0
  115. package/dist/src/room/room.module.d.ts.map +1 -0
  116. package/dist/src/room/room.module.js +55 -0
  117. package/dist/src/room/room.module.js.map +1 -0
  118. package/dist/src/room/rooms/echo-room.d.ts +18 -0
  119. package/dist/src/room/rooms/echo-room.d.ts.map +1 -0
  120. package/dist/src/room/rooms/echo-room.js +85 -0
  121. package/dist/src/room/rooms/echo-room.js.map +1 -0
  122. package/dist/src/room/rooms/index.d.ts +2 -0
  123. package/dist/src/room/rooms/index.d.ts.map +1 -0
  124. package/dist/src/room/rooms/index.js +6 -0
  125. package/dist/src/room/rooms/index.js.map +1 -0
  126. package/dist/src/worker.module.d.ts +10 -0
  127. package/dist/src/worker.module.d.ts.map +1 -0
  128. package/dist/src/worker.module.js +46 -0
  129. package/dist/src/worker.module.js.map +1 -0
  130. package/dist/test/circuit-breaker/circuit-breaker.service.spec.d.ts +2 -0
  131. package/dist/test/circuit-breaker/circuit-breaker.service.spec.d.ts.map +1 -0
  132. package/dist/test/circuit-breaker/circuit-breaker.service.spec.js +220 -0
  133. package/dist/test/circuit-breaker/circuit-breaker.service.spec.js.map +1 -0
  134. package/dist/test/integration/admin-api.spec.d.ts +2 -0
  135. package/dist/test/integration/admin-api.spec.d.ts.map +1 -0
  136. package/dist/test/integration/admin-api.spec.js +246 -0
  137. package/dist/test/integration/admin-api.spec.js.map +1 -0
  138. package/dist/test/migration/game-room-migration.spec.d.ts +2 -0
  139. package/dist/test/migration/game-room-migration.spec.d.ts.map +1 -0
  140. package/dist/test/migration/game-room-migration.spec.js +222 -0
  141. package/dist/test/migration/game-room-migration.spec.js.map +1 -0
  142. package/dist/test/room/client-proxy.spec.d.ts +2 -0
  143. package/dist/test/room/client-proxy.spec.d.ts.map +1 -0
  144. package/dist/test/room/client-proxy.spec.js +117 -0
  145. package/dist/test/room/client-proxy.spec.js.map +1 -0
  146. package/dist/test/room/game-room.spec.d.ts +2 -0
  147. package/dist/test/room/game-room.spec.d.ts.map +1 -0
  148. package/dist/test/room/game-room.spec.js +219 -0
  149. package/dist/test/room/game-room.spec.js.map +1 -0
  150. package/dist/test/room/room-manager.service.spec.d.ts +2 -0
  151. package/dist/test/room/room-manager.service.spec.d.ts.map +1 -0
  152. package/dist/test/room/room-manager.service.spec.js +280 -0
  153. package/dist/test/room/room-manager.service.spec.js.map +1 -0
  154. package/dist/test/setup.d.ts +2 -0
  155. package/dist/test/setup.d.ts.map +1 -0
  156. package/dist/test/setup.js +56 -0
  157. package/dist/test/setup.js.map +1 -0
  158. package/package.json +74 -0
@@ -0,0 +1,541 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var MessageHandlerService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.MessageHandlerService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const core_1 = require("@roomkit/core");
16
+ const redis_service_1 = require("../redis/redis.service");
17
+ const config_service_1 = require("../config/config.service");
18
+ const room_manager_service_1 = require("./room-manager.service");
19
+ const auth_service_1 = require("../auth/auth.service");
20
+ const client_proxy_1 = require("./client-proxy");
21
+ const circuit_breaker_service_1 = require("../circuit-breaker/circuit-breaker.service");
22
+ const uuid_1 = require("uuid");
23
+ let MessageHandlerService = MessageHandlerService_1 = class MessageHandlerService {
24
+ redis;
25
+ config;
26
+ roomManager;
27
+ authService;
28
+ circuitBreaker;
29
+ logger = new common_1.Logger(MessageHandlerService_1.name);
30
+ workerId;
31
+ constructor(redis, config, roomManager, authService, circuitBreaker) {
32
+ this.redis = redis;
33
+ this.config = config;
34
+ this.roomManager = roomManager;
35
+ this.authService = authService;
36
+ this.circuitBreaker = circuitBreaker;
37
+ this.workerId = config.workerId;
38
+ }
39
+ async onModuleInit() {
40
+ const channel = core_1.RedisChannels.rpcWorker(this.workerId);
41
+ await this.redis.subscribe(channel, this.handleMessage.bind(this));
42
+ this.logger.log(`Subscribed to channel: ${channel}`);
43
+ }
44
+ async handleMessage(rawMessage) {
45
+ try {
46
+ const msg = JSON.parse(rawMessage);
47
+ this.logger.debug(`Received message type=${msg.type} msgType=${msg.msgType} from gateway ${msg.gatewayId}`);
48
+ // 检查熔断器状态
49
+ const canProcess = this.circuitBreaker.canProcess();
50
+ if (!canProcess.allowed) {
51
+ this.logger.warn(`Circuit breaker rejected request: ${canProcess.reason}`);
52
+ await this.sendErrorResponse(msg, canProcess.reason);
53
+ return;
54
+ }
55
+ this.circuitBreaker.startRequest();
56
+ try {
57
+ switch (msg.type) {
58
+ case 'auth':
59
+ await this.handleAuthRequest(msg);
60
+ break;
61
+ case 'client-message':
62
+ await this.handleClientMessage(msg);
63
+ break;
64
+ case 'client-disconnect':
65
+ await this.handleClientDisconnect(msg);
66
+ break;
67
+ case 'reconnect-room':
68
+ await this.handleReconnectRoom(msg);
69
+ break;
70
+ default:
71
+ this.logger.warn(`Unknown message type: ${msg.type}`);
72
+ }
73
+ this.circuitBreaker.onSuccess();
74
+ }
75
+ catch (innerError) {
76
+ this.circuitBreaker.onFailure(innerError);
77
+ throw innerError;
78
+ }
79
+ }
80
+ catch (error) {
81
+ this.logger.error(`Failed to handle message: ${error}`);
82
+ }
83
+ }
84
+ /**
85
+ * 发送错误响应(熔断时使用)
86
+ */
87
+ async sendErrorResponse(msg, error) {
88
+ const response = {
89
+ type: 'client-response',
90
+ workerId: this.workerId,
91
+ connectionId: msg.connectionId,
92
+ msgType: core_1.MessageType.MSG_ERROR,
93
+ payload: { success: false, error },
94
+ timestamp: Date.now(),
95
+ };
96
+ await this.sendToGateway(msg.gatewayId, response);
97
+ }
98
+ async handleAuthRequest(msg) {
99
+ const { token } = msg.payload;
100
+ const result = await this.authService.verifyToken(token);
101
+ const response = {
102
+ type: 'auth-response',
103
+ requestId: msg.requestId,
104
+ workerId: this.workerId,
105
+ connectionId: msg.connectionId,
106
+ success: result.valid,
107
+ userId: result.userId,
108
+ error: result.error,
109
+ timestamp: Date.now(),
110
+ };
111
+ await this.sendToGateway(msg.gatewayId, response);
112
+ }
113
+ async handleClientMessage(msg) {
114
+ const userId = msg.userId;
115
+ const roomId = msg.roomId;
116
+ const msgType = msg.msgType;
117
+ // 根据 msgType 路由到不同处理逻辑
118
+ switch (msgType) {
119
+ case core_1.MessageType.MSG_ROOM_CREATE:
120
+ await this.handleCreateRoom(msg, userId);
121
+ break;
122
+ case core_1.MessageType.MSG_ROOM_JOIN:
123
+ await this.handleJoinRoom(msg, userId);
124
+ break;
125
+ case core_1.MessageType.MSG_ROOM_JOIN_OR_CREATE:
126
+ await this.handleJoinOrCreate(msg, userId);
127
+ break;
128
+ case core_1.MessageType.MSG_ROOM_LEAVE:
129
+ await this.handleLeaveRoom(msg, userId, roomId);
130
+ break;
131
+ default:
132
+ // 其他消息类型(游戏自定义消息)
133
+ if (msgType && roomId) {
134
+ await this.handleRoomMessage(msg, userId, roomId);
135
+ }
136
+ else if (msgType) {
137
+ this.logger.warn(`Message ${msgType} received without roomId`);
138
+ }
139
+ else {
140
+ this.logger.warn(`Message received without msgType`);
141
+ }
142
+ }
143
+ }
144
+ async handleCreateRoom(msg, userId) {
145
+ const { roomId, gameType, maxPlayers = 10, config = {} } = msg.payload;
146
+ // 创建 ClientProxy
147
+ const client = new client_proxy_1.ClientProxy(userId, msg.connectionId, msg.gatewayId, this.redis, this.workerId);
148
+ // 使用 Gateway 传来的 roomId,如果没有则生成新的
149
+ const actualRoomId = roomId || `room_${(0, uuid_1.v4)()}`;
150
+ const room = await this.roomManager.createRoom(actualRoomId, gameType, maxPlayers, config, client);
151
+ if (room) {
152
+ // 创建者加入房间
153
+ await this.roomManager.joinRoom(room, client, config);
154
+ const response = {
155
+ type: 'client-response',
156
+ requestId: msg.requestId,
157
+ workerId: this.workerId,
158
+ connectionId: msg.connectionId,
159
+ msgType: core_1.MessageType.MSG_ROOM_CREATE_OK,
160
+ payload: { roomId: actualRoomId, gameType },
161
+ timestamp: Date.now(),
162
+ };
163
+ await this.sendToGateway(msg.gatewayId, response);
164
+ }
165
+ else {
166
+ const response = {
167
+ type: 'client-response',
168
+ requestId: msg.requestId,
169
+ workerId: this.workerId,
170
+ connectionId: msg.connectionId,
171
+ msgType: core_1.MessageType.MSG_ROOM_CREATE_FAIL,
172
+ payload: { error: 'Failed to create room' },
173
+ timestamp: Date.now(),
174
+ };
175
+ await this.sendToGateway(msg.gatewayId, response);
176
+ }
177
+ }
178
+ /**
179
+ * 构建认证上下文
180
+ */
181
+ buildAuthContext(msg) {
182
+ return {
183
+ connectionId: msg.connectionId,
184
+ gatewayId: msg.gatewayId,
185
+ token: msg.token,
186
+ ip: msg.clientIp,
187
+ timestamp: msg.timestamp,
188
+ };
189
+ }
190
+ async handleJoinRoom(msg, userId) {
191
+ const payload = msg.payload;
192
+ const roomId = payload.roomId;
193
+ const { roomId: _roomId, password, ...options } = payload;
194
+ const room = this.roomManager.getRoom(roomId);
195
+ if (!room) {
196
+ const response = {
197
+ type: 'client-response',
198
+ requestId: msg.requestId,
199
+ workerId: this.workerId,
200
+ connectionId: msg.connectionId,
201
+ msgType: core_1.MessageType.MSG_ROOM_JOIN_FAIL,
202
+ payload: { error: 'Room not found' },
203
+ timestamp: Date.now(),
204
+ };
205
+ await this.sendToGateway(msg.gatewayId, response);
206
+ return;
207
+ }
208
+ const client = new client_proxy_1.ClientProxy(userId, msg.connectionId, msg.gatewayId, this.redis, this.workerId);
209
+ // 构建认证上下文
210
+ const authContext = this.buildAuthContext(msg);
211
+ // 传递 token 到 options 中(如果有)
212
+ const joinOptions = { ...options };
213
+ if (password)
214
+ joinOptions.password = password;
215
+ if (msg.token)
216
+ joinOptions.token = msg.token;
217
+ const success = await this.roomManager.joinRoom(room, client, joinOptions, authContext);
218
+ const response = {
219
+ type: 'client-response',
220
+ requestId: msg.requestId,
221
+ workerId: this.workerId,
222
+ connectionId: msg.connectionId,
223
+ msgType: success ? core_1.MessageType.MSG_ROOM_JOIN_OK : core_1.MessageType.MSG_ROOM_JOIN_FAIL,
224
+ payload: success ? { success: true, roomId } : { success: false, error: 'Failed to join room' },
225
+ timestamp: Date.now(),
226
+ };
227
+ await this.sendToGateway(msg.gatewayId, response);
228
+ }
229
+ /**
230
+ * 处理 joinOrCreate 请求(Colyseus 风格的 concurrentJoinOrCreateRoomLock)
231
+ *
232
+ * requestCount = 0: 房间已存在,直接加入
233
+ * requestCount = 1: 第一个请求,负责创建房间
234
+ * requestCount > 1: 并发请求,等待房间创建完成后加入
235
+ */
236
+ async handleJoinOrCreate(msg, userId) {
237
+ const { roomId, gameType, maxPlayers = 10, config = {}, requestCount = 0, waitTimeout = 5000 } = msg.payload;
238
+ this.logger.log(`[JoinOrCreate] userId=${userId}, roomId=${roomId}, requestCount=${requestCount}`);
239
+ const client = new client_proxy_1.ClientProxy(userId, msg.connectionId, msg.gatewayId, this.redis, this.workerId);
240
+ // requestCount = 0: 房间已存在,直接加入
241
+ if (requestCount === 0) {
242
+ this.logger.log(`[JoinOrCreate] requestCount=0, joining existing room`);
243
+ await this.joinExistingRoom(msg, client, roomId, config);
244
+ return;
245
+ }
246
+ // requestCount = 1: 第一个请求,创建房间
247
+ if (requestCount === 1) {
248
+ this.logger.log(`[JoinOrCreate] requestCount=1, creating room`);
249
+ await this.createAndJoinRoom(msg, client, roomId, gameType, maxPlayers, config);
250
+ return;
251
+ }
252
+ // requestCount > 1: 等待房间创建完成后加入
253
+ this.logger.log(`[JoinOrCreate] requestCount=${requestCount}, waiting for room`);
254
+ await this.waitAndJoinRoom(msg, client, roomId, config, waitTimeout);
255
+ }
256
+ /**
257
+ * 创建并加入房间(第一个请求)
258
+ */
259
+ async createAndJoinRoom(msg, client, roomId, gameType, maxPlayers, config) {
260
+ const room = await this.roomManager.createRoom(roomId, gameType, maxPlayers, config, client);
261
+ if (room) {
262
+ // 创建者加入房间
263
+ await this.roomManager.joinRoom(room, client, config);
264
+ // 通知等待的请求:房间创建成功(通过 Redis Pub/Sub)
265
+ await this.notifyRoomCreated(roomId, true);
266
+ // 清理锁
267
+ await this.redis.client.del(core_1.RedisKeys.roomCreatingLock(roomId));
268
+ const response = {
269
+ type: 'client-response',
270
+ requestId: msg.requestId,
271
+ workerId: this.workerId,
272
+ connectionId: msg.connectionId,
273
+ msgType: core_1.MessageType.MSG_ROOM_JOIN_OK,
274
+ payload: {
275
+ success: true,
276
+ created: true,
277
+ roomInfo: {
278
+ roomId,
279
+ gameType,
280
+ playerCount: room.playerCount,
281
+ maxPlayers: room.maxPlayers,
282
+ },
283
+ },
284
+ timestamp: Date.now(),
285
+ };
286
+ await this.sendToGateway(msg.gatewayId, response);
287
+ }
288
+ else {
289
+ // 创建失败,通知等待的请求
290
+ await this.notifyRoomCreated(roomId, false, 'Failed to create room');
291
+ // 清理锁和映射
292
+ await this.redis.client.del(core_1.RedisKeys.roomCreatingLock(roomId));
293
+ await this.redis.client.del(core_1.RedisKeys.roomWorker(roomId));
294
+ const response = {
295
+ type: 'client-response',
296
+ requestId: msg.requestId,
297
+ workerId: this.workerId,
298
+ connectionId: msg.connectionId,
299
+ msgType: core_1.MessageType.MSG_ROOM_JOIN_FAIL,
300
+ payload: { success: false, error: 'Failed to create room' },
301
+ timestamp: Date.now(),
302
+ };
303
+ await this.sendToGateway(msg.gatewayId, response);
304
+ }
305
+ }
306
+ /**
307
+ * 等待房间创建完成后加入(并发请求)
308
+ */
309
+ async waitAndJoinRoom(msg, client, roomId, config, waitTimeout) {
310
+ const channel = core_1.RedisChannels.roomCreated(roomId);
311
+ const startTime = Date.now();
312
+ // 轮询等待房间创建完成
313
+ while (Date.now() - startTime < waitTimeout) {
314
+ const room = this.roomManager.getRoom(roomId);
315
+ if (room) {
316
+ // 房间已创建,加入
317
+ const success = await this.roomManager.joinRoom(room, client, config);
318
+ const response = {
319
+ type: 'client-response',
320
+ requestId: msg.requestId,
321
+ workerId: this.workerId,
322
+ connectionId: msg.connectionId,
323
+ msgType: success ? core_1.MessageType.MSG_ROOM_JOIN_OK : core_1.MessageType.MSG_ROOM_JOIN_FAIL,
324
+ payload: success
325
+ ? {
326
+ success: true,
327
+ created: false,
328
+ roomInfo: {
329
+ roomId,
330
+ gameType: room.gameType,
331
+ playerCount: room.playerCount,
332
+ maxPlayers: room.maxPlayers,
333
+ },
334
+ }
335
+ : { success: false, error: 'Failed to join room' },
336
+ timestamp: Date.now(),
337
+ };
338
+ await this.sendToGateway(msg.gatewayId, response);
339
+ return;
340
+ }
341
+ // 等待 20ms 后重试
342
+ await new Promise(resolve => setTimeout(resolve, 20));
343
+ }
344
+ // 超时
345
+ const response = {
346
+ type: 'client-response',
347
+ requestId: msg.requestId,
348
+ workerId: this.workerId,
349
+ connectionId: msg.connectionId,
350
+ msgType: core_1.MessageType.MSG_ROOM_JOIN_FAIL,
351
+ payload: { success: false, error: 'WAIT_TIMEOUT' },
352
+ timestamp: Date.now(),
353
+ };
354
+ await this.sendToGateway(msg.gatewayId, response);
355
+ }
356
+ /**
357
+ * 加入已存在的房间
358
+ */
359
+ async joinExistingRoom(msg, client, roomId, config) {
360
+ const room = this.roomManager.getRoom(roomId);
361
+ if (!room) {
362
+ // 房间不存在,可能是孤儿数据,触发清理
363
+ this.logger.warn(`Room ${roomId} not found locally, cleaning up orphan data`);
364
+ await this.roomManager.cleanRoomData(roomId);
365
+ const response = {
366
+ type: 'client-response',
367
+ requestId: msg.requestId,
368
+ workerId: this.workerId,
369
+ connectionId: msg.connectionId,
370
+ msgType: core_1.MessageType.MSG_ROOM_JOIN_FAIL,
371
+ payload: { success: false, error: 'Room not found' },
372
+ timestamp: Date.now(),
373
+ };
374
+ await this.sendToGateway(msg.gatewayId, response);
375
+ return;
376
+ }
377
+ const success = await this.roomManager.joinRoom(room, client, config);
378
+ const response = {
379
+ type: 'client-response',
380
+ requestId: msg.requestId,
381
+ workerId: this.workerId,
382
+ connectionId: msg.connectionId,
383
+ msgType: success ? core_1.MessageType.MSG_ROOM_JOIN_OK : core_1.MessageType.MSG_ROOM_JOIN_FAIL,
384
+ payload: success
385
+ ? {
386
+ success: true,
387
+ created: false,
388
+ roomInfo: {
389
+ roomId,
390
+ gameType: room.gameType,
391
+ playerCount: room.playerCount,
392
+ maxPlayers: room.maxPlayers,
393
+ },
394
+ }
395
+ : { success: false, error: 'Failed to join room' },
396
+ timestamp: Date.now(),
397
+ };
398
+ await this.sendToGateway(msg.gatewayId, response);
399
+ }
400
+ /**
401
+ * 通知等待的 joinOrCreate 请求
402
+ */
403
+ async notifyRoomCreated(roomId, success, error) {
404
+ const channel = core_1.RedisChannels.roomCreated(roomId);
405
+ await this.redis.publish(channel, { success, error });
406
+ }
407
+ async handleLeaveRoom(msg, userId, roomId) {
408
+ const room = this.roomManager.getRoom(roomId);
409
+ if (room) {
410
+ await this.roomManager.leaveRoom(room, userId, 'user-request');
411
+ const response = {
412
+ type: 'client-response',
413
+ requestId: msg.requestId,
414
+ workerId: this.workerId,
415
+ connectionId: msg.connectionId,
416
+ msgType: core_1.MessageType.MSG_ROOM_LEAVE_OK,
417
+ payload: { success: true, roomId },
418
+ timestamp: Date.now(),
419
+ };
420
+ await this.sendToGateway(msg.gatewayId, response);
421
+ }
422
+ else {
423
+ // 房间不存在
424
+ const response = {
425
+ type: 'client-response',
426
+ requestId: msg.requestId,
427
+ workerId: this.workerId,
428
+ connectionId: msg.connectionId,
429
+ msgType: core_1.MessageType.MSG_ERROR,
430
+ payload: { success: false, error: 'Room not found' },
431
+ timestamp: Date.now(),
432
+ };
433
+ await this.sendToGateway(msg.gatewayId, response);
434
+ }
435
+ }
436
+ async handleRoomMessage(msg, userId, roomId) {
437
+ const room = this.roomManager.getRoom(roomId);
438
+ if (!room) {
439
+ this.logger.warn(`Room not found: ${roomId}`);
440
+ return;
441
+ }
442
+ const client = room.getPlayer(userId);
443
+ if (!client) {
444
+ this.logger.warn(`User ${userId} not in room ${roomId}`);
445
+ return;
446
+ }
447
+ // 将消息传递给房间处理(使用 msgType 字符串类型)
448
+ const msgType = msg.msgType;
449
+ if (msgType) {
450
+ await room.onMessage(client, msgType, msg.payload);
451
+ }
452
+ else {
453
+ this.logger.warn(`Message missing msgType for room ${roomId}`);
454
+ }
455
+ }
456
+ async handleClientDisconnect(msg) {
457
+ const userId = msg.userId;
458
+ // 从所有房间中移除用户
459
+ for (const [roomId, room] of this.roomManager.getAllRooms()) {
460
+ if (room.getPlayer(userId)) {
461
+ await this.roomManager.leaveRoom(room, userId, 'disconnected');
462
+ }
463
+ }
464
+ }
465
+ /**
466
+ * 处理房间重连请求
467
+ *
468
+ * Gateway 通知 Worker 更新房间成员的连接信息
469
+ *
470
+ * 重连场景(客户端断连或 Gateway 重启):
471
+ * - 只更新 Redis 中的连接信息(Gateway ID + Connection ID)
472
+ * - 默认不发送状态(客户端已有状态,避免不必要的网络开销)
473
+ * - Worker 内存中的 Room 对象和玩家数据都还在,无需重建
474
+ */
475
+ async handleReconnectRoom(msg) {
476
+ const { userId, roomId, gatewayId, connectionId, payload } = msg;
477
+ if (!userId || !roomId) {
478
+ this.logger.warn('Invalid reconnect-room message: missing userId or roomId');
479
+ return;
480
+ }
481
+ const room = this.roomManager.getRoom(roomId);
482
+ if (!room) {
483
+ this.logger.warn(`Room ${roomId} not found for reconnect`);
484
+ return;
485
+ }
486
+ // 检查用户是否在房间中
487
+ const player = room.getPlayer(userId);
488
+ if (!player) {
489
+ this.logger.warn(`User ${userId} not in room ${roomId}`);
490
+ return;
491
+ }
492
+ // 更新 Redis 中的房间成员连接信息
493
+ const memberData = JSON.stringify({
494
+ gatewayId,
495
+ connectionId,
496
+ joinedAt: Date.now(),
497
+ });
498
+ await this.redis.client.hset(core_1.RedisKeys.roomMembers(roomId), userId, memberData);
499
+ this.logger.log(`Updated connection info for user ${userId} in room ${roomId}: ${gatewayId}/${connectionId}`);
500
+ // 根据 payload 决定是否发送状态(默认不发送)
501
+ // 预留扩展性:未来如果需要其他重连场景可以设置 sendState: true
502
+ const sendState = payload?.sendState === true;
503
+ if (sendState) {
504
+ // 发送完整状态(预留给未来的 Worker 重启场景)
505
+ try {
506
+ const state = room.getState();
507
+ const response = {
508
+ type: 'client-response',
509
+ workerId: this.workerId,
510
+ connectionId,
511
+ msgType: core_1.MessageType.MSG_STATE_FULL,
512
+ payload: {
513
+ roomId,
514
+ state,
515
+ },
516
+ timestamp: Date.now(),
517
+ };
518
+ await this.sendToGateway(gatewayId, response);
519
+ this.logger.log(`Sent full state to reconnected user ${userId} in room ${roomId}`);
520
+ }
521
+ catch (error) {
522
+ this.logger.error(`Failed to send state to reconnected user ${userId}:`, error);
523
+ }
524
+ }
525
+ }
526
+ async sendToGateway(gatewayId, message) {
527
+ const channel = core_1.RedisChannels.rpcGateway(gatewayId);
528
+ this.logger.debug(`[sendToGateway] Sending to ${gatewayId}, channel: ${channel}, msgType: ${message.msgType}`);
529
+ await this.redis.publish(channel, message);
530
+ }
531
+ };
532
+ exports.MessageHandlerService = MessageHandlerService;
533
+ exports.MessageHandlerService = MessageHandlerService = MessageHandlerService_1 = __decorate([
534
+ (0, common_1.Injectable)(),
535
+ __metadata("design:paramtypes", [redis_service_1.RedisService,
536
+ config_service_1.ConfigService,
537
+ room_manager_service_1.RoomManagerService,
538
+ auth_service_1.AuthService,
539
+ circuit_breaker_service_1.CircuitBreakerService])
540
+ ], MessageHandlerService);
541
+ //# sourceMappingURL=message-handler.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-handler.service.js","sourceRoot":"","sources":["../../../src/room/message-handler.service.ts"],"names":[],"mappings":"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"}