Skip to content

Commit

Permalink
fix: fix socket.disconnect().connect() usage
Browse files Browse the repository at this point in the history
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: #1014

Backported from 99c2cb8
  • Loading branch information
darrachequesne committed Jun 25, 2022
1 parent b1d7eef commit e7a9d25
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
10 changes: 2 additions & 8 deletions lib/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -481,13 +481,7 @@ Manager.prototype.disconnect = function () {
debug('disconnect');
this.skipReconnect = true;
this.reconnecting = false;
if ('opening' === this.readyState) {
// `onclose` will not fire because
// an open event never happened
this.cleanup();
}
this.backoff.reset();
this.readyState = 'closed';
this.onclose('forced close');
if (this.engine) this.engine.close();
};

Expand All @@ -498,7 +492,7 @@ Manager.prototype.disconnect = function () {
*/

Manager.prototype.onclose = function (reason) {
debug('onclose');
debug('closed due to %s', reason);

this.cleanup();
this.backoff.reset();
Expand Down
20 changes: 20 additions & 0 deletions test/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,24 @@ describe('socket', function () {
done();
});
});

it('should properly disconnect then reconnect', (done) => {
const socket = io('/', { forceNew: true, transports: ['websocket'] });

let count = 0;

socket.once('connect', () => {
socket.disconnect().connect();
});

socket.on('disconnect', () => {
count++;
});

setTimeout(() => {
expect(count).to.eql(1);
socket.disconnect();
done();
}, 200);
});
});

0 comments on commit e7a9d25

Please sign in to comment.