@roomkit/client 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.
- package/README.md +300 -0
- package/dist/Client.d.ts +154 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +602 -0
- package/dist/Client.js.map +1 -0
- package/dist/Room.d.ts +161 -0
- package/dist/Room.d.ts.map +1 -0
- package/dist/Room.js +386 -0
- package/dist/Room.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
package/dist/Client.js
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client - 主客户端类
|
|
3
|
+
* 类似 Colyseus 的 Client API
|
|
4
|
+
*/
|
|
5
|
+
import { MessageId, MessageType } from '@roomkit/core';
|
|
6
|
+
import { Room } from './Room.js';
|
|
7
|
+
let WS;
|
|
8
|
+
let wsInitPromise = null;
|
|
9
|
+
// 初始化 WebSocket
|
|
10
|
+
async function initWS() {
|
|
11
|
+
if (WS)
|
|
12
|
+
return;
|
|
13
|
+
if (typeof WebSocket !== 'undefined') {
|
|
14
|
+
// 浏览器环境
|
|
15
|
+
WS = WebSocket;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Node.js环境
|
|
19
|
+
try {
|
|
20
|
+
const wsModule = await import('ws');
|
|
21
|
+
WS = wsModule.default;
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
throw new Error('@roomkit/client requires "ws" package in Node.js environment. Install it with: npm install ws');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 确保 WS 已初始化
|
|
29
|
+
function ensureWS() {
|
|
30
|
+
if (WS)
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
if (!wsInitPromise) {
|
|
33
|
+
wsInitPromise = initWS();
|
|
34
|
+
}
|
|
35
|
+
return wsInitPromise;
|
|
36
|
+
}
|
|
37
|
+
const DEFAULT_OPTIONS = {
|
|
38
|
+
autoReconnect: true,
|
|
39
|
+
reconnectDelay: 1000,
|
|
40
|
+
maxReconnectAttempts: 10,
|
|
41
|
+
requestTimeout: 10000,
|
|
42
|
+
heartbeatInterval: 20000,
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Client 类 - Gateway-Worker 框架的客户端
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import { Client } from '@roomkit/client';
|
|
50
|
+
*
|
|
51
|
+
* const client = new Client('ws://localhost:27100/ws');
|
|
52
|
+
*
|
|
53
|
+
* // 连接并认证
|
|
54
|
+
* await client.auth('my-token');
|
|
55
|
+
*
|
|
56
|
+
* // 加入或创建房间
|
|
57
|
+
* const room = await client.joinOrCreate<MyGameState>('poker', {
|
|
58
|
+
* maxPlayers: 6
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* // 监听状态变化
|
|
62
|
+
* room.onStateChange((state) => {
|
|
63
|
+
* console.log('State:', state);
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // 发送消息
|
|
67
|
+
* room.send('player_action', { action: 'fold' });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export class Client {
|
|
71
|
+
constructor(url, options = {}) {
|
|
72
|
+
this.url = url;
|
|
73
|
+
this.ws = null;
|
|
74
|
+
this.pendingRequests = new Map();
|
|
75
|
+
this.reqCounter = 0;
|
|
76
|
+
this.reconnectAttempts = 0;
|
|
77
|
+
this.heartbeatTimer = null;
|
|
78
|
+
this.sessionToken = null; // 保存会话令牌用于重连
|
|
79
|
+
this._state = 'disconnected';
|
|
80
|
+
this._userId = null;
|
|
81
|
+
this._rooms = new Map();
|
|
82
|
+
this.stateListeners = new Set();
|
|
83
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
84
|
+
}
|
|
85
|
+
// ============ State Getters ============
|
|
86
|
+
get state() {
|
|
87
|
+
return this._state;
|
|
88
|
+
}
|
|
89
|
+
get userId() {
|
|
90
|
+
return this._userId;
|
|
91
|
+
}
|
|
92
|
+
get isConnected() {
|
|
93
|
+
return this._state !== 'disconnected' && this._state !== 'connecting';
|
|
94
|
+
}
|
|
95
|
+
get isAuthenticated() {
|
|
96
|
+
return this._state === 'authenticated';
|
|
97
|
+
}
|
|
98
|
+
// ============ Connection & Authentication ============
|
|
99
|
+
/**
|
|
100
|
+
* 连接到服务器
|
|
101
|
+
*/
|
|
102
|
+
async connect() {
|
|
103
|
+
// 确保 WebSocket 已初始化
|
|
104
|
+
await ensureWS();
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
if (this.ws) {
|
|
107
|
+
this.disconnect();
|
|
108
|
+
}
|
|
109
|
+
this.setState('connecting');
|
|
110
|
+
try {
|
|
111
|
+
this.ws = new WS(this.url);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
reject(error);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const ws = this.ws; // 保存引用避免null检查
|
|
118
|
+
ws.onopen = () => {
|
|
119
|
+
this.reconnectAttempts = 0;
|
|
120
|
+
this.setState('connected');
|
|
121
|
+
this.startHeartbeat();
|
|
122
|
+
resolve();
|
|
123
|
+
};
|
|
124
|
+
ws.onclose = (event) => {
|
|
125
|
+
this.handleDisconnect(event.code, event.reason);
|
|
126
|
+
};
|
|
127
|
+
ws.onerror = () => {
|
|
128
|
+
reject(new Error('WebSocket connection failed'));
|
|
129
|
+
};
|
|
130
|
+
ws.onmessage = (event) => {
|
|
131
|
+
this.handleMessage(event.data);
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 认证(连接 + 认证一步完成)
|
|
137
|
+
*/
|
|
138
|
+
async auth(token) {
|
|
139
|
+
if (this._state === 'disconnected') {
|
|
140
|
+
await this.connect();
|
|
141
|
+
}
|
|
142
|
+
const response = await this.request(MessageType.MSG_AUTH, { token });
|
|
143
|
+
if (response.success && response.userId) {
|
|
144
|
+
this._userId = response.userId;
|
|
145
|
+
this.sessionToken = response.sessionToken || null; // 保存 sessionToken
|
|
146
|
+
this.setState('authenticated');
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
throw new Error(response.error || 'Authentication failed');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 断开连接
|
|
154
|
+
*/
|
|
155
|
+
disconnect() {
|
|
156
|
+
this.stopHeartbeat();
|
|
157
|
+
if (this.ws) {
|
|
158
|
+
this.ws.close(1000, 'Client disconnect');
|
|
159
|
+
this.ws = null;
|
|
160
|
+
}
|
|
161
|
+
this.cleanupPendingRequests();
|
|
162
|
+
this.setState('disconnected');
|
|
163
|
+
// 触发所有房间的离开事件
|
|
164
|
+
this._rooms.forEach(room => {
|
|
165
|
+
room.handleMessage(MessageType.MSG_ROOM_CLOSING, undefined, { reason: 'client_disconnect' });
|
|
166
|
+
});
|
|
167
|
+
this._rooms.clear();
|
|
168
|
+
}
|
|
169
|
+
// ============ Room Operations ============
|
|
170
|
+
/**
|
|
171
|
+
* 生成唯一的房间ID
|
|
172
|
+
*/
|
|
173
|
+
generateRoomId() {
|
|
174
|
+
return `room_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 创建房间
|
|
178
|
+
*
|
|
179
|
+
* 注意:Room 对象会先注册再发送请求,确保能接收到 STATE_FULL 消息
|
|
180
|
+
*/
|
|
181
|
+
async create(roomName, options = {}) {
|
|
182
|
+
if (!this.isAuthenticated) {
|
|
183
|
+
throw new Error('Not authenticated');
|
|
184
|
+
}
|
|
185
|
+
// 预先生成 roomId,这样可以在发送请求前注册 Room
|
|
186
|
+
// 确保能接收到 Worker 发送的 STATE_FULL 消息
|
|
187
|
+
const roomId = options.roomId || this.generateRoomId();
|
|
188
|
+
// 先创建 Room 对象并注册
|
|
189
|
+
const room = new Room(this, roomId, roomName, this._userId);
|
|
190
|
+
this._rooms.set(roomId, room);
|
|
191
|
+
try {
|
|
192
|
+
const response = await this.request(MessageType.MSG_ROOM_CREATE, {
|
|
193
|
+
roomId, // 传递预生成的 roomId
|
|
194
|
+
gameType: roomName,
|
|
195
|
+
...options
|
|
196
|
+
});
|
|
197
|
+
// 兼容多种响应格式:
|
|
198
|
+
// 1. { success: true, roomInfo: { roomId } }
|
|
199
|
+
// 2. { roomId, gameType }
|
|
200
|
+
const isSuccess = response.success || response.roomId || response.roomInfo?.roomId;
|
|
201
|
+
if (isSuccess) {
|
|
202
|
+
return room;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// 创建失败,移除已注册的 Room
|
|
206
|
+
this._rooms.delete(roomId);
|
|
207
|
+
room.dispose();
|
|
208
|
+
throw new Error(response.error || 'Failed to create room');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
// 请求失败,清理已注册的 Room
|
|
213
|
+
this._rooms.delete(roomId);
|
|
214
|
+
room.dispose();
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 加入房间
|
|
220
|
+
*
|
|
221
|
+
* 注意:Room 对象会先注册再发送请求,确保能接收到 STATE_FULL 消息
|
|
222
|
+
*/
|
|
223
|
+
async join(roomId, options = {}) {
|
|
224
|
+
if (!this.isAuthenticated) {
|
|
225
|
+
throw new Error('Not authenticated');
|
|
226
|
+
}
|
|
227
|
+
// 先创建 Room 对象并注册,确保能接收到 STATE_FULL 消息
|
|
228
|
+
// 因为 Worker 在发送 JOIN_ROOM_RES 之前会先发送 STATE_FULL
|
|
229
|
+
const room = new Room(this, roomId, 'unknown', this._userId);
|
|
230
|
+
this._rooms.set(roomId, room);
|
|
231
|
+
try {
|
|
232
|
+
const response = await this.request(MessageType.MSG_ROOM_JOIN, {
|
|
233
|
+
roomId,
|
|
234
|
+
...options // 传递所有 options
|
|
235
|
+
});
|
|
236
|
+
// 兼容两种响应格式:有 success 字段或有 roomId 字段
|
|
237
|
+
if (response.success || response.roomId) {
|
|
238
|
+
return room;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
// 加入失败,移除已注册的 Room
|
|
242
|
+
this._rooms.delete(roomId);
|
|
243
|
+
room.dispose();
|
|
244
|
+
throw new Error(response.error || 'Failed to join room');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
// 请求失败,清理已注册的 Room
|
|
249
|
+
this._rooms.delete(roomId);
|
|
250
|
+
room.dispose();
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* 加入或创建房间(推荐使用)
|
|
256
|
+
*
|
|
257
|
+
* 注意:Room 对象会先注册再发送请求,确保能接收到 STATE_FULL 消息
|
|
258
|
+
*/
|
|
259
|
+
async joinOrCreate(roomName, options = {}) {
|
|
260
|
+
if (!this.isAuthenticated) {
|
|
261
|
+
throw new Error('Not authenticated');
|
|
262
|
+
}
|
|
263
|
+
// 预先生成 roomId
|
|
264
|
+
const roomId = options.roomId || `${roomName}_${Date.now()}`;
|
|
265
|
+
// 先创建 Room 对象并注册
|
|
266
|
+
const room = new Room(this, roomId, roomName, this._userId);
|
|
267
|
+
this._rooms.set(roomId, room);
|
|
268
|
+
try {
|
|
269
|
+
const response = await this.request(MessageType.MSG_ROOM_JOIN_OR_CREATE, {
|
|
270
|
+
roomId,
|
|
271
|
+
gameType: roomName,
|
|
272
|
+
...options
|
|
273
|
+
});
|
|
274
|
+
if (response.success && response.roomInfo?.roomId) {
|
|
275
|
+
// 如果服务端返回的 roomId 不同(不太可能),更新映射
|
|
276
|
+
if (response.roomInfo.roomId !== roomId) {
|
|
277
|
+
this._rooms.delete(roomId);
|
|
278
|
+
room.id = response.roomInfo.roomId;
|
|
279
|
+
this._rooms.set(response.roomInfo.roomId, room);
|
|
280
|
+
}
|
|
281
|
+
return room;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
// 创建/加入失败,移除已注册的 Room
|
|
285
|
+
this._rooms.delete(roomId);
|
|
286
|
+
room.dispose();
|
|
287
|
+
throw new Error(response.error || 'Failed to join or create room');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
// 请求失败,清理已注册的 Room
|
|
292
|
+
this._rooms.delete(roomId);
|
|
293
|
+
room.dispose();
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 根据条件加入房间
|
|
299
|
+
*/
|
|
300
|
+
async joinBy(roomName, criteria = {}) {
|
|
301
|
+
// 可以扩展为支持查询房间列表
|
|
302
|
+
return this.joinOrCreate(roomName, criteria);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* 获取房间列表(需要后端支持)
|
|
306
|
+
*/
|
|
307
|
+
async getAvailableRooms(roomName) {
|
|
308
|
+
const response = await this.request(MessageType.MSG_ROOM_LIST, { gameType: roomName });
|
|
309
|
+
return response.rooms || [];
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* 重新连接到房间(断线重连)
|
|
313
|
+
*/
|
|
314
|
+
async reconnect(roomId, sessionId) {
|
|
315
|
+
// 这个方法不再需要,因为我们使用了更简单的方案
|
|
316
|
+
// 客户端只需要调用 autoReconnect() 即可
|
|
317
|
+
throw new Error('Use autoReconnect() instead. This method is deprecated.');
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 自动重连(使用 sessionToken)
|
|
321
|
+
*
|
|
322
|
+
* 在 WebSocket 断开后自动调用
|
|
323
|
+
*/
|
|
324
|
+
async autoReconnect() {
|
|
325
|
+
if (!this.sessionToken) {
|
|
326
|
+
this.logger('No sessionToken available for reconnect');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
// 重新建立 WebSocket 连接
|
|
331
|
+
await this.connect();
|
|
332
|
+
// 发送重连请求
|
|
333
|
+
const response = await this.request(MessageType.MSG_RECONNECT, {
|
|
334
|
+
sessionToken: this.sessionToken,
|
|
335
|
+
});
|
|
336
|
+
// 恢复用户状态
|
|
337
|
+
this._userId = response.userId;
|
|
338
|
+
this.setState('authenticated');
|
|
339
|
+
// 重新创建 Room 实例(如果客户端还有引用)
|
|
340
|
+
for (const roomInfo of response.rooms) {
|
|
341
|
+
const existingRoom = this._rooms.get(roomInfo.roomId);
|
|
342
|
+
if (existingRoom) {
|
|
343
|
+
// 通知 Room 已重连
|
|
344
|
+
existingRoom.handleMessage(MessageType.MSG_RECONNECT_OK, undefined, roomInfo);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
this.logger(`Reconnected successfully as user ${response.userId}, rejoined ${response.rooms.length} rooms`);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
this.logger('Reconnect failed:', error);
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 移除房间引用(内部使用)
|
|
356
|
+
*/
|
|
357
|
+
removeRoom(roomId) {
|
|
358
|
+
const room = this._rooms.get(roomId);
|
|
359
|
+
if (room) {
|
|
360
|
+
room.dispose();
|
|
361
|
+
this._rooms.delete(roomId);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* 获取当前所有房间
|
|
366
|
+
*/
|
|
367
|
+
getRooms() {
|
|
368
|
+
return Array.from(this._rooms.values());
|
|
369
|
+
}
|
|
370
|
+
// ============ Low-level Messaging ============
|
|
371
|
+
/**
|
|
372
|
+
* 发送消息(不等待响应)
|
|
373
|
+
* @param msgIdOrType 消息ID(数字)或消息类型(字符串)
|
|
374
|
+
* @param payload 消息内容
|
|
375
|
+
* @param roomId 目标房间ID(多房间模式必须指定)
|
|
376
|
+
*/
|
|
377
|
+
send(msgIdOrType, payload = {}, roomId) {
|
|
378
|
+
if (!this.ws || this.ws.readyState !== 1) { // 1 = OPEN
|
|
379
|
+
throw new Error('Not connected');
|
|
380
|
+
}
|
|
381
|
+
const message = typeof msgIdOrType === 'string'
|
|
382
|
+
? { msgType: msgIdOrType, payload, roomId }
|
|
383
|
+
: { msgId: msgIdOrType, payload, roomId };
|
|
384
|
+
this.ws.send(JSON.stringify(message));
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* 发送请求并等待响应
|
|
388
|
+
* @param msgIdOrType 消息ID(数字)或消息类型(字符串)
|
|
389
|
+
* @param payload 消息内容
|
|
390
|
+
* @param roomId 目标房间ID(多房间模式必须指定)
|
|
391
|
+
*/
|
|
392
|
+
request(msgIdOrType, payload = {}, roomId) {
|
|
393
|
+
return new Promise((resolve, reject) => {
|
|
394
|
+
if (!this.ws || this.ws.readyState !== 1) { // 1 = OPEN
|
|
395
|
+
reject(new Error('Not connected'));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const reqId = `req_${++this.reqCounter}`;
|
|
399
|
+
const message = typeof msgIdOrType === 'string'
|
|
400
|
+
? { msgType: msgIdOrType, payload, reqId, roomId }
|
|
401
|
+
: { msgId: msgIdOrType, payload, reqId, roomId };
|
|
402
|
+
const timer = setTimeout(() => {
|
|
403
|
+
this.pendingRequests.delete(reqId);
|
|
404
|
+
reject(new Error('Request timeout'));
|
|
405
|
+
}, this.options.requestTimeout);
|
|
406
|
+
const resolver = {
|
|
407
|
+
resolve: (value) => resolve(value),
|
|
408
|
+
reject,
|
|
409
|
+
timer,
|
|
410
|
+
};
|
|
411
|
+
// 通过 reqId 匹配响应
|
|
412
|
+
this.pendingRequests.set(reqId, resolver);
|
|
413
|
+
// 同时注册 :ok/:fail 响应类型匹配(用于不返回 reqId 的服务器)
|
|
414
|
+
if (typeof msgIdOrType === 'string') {
|
|
415
|
+
const okKey = `msg_${msgIdOrType}:ok`;
|
|
416
|
+
const failKey = `msg_${msgIdOrType}:fail`;
|
|
417
|
+
this.pendingRequests.set(okKey, resolver);
|
|
418
|
+
this.pendingRequests.set(failKey, resolver);
|
|
419
|
+
}
|
|
420
|
+
this.ws.send(JSON.stringify(message));
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
// ============ Event Handling ============
|
|
424
|
+
/**
|
|
425
|
+
* 监听连接状态变化
|
|
426
|
+
*/
|
|
427
|
+
onStateChange(listener) {
|
|
428
|
+
this.stateListeners.add(listener);
|
|
429
|
+
return () => this.stateListeners.delete(listener);
|
|
430
|
+
}
|
|
431
|
+
// ============ Private Methods ============
|
|
432
|
+
setState(state) {
|
|
433
|
+
this._state = state;
|
|
434
|
+
this.stateListeners.forEach(listener => {
|
|
435
|
+
try {
|
|
436
|
+
listener(state);
|
|
437
|
+
}
|
|
438
|
+
catch (e) {
|
|
439
|
+
console.error('[Client] Error in state listener:', e);
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
handleMessage(data) {
|
|
444
|
+
try {
|
|
445
|
+
const message = JSON.parse(data);
|
|
446
|
+
const msgType = message.msgType;
|
|
447
|
+
const msgId = message.msgId;
|
|
448
|
+
// 处理请求响应(通过reqId匹配)
|
|
449
|
+
if (message.reqId && this.pendingRequests.has(message.reqId)) {
|
|
450
|
+
const pending = this.pendingRequests.get(message.reqId);
|
|
451
|
+
this.pendingRequests.delete(message.reqId);
|
|
452
|
+
clearTimeout(pending.timer);
|
|
453
|
+
pending.resolve(message.payload);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
// 处理响应消息(通过msgType匹配)
|
|
457
|
+
if (msgType) {
|
|
458
|
+
const reqKey = `msg_${msgType}`;
|
|
459
|
+
if (this.pendingRequests.has(reqKey)) {
|
|
460
|
+
const pending = this.pendingRequests.get(reqKey);
|
|
461
|
+
this.pendingRequests.delete(reqKey);
|
|
462
|
+
clearTimeout(pending.timer);
|
|
463
|
+
pending.resolve(message.payload);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// 处理响应消息(通过msgId匹配,向后兼容)
|
|
468
|
+
if (msgId && this.isResponseMessage(msgId)) {
|
|
469
|
+
const reqKey = `msg_${msgId}`;
|
|
470
|
+
if (this.pendingRequests.has(reqKey)) {
|
|
471
|
+
const pending = this.pendingRequests.get(reqKey);
|
|
472
|
+
this.pendingRequests.delete(reqKey);
|
|
473
|
+
clearTimeout(pending.timer);
|
|
474
|
+
pending.resolve(message.payload);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// 处理心跳(支持两种格式)
|
|
479
|
+
if (msgType === MessageType.MSG_HEARTBEAT || msgId === MessageId.HEARTBEAT) {
|
|
480
|
+
this.send(MessageType.MSG_HEARTBEAT_ACK, {});
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (msgType === MessageType.MSG_HEARTBEAT_ACK || msgId === MessageId.HEARTBEAT_ACK) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
// 路由到房间处理(同时传递msgType和msgId)
|
|
487
|
+
this.routeToRoom(msgType, msgId, message.payload);
|
|
488
|
+
}
|
|
489
|
+
catch (e) {
|
|
490
|
+
console.error('[Client] Failed to parse message:', e);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* 检查是否为响应消息
|
|
495
|
+
*/
|
|
496
|
+
isResponseMessage(msgId) {
|
|
497
|
+
// 响应消息ID通常是请求ID+1
|
|
498
|
+
// 例如: AUTH_REQ(1001) -> AUTH_RES(1002)
|
|
499
|
+
const responseMsgIds = [
|
|
500
|
+
MessageId.AUTH_RES,
|
|
501
|
+
MessageId.CREATE_ROOM_RES,
|
|
502
|
+
MessageId.JOIN_ROOM_RES,
|
|
503
|
+
MessageId.JOIN_OR_CREATE_RES,
|
|
504
|
+
MessageId.LEAVE_ROOM_RES,
|
|
505
|
+
MessageId.ROOM_LIST_RES,
|
|
506
|
+
];
|
|
507
|
+
return responseMsgIds.includes(msgId);
|
|
508
|
+
}
|
|
509
|
+
routeToRoom(msgType, msgId, payload) {
|
|
510
|
+
// 如果payload包含roomId,路由到特定房间
|
|
511
|
+
if (payload && typeof payload === 'object' && 'roomId' in payload) {
|
|
512
|
+
const room = this._rooms.get(payload.roomId);
|
|
513
|
+
if (room) {
|
|
514
|
+
room.handleMessage(msgType, msgId, payload);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// 否则广播到所有房间(仅针对特定消息类型)
|
|
519
|
+
if (this._rooms.size === 1) {
|
|
520
|
+
// 如果只有一个房间,直接路由
|
|
521
|
+
const [room] = this._rooms.values();
|
|
522
|
+
room.handleMessage(msgType, msgId, payload);
|
|
523
|
+
}
|
|
524
|
+
else if (this._rooms.size > 1) {
|
|
525
|
+
// 多个房间时,只广播特定消息
|
|
526
|
+
const broadcastTypes = [
|
|
527
|
+
MessageType.MSG_STATE_FULL,
|
|
528
|
+
MessageType.MSG_STATE_DELTA,
|
|
529
|
+
MessageType.MSG_PLAYER_JOINED,
|
|
530
|
+
MessageType.MSG_PLAYER_LEFT,
|
|
531
|
+
];
|
|
532
|
+
const broadcastMsgIds = [
|
|
533
|
+
MessageId.STATE_FULL,
|
|
534
|
+
MessageId.STATE_DELTA,
|
|
535
|
+
MessageId.PLAYER_JOINED,
|
|
536
|
+
MessageId.PLAYER_LEFT,
|
|
537
|
+
];
|
|
538
|
+
const shouldBroadcast = (msgType && broadcastTypes.includes(msgType)) ||
|
|
539
|
+
(msgId && broadcastMsgIds.includes(msgId));
|
|
540
|
+
if (shouldBroadcast) {
|
|
541
|
+
this._rooms.forEach(room => {
|
|
542
|
+
room.handleMessage(msgType, msgId, payload);
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
handleDisconnect(code, reason) {
|
|
548
|
+
this.stopHeartbeat();
|
|
549
|
+
this.cleanupPendingRequests();
|
|
550
|
+
const wasAuthenticated = this._state === 'authenticated';
|
|
551
|
+
this.setState('disconnected');
|
|
552
|
+
// 通知所有房间
|
|
553
|
+
this._rooms.forEach(room => {
|
|
554
|
+
room.handleMessage(MessageType.MSG_ROOM_CLOSING, undefined, {
|
|
555
|
+
reason: 'disconnect',
|
|
556
|
+
code,
|
|
557
|
+
message: reason
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
// 自动重连(如果有 sessionToken)
|
|
561
|
+
if (wasAuthenticated &&
|
|
562
|
+
this.sessionToken &&
|
|
563
|
+
this.options.autoReconnect &&
|
|
564
|
+
this.reconnectAttempts < this.options.maxReconnectAttempts) {
|
|
565
|
+
this.reconnectAttempts++;
|
|
566
|
+
const delay = this.options.reconnectDelay * this.reconnectAttempts;
|
|
567
|
+
console.log(`[Client] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
568
|
+
setTimeout(() => {
|
|
569
|
+
this.autoReconnect().catch((error) => {
|
|
570
|
+
console.error('[Client] Reconnect failed:', error);
|
|
571
|
+
});
|
|
572
|
+
}, delay);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
cleanupPendingRequests() {
|
|
576
|
+
this.pendingRequests.forEach(pending => {
|
|
577
|
+
clearTimeout(pending.timer);
|
|
578
|
+
pending.reject(new Error('Connection closed'));
|
|
579
|
+
});
|
|
580
|
+
this.pendingRequests.clear();
|
|
581
|
+
}
|
|
582
|
+
startHeartbeat() {
|
|
583
|
+
this.stopHeartbeat();
|
|
584
|
+
this.heartbeatTimer = setInterval(() => {
|
|
585
|
+
if (this.ws && this.ws.readyState === 1) { // 1 = OPEN
|
|
586
|
+
this.send(MessageId.HEARTBEAT, { timestamp: Date.now() });
|
|
587
|
+
}
|
|
588
|
+
}, this.options.heartbeatInterval);
|
|
589
|
+
}
|
|
590
|
+
stopHeartbeat() {
|
|
591
|
+
if (this.heartbeatTimer) {
|
|
592
|
+
clearInterval(this.heartbeatTimer);
|
|
593
|
+
this.heartbeatTimer = null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
logger(...args) {
|
|
597
|
+
if (typeof console !== 'undefined') {
|
|
598
|
+
console.log('[Client]', ...args);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
//# sourceMappingURL=Client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Client.js","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"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"}
|