bare-rpc 1.3.3 → 1.3.5

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.d.ts CHANGED
@@ -95,6 +95,8 @@ declare class RPCOutgoingStream extends Writable {
95
95
  }
96
96
 
97
97
  interface RPC {
98
+ readonly idle: boolean
99
+
98
100
  event(command: number): RPCOutgoingEvent
99
101
  request(command: number): RPCOutgoingRequest
100
102
  }
package/index.js CHANGED
@@ -42,6 +42,19 @@ module.exports = exports = class RPC {
42
42
  this._stream.on('error', this._onerror).on('data', this._ondata).on('drain', this._ondrain)
43
43
  }
44
44
 
45
+ // Whether there are no requests or responses currently in flight. Useful for
46
+ // determining when it is safe to tear down the underlying stream.
47
+ get idle() {
48
+ return (
49
+ this._outgoingRequests.size === 0 &&
50
+ this._outgoingResponses.size === 0 &&
51
+ this._incomingRequests.size === 0 &&
52
+ this._incomingResponses.size === 0 &&
53
+ this._pendingRequests.size === 0 &&
54
+ this._pendingResponses.size === 0
55
+ )
56
+ }
57
+
45
58
  event(command) {
46
59
  return new OutgoingEvent(this, command)
47
60
  }
@@ -90,6 +103,8 @@ module.exports = exports = class RPC {
90
103
  this._outgoingRequests.set(request.id, request)
91
104
 
92
105
  request._requestStream = new OutgoingStream(this, request, t.REQUEST, opts)
106
+
107
+ request._requestStream.on('close', () => this._gcOutgoingRequest(request))
93
108
  } else {
94
109
  this._incomingRequests.set(request.id, request)
95
110
 
@@ -114,12 +129,19 @@ module.exports = exports = class RPC {
114
129
  this._outgoingResponses.set(request.id, request)
115
130
 
116
131
  request._responseStream = new OutgoingStream(this, request, t.RESPONSE, opts)
132
+
133
+ request._responseStream.on('close', () => this._outgoingResponses.delete(request.id))
117
134
  } else {
118
135
  this._incomingResponses.set(request.id, request)
119
136
 
120
137
  request._responseStream = new IncomingStream(this, request, t.RESPONSE, opts)
121
138
 
122
- request._responseStream.on('close', () => this._incomingResponses.delete(request.id))
139
+ request._responseStream.on('close', () => {
140
+ this._incomingResponses.delete(request.id)
141
+
142
+ request._responded = true
143
+ this._gcOutgoingRequest(request)
144
+ })
123
145
  }
124
146
  }
125
147
 
@@ -133,6 +155,17 @@ module.exports = exports = class RPC {
133
155
  })
134
156
  }
135
157
 
158
+ _gcOutgoingRequest(request) {
159
+ // The entry must stay reachable for as long as an incoming message might
160
+ // still target it; until the response has settled and, if the request was
161
+ // streamed, until the outgoing request stream has closed. Either can be the
162
+ // last to arrive, so only remove the entry once both have completed.
163
+ if (!request._responded) return
164
+ if (request._requestStream !== null && !request._requestStream.destroyed) return
165
+
166
+ this._outgoingRequests.delete(request.id)
167
+ }
168
+
136
169
  _onerror(err) {
137
170
  this._ondrain(err)
138
171
 
@@ -226,8 +259,14 @@ module.exports = exports = class RPC {
226
259
  if (request === undefined) return
227
260
 
228
261
  if (message.error) {
262
+ request._responded = true
263
+ this._gcOutgoingRequest(request)
264
+
229
265
  request._reject(message.error)
230
266
  } else if (message.stream === 0) {
267
+ request._responded = true
268
+ this._gcOutgoingRequest(request)
269
+
231
270
  request._resolve(message.data)
232
271
  }
233
272
  }
package/lib/messages.js CHANGED
@@ -5,12 +5,12 @@ const errors = require('./errors')
5
5
  const error = {
6
6
  preencode(state, m) {
7
7
  c.utf8.preencode(state, m.message)
8
- c.utf8.preencode(state, String(m.code) || '')
8
+ c.utf8.preencode(state, m.code === undefined || m.code === null ? '' : String(m.code))
9
9
  c.int.preencode(state, Number(m.errno) || 0)
10
10
  },
11
11
  encode(state, m) {
12
12
  c.utf8.encode(state, m.message)
13
- c.utf8.encode(state, String(m.code) || '')
13
+ c.utf8.encode(state, m.code === undefined || m.code === null ? '' : String(m.code))
14
14
  c.int.encode(state, Number(m.errno) || 0)
15
15
  },
16
16
  decode(state) {
@@ -9,6 +9,8 @@ module.exports = class RPCOutgoingRequest {
9
9
  this.sent = false
10
10
  this.received = false
11
11
 
12
+ this._responded = false
13
+
12
14
  this._promise = new Promise((resolve, reject) => {
13
15
  this._resolve = resolve
14
16
  this._reject = reject
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-rpc",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "librpc ABI compatible RPC for Bare",
5
5
  "exports": {
6
6
  ".": {