Skip to content

Commit ce4475b

Browse files
committed
Dispose handlers
1 parent f580bf8 commit ce4475b

15 files changed

+433
-103
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "jsonrpc-bidirectional",
33
"description": "Bidirectional JSONRPC over web sockets or HTTP with extensive plugin support.",
4-
"version": "8.9.9",
4+
"version": "9.0.0",
55
"scripts": {
66
"build": "node --experimental-worker build.js",
77
"prepublish": "node --experimental-worker build.js && node --expose-gc --max-old-space-size=1024 --experimental-worker tests/main.js",

src/Client.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ const assert = require("assert");
1616

1717

1818
/**
19-
*
19+
* @event beforeJSONEncode outgoingRequest
20+
* @event afterJSONEncode outgoingRequest
21+
* @event makeRequest outgoingRequest
22+
* @event beforeJSONDecode outgoingRequest
23+
* @event afterJSONDecode outgoingRequest
24+
* @event exceptionCatch outgoingRequest
25+
* @event disposed
2026
*/
21-
module.exports =
2227
class Client extends EventEmitter
2328
{
2429
/**
@@ -56,6 +61,28 @@ class Client extends EventEmitter
5661
}
5762

5863

64+
/**
65+
* @param {{bCallPluginDispose:boolean}} param0
66+
*
67+
* @returns {null}
68+
*/
69+
dispose({bCallPluginDispose = true} = {})
70+
{
71+
for(let i = this._arrPlugins.length - 1; i >= 0; i--)
72+
{
73+
if(bCallPluginDispose)
74+
{
75+
this._arrPlugins[i].dispose();
76+
}
77+
78+
this._arrPlugins.splice(i, 1);
79+
}
80+
this._arrPlugins.splice(0);
81+
82+
this.emit("disposed", {bCallPluginDispose});
83+
}
84+
85+
5986
/**
6087
* This is the function used to set the HTTP credentials.
6188
*
@@ -454,3 +481,6 @@ class Client extends EventEmitter
454481
}
455482
}
456483
};
484+
485+
486+
module.exports = Client;

src/ClientPluginBase.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
const EventEmitter = require("events");
2+
3+
14
/**
25
* JSONRPC.Client plugins need to extend this class.
36
*/
4-
module.exports =
5-
class ClientPluginBase
7+
class ClientPluginBase extends EventEmitter
68
{
79
/**
810
* Gives a chance to modify the client request object before sending it out.
@@ -77,4 +79,16 @@ class ClientPluginBase
7779
{
7880
// outgoingRequest.callResult is available here, and it is a subclass of Error.
7981
}
82+
83+
84+
/**
85+
* @returns {null}
86+
*/
87+
dispose()
88+
{
89+
this.emit("disposed");
90+
}
8091
};
92+
93+
94+
module.exports = ClientPluginBase;

src/EndpointBase.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ catch(error)
2323
*
2424
* Methods defined by subclasses, which are to be exported through RPC,
2525
* must each return a single Promise object or simply decorated with async so they are awaitable.
26+
*
27+
* @event disposed
2628
*/
2729
class EndpointBase extends EventEmitter
2830
{
@@ -47,6 +49,15 @@ class EndpointBase extends EventEmitter
4749
}
4850

4951

52+
/**
53+
* @returns {null}
54+
*/
55+
dispose()
56+
{
57+
this.emit("disposed");
58+
}
59+
60+
5061
/**
5162
* Brings methods of some class instance into this class (mixins, traits).
5263
*

src/Plugins/Client/Cache.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ class Cache extends JSONRPC.ClientPluginBase
3535
}
3636

3737

38+
dispose()
39+
{
40+
this.clear();
41+
}
42+
43+
3844
clear()
3945
{
4046
this.mapCache.clear();

src/Plugins/Client/ElectronIPCTransport.js

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class ElectronIPCTransport extends JSONRPC.ClientPluginBase
3636
super();
3737

3838

39+
this._arrDisposeCalls = [];
40+
41+
3942
// JSONRPC call ID as key, {promise: {Promise}, fnResolve: {Function}, fnReject: {Function}, outgoingRequest: {OutgoingRequest}} as values.
4043
this._objBrowserWindowRequestsPromises = {};
4144

@@ -46,10 +49,28 @@ class ElectronIPCTransport extends JSONRPC.ClientPluginBase
4649
// eslint-disable-next-line no-undef
4750
this._strChannel = "jsonrpc_winid_" + (browserWindow ? browserWindow.id : (window || self).require("electron").remote.getCurrentWindow().id);
4851

52+
4953
this._setupIPCTransport();
5054
}
5155

5256

57+
/**
58+
* @returns {null}
59+
*/
60+
dispose()
61+
{
62+
for(const fnDispose of this._arrDisposeCalls)
63+
{
64+
fnDispose();
65+
}
66+
this._arrDisposeCalls.slice(0);
67+
68+
this.rejectAllPromises();
69+
70+
super.dispose();
71+
}
72+
73+
5374
/**
5475
* @returns {BrowserWindow|null}
5576
*/
@@ -227,32 +248,33 @@ class ElectronIPCTransport extends JSONRPC.ClientPluginBase
227248
{
228249
if(!this._bBidirectionalMode)
229250
{
251+
const fnOnChannel = async(event, objJSONRPCRequest) => {
252+
await this.processResponse(objJSONRPCRequest);
253+
};
254+
230255
// eslint-disable-next-line no-undef
231-
(window || self).require("electron").ipcRenderer.on(
232-
this._strChannel,
233-
async(event, objJSONRPCRequest) => {
234-
await this.processResponse(objJSONRPCRequest);
235-
}
236-
);
256+
(window || self).require("electron").ipcRenderer.on(this._strChannel, fnOnChannel);
257+
258+
// eslint-disable-next-line no-undef
259+
this._arrDisposeCalls.push(() => { (window || self).require("electron").ipcRenderer.removeListener(this._strChannel, fnOnChannel); });
237260
}
238261
}
239262
else
240263
{
241-
this._browserWindow.on(
242-
"closed",
243-
() => {
244-
this.rejectAllPromises(new Error(`BrowserWindow ${this.browserWindow.id} closed`));
245-
}
246-
);
264+
const fnOnClosed = () => {
265+
this.rejectAllPromises(new Error(`BrowserWindow ${this.browserWindow.id} closed`));
266+
};
267+
this._browserWindow.on("closed", fnOnClosed);
268+
this._arrDisposeCalls.push(() => { this._browserWindow.removeListener("closed", fnOnClosed); });
247269

248270
if(!this._bBidirectionalMode)
249271
{
250-
electron.ipcMain.on(
251-
this.channel,
252-
async(event, objJSONRPCRequest) => {
253-
await this.processResponse(objJSONRPCRequest);
254-
}
255-
);
272+
const fnOnChannel = async(event, objJSONRPCRequest) => {
273+
await this.processResponse(objJSONRPCRequest);
274+
};
275+
276+
electron.ipcMain.on(this.channel, fnOnChannel);
277+
this._arrDisposeCalls.push(() => { electron.ipcMain.removeListener(this.channel, fnOnChannel); });
256278
}
257279
}
258280
}

src/Plugins/Client/WebRTCTransport.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ class WebRTCTransport extends JSONRPC.ClientPluginBase
2929
}
3030

3131

32+
/**
33+
* @returns {null}
34+
*/
35+
dispose()
36+
{
37+
try
38+
{
39+
this._dataChannel.close();
40+
}
41+
catch(error)
42+
{
43+
console.error(error);
44+
}
45+
46+
super.dispose();
47+
}
48+
49+
3250
/**
3351
* @returns {RTCDataChannel}
3452
*/

src/Plugins/Client/WebSocketTransport.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@ class WebSocketTransport extends JSONRPC.ClientPluginBase
3232
}
3333

3434

35+
/**
36+
* @returns {null}
37+
*/
38+
dispose()
39+
{
40+
try
41+
{
42+
this._webSocket.close();
43+
}
44+
catch(error)
45+
{
46+
console.error(error);
47+
}
48+
49+
super.dispose();
50+
}
51+
52+
3553
/**
3654
* @returns {WebSocket}
3755
*/

src/Plugins/Client/WorkerThreadTransport.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class WorkerThreadTransport extends JSONRPC.ClientPluginBase
2525
super();
2626

2727

28+
this._arrDisposeCalls = [];
29+
30+
2831
assert(threadWorker instanceof Threads.Worker || threadWorker === Threads);
2932

3033

@@ -36,11 +39,28 @@ class WorkerThreadTransport extends JSONRPC.ClientPluginBase
3639
this._threadWorker = threadWorker;
3740
this._threadID = threadWorker.threadId;
3841

39-
42+
4043
this._setupThreadWorker();
4144
}
4245

4346

47+
/**
48+
* @returns {null}
49+
*/
50+
dispose()
51+
{
52+
for(const fnDispose of this._arrDisposeCalls)
53+
{
54+
fnDispose();
55+
}
56+
this._arrDisposeCalls.slice(0);
57+
58+
this.rejectAllPromises();
59+
60+
super.dispose();
61+
}
62+
63+
4464
/**
4565
* @returns {worker_threads.Worker|worker_threads}
4666
*/
@@ -251,20 +271,27 @@ class WorkerThreadTransport extends JSONRPC.ClientPluginBase
251271
if(Threads.isMainThread)
252272
{
253273
this._threadWorker.on("exit", fnOnExit);
274+
this._arrDisposeCalls.push(() => { this._threadWorker.removeListener("exit", fnOnExit); });
275+
254276
this._threadWorker.on("error", fnOnError);
277+
this._arrDisposeCalls.push(() => { this._threadWorker.removeListener("error", fnOnError); });
278+
255279

256280
if(!this._bBidirectionalMode)
257281
{
258282
this._threadWorker.on("message", fnOnMessage);
283+
this._arrDisposeCalls.push(() => { this._threadWorker.removeListener("message", fnOnMessage); });
259284
}
260285
}
261286
else
262287
{
263288
Threads.parentPort.on("close", fnOnClose);
289+
this._arrDisposeCalls.push(() => { Threads.parentPort.removeListener("close", fnOnClose); });
264290

265291
if(!this._bBidirectionalMode)
266292
{
267293
Threads.parentPort.on("message", fnOnMessage);
294+
this._arrDisposeCalls.push(() => { Threads.parentPort.removeListener("message", fnOnMessage); });
268295
}
269296
}
270297
}

0 commit comments

Comments
 (0)