bare-rpc 1.3.7 → 1.3.8

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/index.js CHANGED
@@ -29,6 +29,9 @@ module.exports = exports = class RPC {
29
29
  this._frame = -1
30
30
  this._draining = []
31
31
 
32
+ this._closed = false
33
+ this._error = null
34
+
32
35
  if (typeof onrequest === 'function') {
33
36
  onrequest = onrequest.bind(this)
34
37
  } else {
@@ -101,6 +104,11 @@ module.exports = exports = class RPC {
101
104
  }
102
105
 
103
106
  _sendRequest(request, data = null) {
107
+ // Once the channel has been torn down there is nowhere left to send the
108
+ // request. Skip registering it so that it never leaks into the maps; the
109
+ // awaiting reply is rejected through `RPCOutgoingRequest.reply()` instead.
110
+ if (this._closed) return
111
+
104
112
  this._outgoingRequests.set(request.id, request)
105
113
 
106
114
  this._sendMessage({
@@ -114,21 +122,33 @@ module.exports = exports = class RPC {
114
122
 
115
123
  _createRequestStream(request, isInitiator, opts) {
116
124
  if (isInitiator) {
117
- this._outgoingRequests.set(request.id, request)
118
-
119
125
  request._requestStream = new OutgoingStream(this, request, t.REQUEST, opts)
120
126
 
127
+ // Once the channel has been torn down there is nowhere left to open the
128
+ // stream, so destroy it right away rather than leave it hanging.
129
+ if (this._closed) return request._requestStream.destroy(this._error)
130
+
131
+ this._outgoingRequests.set(request.id, request)
132
+
121
133
  request._requestStream.on('close', () => this._gcOutgoingRequest(request))
122
134
  } else {
123
- this._incomingRequests.set(request.id, request)
124
-
125
135
  request._requestStream = new IncomingStream(this, request, t.REQUEST, opts)
126
136
 
137
+ if (this._closed) return request._requestStream.destroy(this._error)
138
+
139
+ this._incomingRequests.set(request.id, request)
140
+
127
141
  request._requestStream.on('close', () => this._incomingRequests.delete(request.id))
128
142
  }
129
143
  }
130
144
 
131
145
  _sendResponse(request, data) {
146
+ // Once the channel has been torn down there is nowhere left to send the
147
+ // response, so drop it rather than encode and write a message that would
148
+ // only be discarded. The reply is fire-and-forget, so there is nothing to
149
+ // settle.
150
+ if (this._closed) return
151
+
132
152
  this._sendMessage({
133
153
  type: t.RESPONSE,
134
154
  id: request.id,
@@ -140,16 +160,22 @@ module.exports = exports = class RPC {
140
160
 
141
161
  _createResponseStream(request, isInitiator, opts) {
142
162
  if (isInitiator) {
143
- this._outgoingResponses.set(request.id, request)
144
-
145
163
  request._responseStream = new OutgoingStream(this, request, t.RESPONSE, opts)
146
164
 
165
+ // Once the channel has been torn down there is nowhere left to open the
166
+ // stream, so destroy it right away rather than leave it hanging.
167
+ if (this._closed) return request._responseStream.destroy(this._error)
168
+
169
+ this._outgoingResponses.set(request.id, request)
170
+
147
171
  request._responseStream.on('close', () => this._outgoingResponses.delete(request.id))
148
172
  } else {
149
- this._incomingResponses.set(request.id, request)
150
-
151
173
  request._responseStream = new IncomingStream(this, request, t.RESPONSE, opts)
152
174
 
175
+ if (this._closed) return request._responseStream.destroy(this._error)
176
+
177
+ this._incomingResponses.set(request.id, request)
178
+
153
179
  request._responseStream.on('close', () => {
154
180
  this._incomingResponses.delete(request.id)
155
181
 
@@ -192,6 +218,11 @@ module.exports = exports = class RPC {
192
218
  }
193
219
 
194
220
  _teardown(err) {
221
+ // Mark the channel as closed so that any calls made from here on are
222
+ // rejected or destroyed immediately rather than left hanging.
223
+ this._closed = true
224
+ this._error = err
225
+
195
226
  this._ondrain(err)
196
227
 
197
228
  // Reject any request awaiting a plain reply. Requests whose response is
@@ -46,6 +46,12 @@ module.exports = class RPCOutgoingRequest {
46
46
 
47
47
  this.received = true
48
48
 
49
+ // If the channel was torn down before a response arrived there is nothing
50
+ // left to await, so reject with the teardown error rather than hang. This
51
+ // covers both requests sent after teardown and requests still awaiting a
52
+ // reply when teardown happens.
53
+ if (this.rpc._closed && !this._responded) this._reject(this.rpc._error)
54
+
49
55
  return encoding ? this._promise.then((data) => c.decode(encoding, data)) : this._promise
50
56
  }
51
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-rpc",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "description": "librpc ABI compatible RPC for Bare",
5
5
  "exports": {
6
6
  ".": {