@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,434 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GameRoom = exports.ServerError = void 0;
4
+ const core_1 = require("@roomkit/core");
5
+ const DEFAULT_ENCODING_OPTIONS = {
6
+ useBinaryEncoding: true,
7
+ compressLargeState: true,
8
+ compressionThreshold: 4 * 1024, // 4KB
9
+ };
10
+ // 导出认证相关类型供子类使用
11
+ var core_2 = require("@roomkit/core");
12
+ Object.defineProperty(exports, "ServerError", { enumerable: true, get: function () { return core_2.ServerError; } });
13
+ /**
14
+ * 游戏房间抽象基类
15
+ * 类似 Colyseus 的 Room 设计
16
+ * 支持 @roomkit/state 状态同步
17
+ */
18
+ class GameRoom {
19
+ roomId;
20
+ gameType;
21
+ maxPlayers;
22
+ config;
23
+ status = 'creating';
24
+ players = new Map();
25
+ playerInfos = new Map();
26
+ createdAt;
27
+ autoDispose = true;
28
+ autoDisposeTimeout = 60000; // 1分钟
29
+ disposeTimer = null;
30
+ // 迁移相关
31
+ isMigrating = false;
32
+ sourceWorkerId; // 如果是从迁移恢复的,记录源 Worker
33
+ // 状态同步相关
34
+ state = null;
35
+ stateSyncInterval = null;
36
+ stateSyncRate = 50; // 默认50ms
37
+ // 状态编码配置(参考 Colyseus 设计)
38
+ stateEncodingOptions = { ...DEFAULT_ENCODING_OPTIONS };
39
+ // 持久化相关
40
+ stateVersion = 0; // 状态版本号
41
+ persistenceCallback; // 持久化事件回调
42
+ constructor(roomId, gameType, maxPlayers, config = {}) {
43
+ this.roomId = roomId;
44
+ this.gameType = gameType;
45
+ this.maxPlayers = maxPlayers;
46
+ this.config = config;
47
+ this.createdAt = Date.now();
48
+ }
49
+ // ============ 静态鉴权(Colyseus 风格,推荐) ============
50
+ /**
51
+ * 静态认证方法(推荐)
52
+ *
53
+ * 在创建房间实例前验证用户身份,适合需要在加入前验证 token 的场景。
54
+ *
55
+ * @param token - 客户端传入的认证 token
56
+ * @param options - 加入房间的选项
57
+ * @param context - 认证上下文,包含 IP、headers 等信息
58
+ * @returns 返回用户数据(truthy)允许加入,返回 falsy 或抛出错误拒绝加入
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * static async onAuth(token: string, options: any, context: AuthContext) {
63
+ * // 验证 JWT
64
+ * const user = await JWT.verify(token);
65
+ * if (!user) throw new ServerError('INVALID_TOKEN', 'Token 无效');
66
+ *
67
+ * // 验证房间密码
68
+ * if (options.password !== 'secret') {
69
+ * throw new ServerError('WRONG_PASSWORD', '密码错误');
70
+ * }
71
+ *
72
+ * // 返回用户数据,会附加到 client.auth
73
+ * return { userId: user.id, username: user.name };
74
+ * }
75
+ * ```
76
+ */
77
+ static async onAuth(token, options, context) {
78
+ // 默认实现:信任 Gateway 层的认证
79
+ return true;
80
+ }
81
+ /**
82
+ * 实例鉴权方法(需要访问房间状态时使用)
83
+ *
84
+ * 如果同时定义了 static onAuth 和实例 onAuth,两者都会被调用。
85
+ * static onAuth 先执行,通过后再执行实例 onAuth。
86
+ *
87
+ * @param client - 客户端代理,包含 userId、auth 等信息
88
+ * @param options - 加入房间的选项
89
+ * @param context - 认证上下文
90
+ * @returns true 允许加入,false 或抛出错误拒绝加入
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * async onAuth(client, options, context) {
95
+ * // 检查是否在黑名单
96
+ * if (this.blacklist.has(client.userId)) {
97
+ * await client.send(MessageType.ERROR, {
98
+ * code: 'BANNED',
99
+ * message: '你已被封禁'
100
+ * });
101
+ * return false;
102
+ * }
103
+ *
104
+ * // 检查房间密码
105
+ * if (this.config.password && options.password !== this.config.password) {
106
+ * throw new ServerError('WRONG_PASSWORD', '密码错误');
107
+ * }
108
+ *
109
+ * return true;
110
+ * }
111
+ * ```
112
+ */
113
+ async onAuth(client, options, context) {
114
+ return true;
115
+ }
116
+ // ============ 公共方法 ============
117
+ /**
118
+ * 添加玩家
119
+ */
120
+ addPlayer(client, playerInfo) {
121
+ this.players.set(client.userId, client);
122
+ this.playerInfos.set(client.userId, playerInfo);
123
+ client.roomId = this.roomId;
124
+ // 取消自动销毁计时器
125
+ if (this.disposeTimer) {
126
+ clearTimeout(this.disposeTimer);
127
+ this.disposeTimer = null;
128
+ }
129
+ }
130
+ /**
131
+ * 移除玩家
132
+ */
133
+ removePlayer(userId) {
134
+ this.players.delete(userId);
135
+ this.playerInfos.delete(userId);
136
+ // 如果房间为空且开启自动销毁
137
+ if (this.players.size === 0 && this.autoDispose) {
138
+ this.scheduleDispose();
139
+ }
140
+ }
141
+ /**
142
+ * 获取玩家数量
143
+ */
144
+ get playerCount() {
145
+ return this.players.size;
146
+ }
147
+ /**
148
+ * 获取所有玩家信息
149
+ */
150
+ getPlayerInfos() {
151
+ return Array.from(this.playerInfos.values());
152
+ }
153
+ /**
154
+ * 检查玩家是否在房间
155
+ */
156
+ hasPlayer(userId) {
157
+ return this.players.has(userId);
158
+ }
159
+ /**
160
+ * 获取玩家
161
+ */
162
+ getPlayer(userId) {
163
+ return this.players.get(userId);
164
+ }
165
+ /**
166
+ * 广播给所有玩家
167
+ */
168
+ async broadcast(msgType, payload, excludeUserId) {
169
+ for (const [userId, client] of this.players) {
170
+ if (excludeUserId && userId === excludeUserId)
171
+ continue;
172
+ await client.send(msgType, payload);
173
+ }
174
+ }
175
+ /**
176
+ * 发送消息给特定玩家
177
+ */
178
+ async send(userId, msgType, payload) {
179
+ const client = this.players.get(userId);
180
+ if (client) {
181
+ await client.send(msgType, payload);
182
+ }
183
+ }
184
+ /**
185
+ * 设置状态同步间隔
186
+ * @param intervalMs 间隔毫秒数,0 表示禁用自动同步
187
+ */
188
+ setStateSyncInterval(intervalMs) {
189
+ // 清除旧的定时器
190
+ if (this.stateSyncInterval) {
191
+ clearInterval(this.stateSyncInterval);
192
+ this.stateSyncInterval = null;
193
+ }
194
+ this.stateSyncRate = intervalMs;
195
+ // 设置新的定时器
196
+ if (intervalMs > 0) {
197
+ this.stateSyncInterval = setInterval(() => {
198
+ this.syncState();
199
+ }, intervalMs);
200
+ }
201
+ }
202
+ /**
203
+ * 同步状态(增量更新)
204
+ */
205
+ async syncState() {
206
+ if (!this.state)
207
+ return;
208
+ // 检查状态是否是 State 实例且有变化
209
+ const stateObj = this.state;
210
+ if (typeof stateObj.hasChanges === 'function' && typeof stateObj.getPatches === 'function') {
211
+ if (!stateObj.hasChanges())
212
+ return;
213
+ const patches = stateObj.getPatches();
214
+ if (patches.length === 0)
215
+ return;
216
+ // 广播增量更新
217
+ await this.broadcast(core_1.MessageType.MSG_STATE_DELTA, {
218
+ patches,
219
+ });
220
+ // 清除已发送的变化
221
+ if (typeof stateObj.clearChanges === 'function') {
222
+ stateObj.clearChanges();
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * 设置状态编码配置
228
+ */
229
+ setStateEncodingOptions(options) {
230
+ this.stateEncodingOptions = { ...this.stateEncodingOptions, ...options };
231
+ }
232
+ /**
233
+ * 发送完整状态给特定玩家
234
+ *
235
+ * 参考 Colyseus 设计:
236
+ * 1. 优先使用二进制编码(@roomkit/state 的 encode 方法)
237
+ * 2. 如果状态实现了 encode(true),使用二进制格式
238
+ * 3. 否则回退到 JSON 格式
239
+ */
240
+ async sendFullState(userId) {
241
+ if (!this.state)
242
+ return;
243
+ const client = this.players.get(userId);
244
+ if (!client)
245
+ return;
246
+ const stateObj = this.state;
247
+ // 优先使用二进制编码(如果状态支持)
248
+ if (this.stateEncodingOptions.useBinaryEncoding && typeof stateObj.encode === 'function') {
249
+ try {
250
+ // 使用 @roomkit/state 的 encode(true) 获取二进制完整状态
251
+ const encoded = stateObj.encode(true, {
252
+ compressionOptions: {
253
+ forceCompress: this.stateEncodingOptions.compressLargeState,
254
+ compressionThreshold: this.stateEncodingOptions.compressionThreshold,
255
+ }
256
+ });
257
+ // 发送二进制编码的状态
258
+ await client.send(core_1.MessageType.MSG_STATE_FULL, {
259
+ binary: true,
260
+ data: Array.from(encoded.data), // Uint8Array 转为普通数组以便序列化
261
+ compressed: encoded.compressed,
262
+ originalSize: encoded.originalSize,
263
+ });
264
+ return;
265
+ }
266
+ catch (e) {
267
+ // 二进制编码失败,回退到 JSON
268
+ console.warn(`[GameRoom] Binary encoding failed, falling back to JSON:`, e);
269
+ }
270
+ }
271
+ // 回退:使用 JSON 格式
272
+ let stateData;
273
+ if (typeof stateObj.toJSON === 'function') {
274
+ stateData = stateObj.toJSON();
275
+ }
276
+ else {
277
+ stateData = this.state;
278
+ }
279
+ await client.send(core_1.MessageType.MSG_STATE_FULL, {
280
+ binary: false,
281
+ state: stateData,
282
+ });
283
+ }
284
+ /**
285
+ * 广播完整状态给所有玩家
286
+ */
287
+ async broadcastFullState() {
288
+ if (!this.state)
289
+ return;
290
+ for (const userId of this.players.keys()) {
291
+ await this.sendFullState(userId);
292
+ }
293
+ }
294
+ /**
295
+ * 获取客户端列表(兼容性方法)
296
+ */
297
+ get clients() {
298
+ return this.players;
299
+ }
300
+ /**
301
+ * 计划销毁房间
302
+ */
303
+ scheduleDispose() {
304
+ this.disposeTimer = setTimeout(() => {
305
+ if (this.players.size === 0) {
306
+ this.dispose();
307
+ }
308
+ }, this.autoDisposeTimeout);
309
+ }
310
+ /**
311
+ * 销毁房间
312
+ * 需要子类或RoomManager调用
313
+ */
314
+ async dispose() {
315
+ if (this.status === 'disposed')
316
+ return;
317
+ this.status = 'disposed';
318
+ if (this.disposeTimer) {
319
+ clearTimeout(this.disposeTimer);
320
+ }
321
+ if (this.stateSyncInterval) {
322
+ clearInterval(this.stateSyncInterval);
323
+ }
324
+ await this.onDispose();
325
+ }
326
+ // ============ 迁移相关方法 ============
327
+ /**
328
+ * 创建房间快照用于迁移
329
+ * 子类可以覆盖 getGameState() 来序列化游戏特定状态
330
+ */
331
+ createSnapshot(workerId) {
332
+ const players = [];
333
+ for (const [userId, client] of this.players) {
334
+ const playerInfo = this.playerInfos.get(userId);
335
+ if (playerInfo) {
336
+ players.push({
337
+ userId,
338
+ gatewayId: client.gatewayId,
339
+ connectionId: client.connectionId,
340
+ playerInfo,
341
+ });
342
+ }
343
+ }
344
+ return {
345
+ roomId: this.roomId,
346
+ gameType: this.gameType,
347
+ maxPlayers: this.maxPlayers,
348
+ config: { ...this.config },
349
+ status: this.status,
350
+ createdAt: this.createdAt,
351
+ players,
352
+ gameState: this.getGameState(),
353
+ snapshotVersion: 1,
354
+ snapshotTime: Date.now(),
355
+ sourceWorkerId: workerId,
356
+ };
357
+ }
358
+ /**
359
+ * 从快照恢复房间状态
360
+ * 子类可以覆盖 restoreGameState() 来恢复游戏特定状态
361
+ */
362
+ restoreFromSnapshot(snapshot) {
363
+ this.status = snapshot.status;
364
+ this.sourceWorkerId = snapshot.sourceWorkerId;
365
+ // 恢复玩家信息(ClientProxy 需要在 RoomManager 中重建)
366
+ for (const player of snapshot.players) {
367
+ this.playerInfos.set(player.userId, player.playerInfo);
368
+ }
369
+ // 恢复游戏状态
370
+ this.restoreGameState(snapshot.gameState);
371
+ }
372
+ /**
373
+ * 获取游戏特定状态(子类需要覆盖)
374
+ * 返回可 JSON 序列化的对象
375
+ */
376
+ getGameState() {
377
+ return null;
378
+ }
379
+ /**
380
+ * 恢复游戏特定状态(子类需要覆盖)
381
+ */
382
+ restoreGameState(state) {
383
+ // 默认不做任何事情
384
+ }
385
+ /**
386
+ * 迁移前的准备工作(可选覆盖)
387
+ * 例如:暂停游戏逻辑、保存关键状态
388
+ */
389
+ async onMigrationStart() {
390
+ this.isMigrating = true;
391
+ }
392
+ /**
393
+ * 迁移完成后的回调(可选覆盖)
394
+ * 在新 Worker 上调用
395
+ */
396
+ async onMigrationComplete() {
397
+ this.isMigrating = false;
398
+ }
399
+ /**
400
+ * 迁移失败时的回调(可选覆盖)
401
+ */
402
+ async onMigrationFailed(error) {
403
+ this.isMigrating = false;
404
+ }
405
+ // ============ 持久化辅助方法 ============
406
+ /**
407
+ * 获取当前状态(供持久化使用)
408
+ */
409
+ getState() {
410
+ return {
411
+ version: this.stateVersion,
412
+ status: this.status,
413
+ playerCount: this.playerCount,
414
+ state: this.state,
415
+ createdAt: this.createdAt,
416
+ };
417
+ }
418
+ /**
419
+ * 记录状态变更事件(供子类使用)
420
+ */
421
+ recordStateChange(type, data) {
422
+ this.stateVersion++;
423
+ if (this.persistenceCallback) {
424
+ this.persistenceCallback({
425
+ type,
426
+ version: this.stateVersion,
427
+ data,
428
+ timestamp: Date.now(),
429
+ });
430
+ }
431
+ }
432
+ }
433
+ exports.GameRoom = GameRoom;
434
+ //# sourceMappingURL=game-room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-room.js","sourceRoot":"","sources":["../../../src/room/game-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { RedisService } from '../redis/redis.service';
3
+ import { ConfigService } from '../config/config.service';
4
+ import { RoomManagerService } from './room-manager.service';
5
+ import { AuthService } from '../auth/auth.service';
6
+ import { CircuitBreakerService } from '../circuit-breaker/circuit-breaker.service';
7
+ export declare class MessageHandlerService implements OnModuleInit {
8
+ private readonly redis;
9
+ private readonly config;
10
+ private readonly roomManager;
11
+ private readonly authService;
12
+ private readonly circuitBreaker;
13
+ private readonly logger;
14
+ private readonly workerId;
15
+ constructor(redis: RedisService, config: ConfigService, roomManager: RoomManagerService, authService: AuthService, circuitBreaker: CircuitBreakerService);
16
+ onModuleInit(): Promise<void>;
17
+ private handleMessage;
18
+ /**
19
+ * 发送错误响应(熔断时使用)
20
+ */
21
+ private sendErrorResponse;
22
+ private handleAuthRequest;
23
+ private handleClientMessage;
24
+ private handleCreateRoom;
25
+ /**
26
+ * 构建认证上下文
27
+ */
28
+ private buildAuthContext;
29
+ private handleJoinRoom;
30
+ /**
31
+ * 处理 joinOrCreate 请求(Colyseus 风格的 concurrentJoinOrCreateRoomLock)
32
+ *
33
+ * requestCount = 0: 房间已存在,直接加入
34
+ * requestCount = 1: 第一个请求,负责创建房间
35
+ * requestCount > 1: 并发请求,等待房间创建完成后加入
36
+ */
37
+ private handleJoinOrCreate;
38
+ /**
39
+ * 创建并加入房间(第一个请求)
40
+ */
41
+ private createAndJoinRoom;
42
+ /**
43
+ * 等待房间创建完成后加入(并发请求)
44
+ */
45
+ private waitAndJoinRoom;
46
+ /**
47
+ * 加入已存在的房间
48
+ */
49
+ private joinExistingRoom;
50
+ /**
51
+ * 通知等待的 joinOrCreate 请求
52
+ */
53
+ private notifyRoomCreated;
54
+ private handleLeaveRoom;
55
+ private handleRoomMessage;
56
+ private handleClientDisconnect;
57
+ /**
58
+ * 处理房间重连请求
59
+ *
60
+ * Gateway 通知 Worker 更新房间成员的连接信息
61
+ *
62
+ * 重连场景(客户端断连或 Gateway 重启):
63
+ * - 只更新 Redis 中的连接信息(Gateway ID + Connection ID)
64
+ * - 默认不发送状态(客户端已有状态,避免不必要的网络开销)
65
+ * - Worker 内存中的 Room 对象和玩家数据都还在,无需重建
66
+ */
67
+ private handleReconnectRoom;
68
+ private sendToGateway;
69
+ }
70
+ //# sourceMappingURL=message-handler.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-handler.service.d.ts","sourceRoot":"","sources":["../../../src/room/message-handler.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAU,MAAM,gBAAgB,CAAC;AASlE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAGnF,qBACa,qBAAsB,YAAW,YAAY;IAKtD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IARjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,kBAAkB,EAC/B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,qBAAqB;IAKlD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAMrB,aAAa;IA+C3B;;OAEG;YACW,iBAAiB;YAYjB,iBAAiB;YAkBjB,mBAAmB;YAmCnB,gBAAgB;IAiD9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;YAUV,cAAc;IAkD5B;;;;;;OAMG;YACW,kBAAkB;IAuChC;;OAEG;YACW,iBAAiB;IA4D/B;;OAEG;YACW,eAAe;IA0D7B;;OAEG;YACW,gBAAgB;IAkD9B;;OAEG;YACW,iBAAiB;YASjB,eAAe;YAkCf,iBAAiB;YA0BjB,sBAAsB;IAWpC;;;;;;;;;OASG;YACW,mBAAmB;YAgEnB,aAAa;CAQ5B"}