Skip to content

Commit ecbcb1c

Browse files
committed
fix: enlarge client 'live' time to prevent inproper connection close
1 parent 7cb7ffa commit ecbcb1c

File tree

5 files changed

+137
-93
lines changed

5 files changed

+137
-93
lines changed

plugins/live-query/src/index.js

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,47 @@ const onRealtimeCreate = realtime => {
88
if (realtime._liveQueryClients[subscriptionId] !== undefined) {
99
return _Promise.resolve(realtime._liveQueryClients[subscriptionId]);
1010
}
11-
const promise = realtime._open().then(connection => {
12-
const client = new LiveQueryClient(
13-
realtime._options.appId,
14-
subscriptionId,
15-
connection
16-
);
17-
connection.on('reconnect', () =>
18-
client
19-
._open()
20-
.then(
21-
() => client.emit('reconnect'),
22-
error => client.emit('reconnecterror', error)
23-
)
24-
);
25-
client._eventemitter.on(
26-
'close',
27-
() => {
28-
delete realtime._liveQueryClients[client.id];
29-
realtime._deregister(client);
30-
},
31-
realtime
32-
);
33-
return client._open().then(() => {
34-
realtime._liveQueryClients[client.id] = client;
35-
realtime._register(client);
36-
return client;
11+
const promise = realtime
12+
._open()
13+
.then(connection => {
14+
const client = new LiveQueryClient(
15+
realtime._options.appId,
16+
subscriptionId,
17+
connection
18+
);
19+
connection.on('reconnect', () =>
20+
client
21+
._open()
22+
.then(
23+
() => client.emit('reconnect'),
24+
error => client.emit('reconnecterror', error)
25+
)
26+
);
27+
client._eventemitter.on(
28+
'beforeclose',
29+
() => {
30+
delete realtime._liveQueryClients[client.id];
31+
},
32+
realtime
33+
);
34+
client._eventemitter.on(
35+
'close',
36+
() => {
37+
realtime._deregister(client);
38+
},
39+
realtime
40+
);
41+
return client._open().then(() => {
42+
realtime._liveQueryClients[client.id] = client;
43+
realtime._register(client);
44+
return client;
45+
});
46+
})
47+
.finally(() => {
48+
if (realtime._deregisterPending) realtime._deregisterPending(promise);
3749
});
38-
});
3950
realtime._liveQueryClients[subscriptionId] = promise;
51+
if (realtime._registerPending) realtime._registerPending(promise);
4052
return promise;
4153
};
4254
/* eslint-enable no-param-reassign */

plugins/live-query/src/live-query-client.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,22 @@ export default class LiveQueryClient extends EventEmitter {
3131
);
3232
}
3333
close() {
34+
const _ee = this._eventemitter;
35+
_ee.emit('beforeclose');
3436
return this._send(
3537
new GenericCommand({
3638
cmd: CommandType.logout,
3739
})
38-
).then(() => this._eventemitter.emit('close'));
40+
).then(() => _ee.emit('close'));
3941
}
4042
register(liveQuery) {
4143
this._querys.add(liveQuery);
4244
}
4345
deregister(liveQuery) {
4446
this._querys.delete(liveQuery);
45-
if (!this._querys.size) this.close().catch(warn);
47+
setTimeout(() => {
48+
if (!this._querys.size) this.close().catch(warn);
49+
}, 0);
4650
}
4751
_dispatchCommand(command) {
4852
if (command.cmd !== CommandType.data) {

src/im-client.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,14 +1037,16 @@ export default class IMClient extends EventEmitter {
10371037
*/
10381038
async close() {
10391039
this._debug('close session');
1040+
const _ee = internal(this)._eventemitter;
1041+
_ee.emit('beforeclose');
10401042
if (this._connection.is('connected')) {
10411043
const command = new GenericCommand({
10421044
cmd: 'session',
10431045
op: 'close',
10441046
});
10451047
await this._send(command);
10461048
}
1047-
internal(this)._eventemitter.emit('close');
1049+
_ee.emit('close');
10481050
this.emit(CLOSE, {
10491051
code: 0,
10501052
});

src/plugin-im.js

Lines changed: 75 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -222,70 +222,85 @@ const onRealtimeCreate = realtime => {
222222
);
223223
}
224224
const _tag = tag || lagecyTag;
225-
const promise = realtime._open().then(connection => {
226-
const client = new IMClient(
227-
id,
228-
{ ...buildinOptions, ...clientOptions },
229-
{
230-
_connection: connection,
231-
_request: realtime._request.bind(realtime),
232-
_messageParser: messageParser,
233-
_plugins: realtime._plugins,
234-
_identity: identity,
235-
}
236-
);
237-
connection.on(RECONNECT, () =>
238-
client
239-
._open(realtime._options.appId, _tag, deviceId, true)
240-
/**
241-
* 客户端连接恢复正常,该事件通常在 {@link Realtime#event:RECONNECT} 之后发生
242-
* @event IMClient#RECONNECT
243-
* @see Realtime#event:RECONNECT
244-
* @since 3.2.0
245-
*/
246-
/**
247-
* 客户端重新登录发生错误(网络连接已恢复,但重新登录错误)
248-
* @event IMClient#RECONNECT_ERROR
249-
* @since 3.2.0
250-
*/
251-
.then(
252-
() => client.emit(RECONNECT),
253-
error => client.emit(RECONNECT_ERROR, error)
254-
)
255-
);
256-
internal(client)._eventemitter.on(
257-
'close',
258-
() => {
259-
delete realtime._IMClients[client.id];
260-
realtime._deregister(client);
261-
},
262-
realtime
263-
);
264-
return client
265-
._open(realtime._options.appId, _tag, deviceId, isReconnect)
266-
.then(() => {
267-
realtime._IMClients[client.id] = client;
268-
realtime._IMClientsCreationCount += 1;
269-
if (realtime._IMClientsCreationCount === 1) {
270-
client._omitPeerId(true);
271-
realtime._firstIMClient = client;
272-
} else if (
273-
realtime._IMClientsCreationCount > 1 &&
274-
realtime._firstIMClient
275-
) {
276-
realtime._firstIMClient._omitPeerId(false);
225+
const promise = realtime
226+
._open()
227+
.then(connection => {
228+
const client = new IMClient(
229+
id,
230+
{ ...buildinOptions, ...clientOptions },
231+
{
232+
_connection: connection,
233+
_request: realtime._request.bind(realtime),
234+
_messageParser: messageParser,
235+
_plugins: realtime._plugins,
236+
_identity: identity,
277237
}
278-
realtime._register(client);
279-
return client;
280-
})
281-
.catch(error => {
282-
delete realtime._IMClients[client.id];
283-
throw error;
284-
});
285-
});
238+
);
239+
connection.on(RECONNECT, () =>
240+
client
241+
._open(realtime._options.appId, _tag, deviceId, true)
242+
/**
243+
* 客户端连接恢复正常,该事件通常在 {@link Realtime#event:RECONNECT} 之后发生
244+
* @event IMClient#RECONNECT
245+
* @see Realtime#event:RECONNECT
246+
* @since 3.2.0
247+
*/
248+
/**
249+
* 客户端重新登录发生错误(网络连接已恢复,但重新登录错误)
250+
* @event IMClient#RECONNECT_ERROR
251+
* @since 3.2.0
252+
*/
253+
.then(
254+
() => client.emit(RECONNECT),
255+
error => client.emit(RECONNECT_ERROR, error)
256+
)
257+
);
258+
internal(client)._eventemitter.on(
259+
'beforeclose',
260+
() => {
261+
delete realtime._IMClients[client.id];
262+
if (realtime._firstIMClient === client) {
263+
delete realtime._firstIMClient;
264+
}
265+
},
266+
realtime
267+
);
268+
internal(client)._eventemitter.on(
269+
'close',
270+
() => {
271+
realtime._deregister(client);
272+
},
273+
realtime
274+
);
275+
return client
276+
._open(realtime._options.appId, _tag, deviceId, isReconnect)
277+
.then(() => {
278+
realtime._IMClients[client.id] = client;
279+
realtime._IMClientsCreationCount += 1;
280+
if (realtime._IMClientsCreationCount === 1) {
281+
client._omitPeerId(true);
282+
realtime._firstIMClient = client;
283+
} else if (
284+
realtime._IMClientsCreationCount > 1 &&
285+
realtime._firstIMClient
286+
) {
287+
realtime._firstIMClient._omitPeerId(false);
288+
}
289+
realtime._register(client);
290+
return client;
291+
})
292+
.catch(error => {
293+
delete realtime._IMClients[client.id];
294+
throw error;
295+
});
296+
})
297+
.finally(() => {
298+
realtime._deregisterPending(promise);
299+
});
286300
if (identity) {
287301
realtime._IMClients[id] = promise;
288302
}
303+
realtime._registerPending(promise);
289304
return promise;
290305
};
291306
Object.assign(realtime, {

src/realtime.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ export default class Realtime extends EventEmitter {
6060
options
6161
);
6262
this._cache = new Cache('endpoints');
63-
internal(this).clients = new Set();
63+
const _this = internal(this);
64+
_this.clients = new Set();
65+
_this.pendingClients = new Set();
6466
const mergedPlugins = [
6567
...ensureArray(Realtime.__preRegisteredPlugins),
6668
...ensureArray(plugins),
@@ -391,13 +393,22 @@ export default class Realtime extends EventEmitter {
391393
if (connection.can('resume')) connection.resume();
392394
}
393395

396+
_registerPending(value) {
397+
internal(this).pendingClients.add(value);
398+
}
399+
400+
_deregisterPending(client) {
401+
internal(this).pendingClients.delete(client);
402+
}
403+
394404
_register(client) {
395405
internal(this).clients.add(client);
396406
}
397407

398408
_deregister(client) {
399-
internal(this).clients.delete(client);
400-
if (internal(this).clients.size === 0) {
409+
const _this = internal(this);
410+
_this.clients.delete(client);
411+
if (_this.clients.size + _this.pendingClients.size === 0) {
401412
this._close();
402413
}
403414
}

0 commit comments

Comments
 (0)