Skip to content

Commit 7712876

Browse files
committed
fix: Fixed error removing already removed listeners
1 parent bf05e66 commit 7712876

File tree

1 file changed

+72
-14
lines changed

1 file changed

+72
-14
lines changed

src/TcpSocket.js

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,39 @@ const STATE = {
1010
CONNECTED: 2,
1111
};
1212

13+
class RemovableListener {
14+
/**
15+
* @param {import("react-native").EmitterSubscription} listener
16+
* @param {import("react-native").NativeEventEmitter} eventEmitter
17+
*/
18+
constructor(listener, eventEmitter) {
19+
this._listener = listener;
20+
this._eventEmitter = eventEmitter;
21+
this._removed = false;
22+
}
23+
24+
isRemoved() {
25+
return this._removed;
26+
}
27+
28+
remove() {
29+
this._eventEmitter.removeSubscription(this._listener);
30+
this._removed = true;
31+
}
32+
}
33+
1334
export default class TcpSocket {
1435
/**
1536
* Initialices a TcpSocket.
1637
*
17-
* @param {Number} id
38+
* @param {number} id
1839
* @param {import('react-native').NativeEventEmitter} eventEmitter
1940
*/
2041
constructor(id, eventEmitter) {
2142
this._id = id;
2243
this._eventEmitter = eventEmitter;
2344
this._state = STATE.DISCONNECTED;
45+
/** @type {RemovableListener[]} */
2446
this._listeners = [];
2547
}
2648

@@ -35,10 +57,16 @@ export default class TcpSocket {
3557
*/
3658
on(event, callback, context) {
3759
const newListener = this._selectListener(event, callback, context);
38-
this._listeners.push(newListener);
39-
return newListener;
60+
const removableListener = new RemovableListener(newListener, this._eventEmitter);
61+
this._listeners.push(removableListener);
62+
return removableListener;
4063
}
4164

65+
/**
66+
* @param {string} event
67+
* @param {function(any):void} callback
68+
* @param {any} [context]
69+
*/
4270
_selectListener(event, callback, context) {
4371
switch (event) {
4472
case 'data':
@@ -78,6 +106,10 @@ export default class TcpSocket {
78106
);
79107
}
80108

109+
/**
110+
* @param {{ host: string; port: number; timeout: number; }} options
111+
* @param {(address: string) => void} [callback]
112+
*/
81113
connect(options, callback) {
82114
this._registerEvents();
83115
// Normalize args
@@ -95,6 +127,10 @@ export default class TcpSocket {
95127
return this;
96128
}
97129

130+
/**
131+
* @param {number} msecs
132+
* @param {() => void} [wrapper]
133+
*/
98134
_activeTimer(msecs, wrapper) {
99135
if (this._timeout && this._timeout.handle) clearTimeout(this._timeout.handle);
100136

@@ -120,12 +156,16 @@ export default class TcpSocket {
120156
}
121157
}
122158

159+
/**
160+
* @param {number} msecs
161+
* @param {{ (...args: any[]): any; (...args: any[]): any; }} [callback]
162+
*/
123163
setTimeout(msecs, callback) {
124164
if (msecs === 0) {
125165
this._clearTimeout();
126166
if (callback) this._eventEmitter.removeListener('timeout', callback);
127167
} else {
128-
if (callback) this._eventEmitter.once('timeout', callback);
168+
if (callback) this._eventEmitter.once('timeout', callback, this);
129169

130170
this._activeTimer(msecs);
131171
}
@@ -136,6 +176,10 @@ export default class TcpSocket {
136176
return this._address;
137177
}
138178

179+
/**
180+
* @param {string | Buffer | Uint8Array} data
181+
* @param {BufferEncoding} [encoding]
182+
*/
139183
end(data, encoding) {
140184
if (this._destroyed) return;
141185
if (data) this.write(data, encoding);
@@ -153,14 +197,18 @@ export default class TcpSocket {
153197

154198
_registerEvents() {
155199
this.on('connect', (ev) => this._onConnect(ev.address));
156-
this.on('close', (ev) => this._onClose(ev.hadError));
157-
this.on('error', (ev) => this._onError(ev.error));
200+
this.on('close', () => this._onClose());
201+
this.on('error', () => this._onError());
158202
}
159203

160204
_unregisterEvents() {
161-
this._listeners.forEach((listener) => listener.remove());
205+
this._listeners.forEach((listener) => (listener.isRemoved() ? listener.remove() : null));
206+
this._listeners = [];
162207
}
163208

209+
/**
210+
* @param {string} address
211+
*/
164212
_onConnect(address) {
165213
this.setConnected(address);
166214
}
@@ -176,8 +224,8 @@ export default class TcpSocket {
176224
/**
177225
*
178226
* @param {string | Buffer | Uint8Array} buffer
179-
* @param {string} encoding
180-
* @param {Function} callback
227+
* @param {BufferEncoding} [encoding]
228+
* @param {(error?: string) => void} [callback]
181229
*/
182230
write(buffer, encoding, callback) {
183231
const self = this;
@@ -193,13 +241,23 @@ export default class TcpSocket {
193241
`Invalid data, chunk must be a string or buffer, not ${typeof buffer}`
194242
);
195243

196-
Sockets.write(this._id, str, function(err) {
197-
if (self._timeout) self._activeTimer(self._timeout.msecs);
198-
if (err) return callback(err);
199-
callback();
200-
});
244+
Sockets.write(
245+
this._id,
246+
str,
247+
/**
248+
* @param {string} err
249+
*/
250+
function(err) {
251+
if (self._timeout) self._activeTimer(self._timeout.msecs);
252+
if (err) return callback(err);
253+
callback();
254+
}
255+
);
201256
}
202257

258+
/**
259+
* @param {string} address
260+
*/
203261
setConnected(address) {
204262
this._state = STATE.CONNECTED;
205263
this._address = address;

0 commit comments

Comments
 (0)