bare-rpc 0.1.3 → 0.2.0

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
@@ -4,7 +4,7 @@ import {
4
4
  ReadableOptions,
5
5
  Writable,
6
6
  WritableOptions,
7
- PassThrough
7
+ Duplex
8
8
  } from 'bare-stream'
9
9
 
10
10
  declare const constants: {
@@ -24,11 +24,12 @@ declare const constants: {
24
24
  }
25
25
 
26
26
  interface RPCIncomingRequest {
27
- rpc: RPC
28
- id: number
29
- command: string
30
- data: Buffer
31
- sent: boolean
27
+ readonly rpc: RPC
28
+ readonly id: number
29
+ readonly command: number
30
+ readonly data: Buffer
31
+ readonly sent: boolean
32
+ readonly received: boolean
32
33
 
33
34
  reply(data: Buffer | string, encoding?: BufferEncoding): void
34
35
 
@@ -37,10 +38,16 @@ interface RPCIncomingRequest {
37
38
  }
38
39
 
39
40
  declare class RPCIncomingRequest {
40
- constructor(rpc: RPC, id: number, command: string, data: Buffer)
41
+ constructor(rpc: RPC, id: number, command: number, data: Buffer)
41
42
  }
42
43
 
43
44
  interface RPCOutgoingRequest {
45
+ readonly rpc: RPC
46
+ readonly id: number
47
+ readonly command: number
48
+ readonly sent: boolean
49
+ readonly received: boolean
50
+
44
51
  send(data: Buffer | string, encoding?: BufferEncoding): void
45
52
 
46
53
  reply(encoding?: BufferEncoding): Promise<Buffer>
@@ -50,7 +57,7 @@ interface RPCOutgoingRequest {
50
57
  }
51
58
 
52
59
  declare class RPCOutgoingRequest {
53
- constructor(rpc: RPC, command: string)
60
+ constructor(rpc: RPC, command: number)
54
61
  }
55
62
 
56
63
  declare class RPCIncomingStream extends Readable {
@@ -72,11 +79,11 @@ declare class RPCOutgoingStream extends Writable {
72
79
  }
73
80
 
74
81
  interface RPC {
75
- request(command: string): RPCOutgoingRequest
82
+ request(command: number): RPCOutgoingRequest
76
83
  }
77
84
 
78
85
  declare class RPC {
79
- constructor(stream: PassThrough, onrequest: (req: RPCIncomingRequest) => void)
86
+ constructor(stream: Duplex, onrequest: (req: RPCIncomingRequest) => void)
80
87
  }
81
88
 
82
89
  export = RPC
package/index.js CHANGED
@@ -7,8 +7,9 @@ const IncomingRequest = require('./lib/incoming-request')
7
7
  const IncomingStream = require('./lib/incoming-stream')
8
8
  const OutgoingRequest = require('./lib/outgoing-request')
9
9
  const OutgoingStream = require('./lib/outgoing-stream')
10
+ const CommandRouter = require('./lib/command-router')
10
11
 
11
- module.exports = class RPC {
12
+ module.exports = exports = class RPC {
12
13
  constructor(stream, onrequest) {
13
14
  this._stream = stream
14
15
 
@@ -23,14 +24,20 @@ module.exports = class RPC {
23
24
 
24
25
  this._buffer = null
25
26
 
26
- this._onrequest = onrequest.bind(this)
27
+ if (typeof onrequest === 'function') {
28
+ onrequest = onrequest.bind(this)
29
+ } else {
30
+ onrequest = onrequest._onrequest.bind(onrequest)
31
+ }
32
+
33
+ this._onrequest = onrequest
27
34
  this._ondata = this._ondata.bind(this)
28
35
 
29
36
  this._stream.on('data', this._ondata)
30
37
  }
31
38
 
32
39
  request(command) {
33
- return new OutgoingRequest(++this._id, this, command)
40
+ return new OutgoingRequest(this, ++this._id, command)
34
41
  }
35
42
 
36
43
  _sendMessage(message) {
@@ -357,3 +364,5 @@ module.exports = class RPC {
357
364
  stream.destroy(message.error)
358
365
  }
359
366
  }
367
+
368
+ exports.CommandRouter = CommandRouter
@@ -0,0 +1,49 @@
1
+ const c = require('compact-encoding')
2
+
3
+ module.exports = class RPCCommandRouter {
4
+ constructor(opts = {}) {
5
+ const { valueEncoding = c.raw } = opts
6
+
7
+ this._responders = new Map()
8
+ this._defaultValueEncoding = valueEncoding
9
+ }
10
+
11
+ respond(command, opts = {}, onrequest) {
12
+ if (typeof opts === 'function') {
13
+ onrequest = opts
14
+ opts = {}
15
+ }
16
+
17
+ const {
18
+ valueEncoding = this._defaultValueEncoding,
19
+ requestEncoding = valueEncoding,
20
+ responseEncoding = valueEncoding
21
+ } = opts
22
+
23
+ this._responders.set(command, {
24
+ onrequest,
25
+ requestEncoding,
26
+ responseEncoding
27
+ })
28
+ }
29
+
30
+ async _onrequest(req) {
31
+ const responder = this._responders.get(req.command)
32
+
33
+ if (responder === undefined) return
34
+
35
+ const { onrequest, requestEncoding, responseEncoding } = responder
36
+
37
+ let data = req.data
38
+
39
+ if (requestEncoding) data = c.decode(requestEncoding, data)
40
+
41
+ data = await onrequest(req, req.data)
42
+
43
+ if (req.sent) return
44
+
45
+ if (responseEncoding) data = c.encode(responseEncoding, data)
46
+
47
+ req.reply(data)
48
+ }
49
+ }
package/lib/errors.js CHANGED
@@ -19,4 +19,8 @@ module.exports = class RPCError extends Error {
19
19
  static ALREADY_SENT(msg) {
20
20
  return new RPCError(msg, 'ALREADY_SENT', RPCError.ALREADY_SENT)
21
21
  }
22
+
23
+ static ALREADY_RECEIVED(msg) {
24
+ return new RPCError(msg, 'ALREADY_RECEIVED', RPCError.ALREADY_RECEIVED)
25
+ }
22
26
  }
@@ -8,13 +8,17 @@ module.exports = class RPCIncomingRequest {
8
8
  this.command = command
9
9
  this.data = data
10
10
  this.sent = false
11
+ this.received = false
11
12
 
12
13
  this._requestStream = null
13
14
  this._responseStream = null
14
15
  }
15
16
 
16
17
  reply(data, encoding) {
17
- if (this.sent) throw errors.ALREADY_SENT('Response has already been sent')
18
+ if (this.sent) {
19
+ throw errors.ALREADY_SENT('Response has already been sent')
20
+ }
21
+
18
22
  this.sent = true
19
23
 
20
24
  this.rpc._sendResponse(
@@ -24,15 +28,25 @@ module.exports = class RPCIncomingRequest {
24
28
  }
25
29
 
26
30
  createResponseStream(opts = {}) {
27
- if (this._responseStream === null)
28
- this.rpc._createResponseStream(this, true, opts)
31
+ if (this.sent) {
32
+ throw errors.ALREADY_SENT('Response has already been sent')
33
+ }
34
+
35
+ this.sent = true
36
+
37
+ this.rpc._createResponseStream(this, true, opts)
29
38
 
30
39
  return this._responseStream
31
40
  }
32
41
 
33
42
  createRequestStream(opts = {}) {
34
- if (this._requestStream === null)
35
- this.rpc._createRequestStream(this, false, opts)
43
+ if (this.received) {
44
+ throw errors.ALREADY_RECEIVED('Request has already been received')
45
+ }
46
+
47
+ this.received = true
48
+
49
+ this.rpc._createRequestStream(this, false, opts)
36
50
 
37
51
  return this._requestStream
38
52
  }
package/lib/messages.js CHANGED
@@ -4,17 +4,17 @@ const errors = require('./errors')
4
4
 
5
5
  const request = {
6
6
  preencode(state, m) {
7
- c.utf8.preencode(state, m.command)
7
+ c.uint.preencode(state, m.command)
8
8
  c.uint.preencode(state, m.stream)
9
9
  if (m.stream === 0) c.buffer.preencode(state, m.data)
10
10
  },
11
11
  encode(state, m) {
12
- c.utf8.encode(state, m.command)
12
+ c.uint.encode(state, m.command)
13
13
  c.uint.encode(state, m.stream)
14
14
  if (m.stream === 0) c.buffer.encode(state, m.data)
15
15
  },
16
16
  decode(state, id) {
17
- const command = c.utf8.decode(state)
17
+ const command = c.uint.decode(state)
18
18
  const stream = c.uint.decode(state)
19
19
  const data = stream === 0 ? c.buffer.decode(state) : null
20
20
 
@@ -2,11 +2,12 @@ const b4a = require('b4a')
2
2
  const errors = require('./errors')
3
3
 
4
4
  module.exports = class RPCOutgoingRequest {
5
- constructor(id, rpc, command) {
6
- this.id = id
5
+ constructor(rpc, id, command) {
7
6
  this.rpc = rpc
7
+ this.id = id
8
8
  this.command = command
9
9
  this.sent = false
10
+ this.received = false
10
11
 
11
12
  this._promise = new Promise((resolve, reject) => {
12
13
  this._resolve = resolve
@@ -18,7 +19,10 @@ module.exports = class RPCOutgoingRequest {
18
19
  }
19
20
 
20
21
  send(data, encoding) {
21
- if (this.sent) throw errors.ALREADY_SENT('Request has already been sent')
22
+ if (this.sent) {
23
+ throw errors.ALREADY_SENT('Request has already been sent')
24
+ }
25
+
22
26
  this.sent = true
23
27
 
24
28
  this.rpc._sendRequest(
@@ -28,24 +32,38 @@ module.exports = class RPCOutgoingRequest {
28
32
  }
29
33
 
30
34
  reply(encoding) {
35
+ if (this.received) {
36
+ throw errors.ALREADY_RECEIVED('Response is already being received')
37
+ }
38
+
39
+ this.received = true
40
+
31
41
  return encoding && encoding !== 'buffer'
32
42
  ? this._promise.then((data) => b4a.toString(data, encoding))
33
43
  : this._promise
34
44
  }
35
45
 
36
46
  createRequestStream(opts = {}) {
37
- if (this._requestStream === null) {
38
- this.rpc._createRequestStream(this, true, opts)
47
+ if (this.sent) {
48
+ throw errors.ALREADY_SENT('Request has already been sent')
39
49
  }
40
50
 
51
+ this.sent = true
52
+
53
+ this.rpc._createRequestStream(this, true, opts)
54
+
41
55
  return this._requestStream
42
56
  }
43
57
 
44
58
  createResponseStream(opts = {}) {
45
- if (this._requestStream === null) {
46
- this.rpc._createResponseStream(this, false, opts)
59
+ if (this.received) {
60
+ throw errors.ALREADY_RECEIVED('Response has already been received')
47
61
  }
48
62
 
63
+ this.received = true
64
+
65
+ this.rpc._createResponseStream(this, false, opts)
66
+
49
67
  return this._responseStream
50
68
  }
51
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-rpc",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "librpc ABI compatible RPC for Bare",
5
5
  "exports": {
6
6
  ".": {