starpc 0.6.1 → 0.7.1

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/Makefile CHANGED
@@ -106,6 +106,7 @@ gents: $(PROTOWRAP) node_modules
106
106
  --ts_proto_out=$$(pwd)/vendor \
107
107
  --ts_proto_opt=esModuleInterop=true \
108
108
  --ts_proto_opt=fileSuffix=.pb \
109
+ --ts_proto_opt=importSuffix=.js \
109
110
  --ts_proto_opt=forceLong=long \
110
111
  --ts_proto_opt=oneof=unions \
111
112
  --ts_proto_opt=outputServices=default,outputServices=generic-definitions \
package/README.md CHANGED
@@ -121,7 +121,7 @@ import { pushable } from 'it-pushable'
121
121
  const mux = createMux()
122
122
  const echoer = new EchoerServer()
123
123
  mux.register(createHandler(EchoerDefinition, echoer))
124
- const server = new Server(mux)
124
+ const server = new Server(mux.lookupMethodFunc)
125
125
 
126
126
  const clientConn = new Conn()
127
127
  const serverConn = new Conn(server)
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { pipe } from 'it-pipe';
2
+ import { createHandler, createMux, Server, Client, Conn } from '../srpc';
3
+ import { EchoerDefinition, EchoerServer, runClientTest } from '../echo';
4
+ import { runRpcStreamTest } from '../echo/client-test';
5
+ async function runRPC() {
6
+ const mux = createMux();
7
+ const server = new Server(mux.lookupMethodFunc);
8
+ const echoer = new EchoerServer(server);
9
+ mux.register(createHandler(EchoerDefinition, echoer));
10
+ const clientConn = new Conn();
11
+ const serverConn = new Conn(server);
12
+ pipe(clientConn, serverConn, clientConn);
13
+ const client = new Client(clientConn.buildOpenStreamFunc());
14
+ await runRpcStreamTest(client);
15
+ await runClientTest(client);
16
+ }
17
+ runRPC()
18
+ .then(() => {
19
+ console.log('finished successfully');
20
+ })
21
+ .catch((err) => {
22
+ console.error(err);
23
+ process.exit(1);
24
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import { WebSocketConn } from '../srpc/websocket.js';
2
+ import { runClientTest, runRpcStreamTest } from '../echo/client-test.js';
3
+ import WebSocket from 'isomorphic-ws';
4
+ async function runRPC() {
5
+ const addr = 'ws://localhost:5000/demo';
6
+ console.log(`Connecting to ${addr}`);
7
+ const ws = new WebSocket(addr);
8
+ const channel = new WebSocketConn(ws);
9
+ const client = channel.buildClient();
10
+ console.log('Running client test via WebSocket..');
11
+ await runClientTest(client);
12
+ console.log('Running RpcStream test via WebSocket..');
13
+ await runRpcStreamTest(client);
14
+ }
15
+ runRPC()
16
+ .then(() => {
17
+ process.exit(0);
18
+ })
19
+ .catch((err) => {
20
+ console.error(err);
21
+ process.exit(1);
22
+ });
@@ -1,11 +1,16 @@
1
1
  import { InvokeFn, Handler } from './handler';
2
+ export declare type LookupMethod = (serviceID: string, methodID: string) => Promise<InvokeFn | null>;
2
3
  export interface Mux {
3
- register(handler: Handler): void;
4
4
  lookupMethod(serviceID: string, methodID: string): Promise<InvokeFn | null>;
5
5
  }
6
- export declare function createMux(): Mux;
6
+ export declare function createMux(): StaticMux;
7
7
  export declare class StaticMux implements Mux {
8
8
  private services;
9
+ private lookups;
10
+ get lookupMethodFunc(): LookupMethod;
9
11
  register(handler: Handler): void;
12
+ registerLookupMethod(lookupMethod: LookupMethod): void;
10
13
  lookupMethod(serviceID: string, methodID: string): Promise<InvokeFn | null>;
14
+ private lookupViaMap;
15
+ private lookupViaLookups;
11
16
  }
package/dist/srpc/mux.js CHANGED
@@ -1,4 +1,4 @@
1
- // createMux builds a new Mux.
1
+ // createMux builds a new StaticMux.
2
2
  export function createMux() {
3
3
  return new StaticMux();
4
4
  }
@@ -8,6 +8,13 @@ export class StaticMux {
8
8
  constructor() {
9
9
  // services contains a mapping from service id to handlers.
10
10
  this.services = {};
11
+ // lookups is the list of lookup methods to call.
12
+ // called if the method is not resolved by the services list.
13
+ this.lookups = [];
14
+ }
15
+ // lookupMethodFunc implements the LookupMethod type.
16
+ get lookupMethodFunc() {
17
+ return this.lookupMethod.bind(this);
11
18
  }
12
19
  register(handler) {
13
20
  const serviceID = handler?.getServiceID();
@@ -21,10 +28,21 @@ export class StaticMux {
21
28
  }
22
29
  this.services[serviceID] = serviceMethods;
23
30
  }
31
+ // registerLookupMethod registers a extra lookup function to the mux.
32
+ registerLookupMethod(lookupMethod) {
33
+ this.lookups.push(lookupMethod);
34
+ }
24
35
  async lookupMethod(serviceID, methodID) {
25
- if (!serviceID) {
26
- return null;
36
+ if (serviceID) {
37
+ const invokeFn = await this.lookupViaMap(serviceID, methodID);
38
+ if (invokeFn) {
39
+ return invokeFn;
40
+ }
27
41
  }
42
+ return await this.lookupViaLookups(serviceID, methodID);
43
+ }
44
+ // lookupViaMap looks up the method via the services map.
45
+ async lookupViaMap(serviceID, methodID) {
28
46
  const serviceMethods = this.services[serviceID];
29
47
  if (!serviceMethods) {
30
48
  return null;
@@ -35,4 +53,14 @@ export class StaticMux {
35
53
  }
36
54
  return await handler.lookupMethod(serviceID, methodID);
37
55
  }
56
+ // lookupViaLookups looks up the method via the lookup funcs.
57
+ async lookupViaLookups(serviceID, methodID) {
58
+ for (const lookupMethod of this.lookups) {
59
+ const invokeFn = await lookupMethod(serviceID, methodID);
60
+ if (invokeFn) {
61
+ return invokeFn;
62
+ }
63
+ }
64
+ return null;
65
+ }
38
66
  }
@@ -1,9 +1,9 @@
1
1
  import type { CallData, CallStart } from './rpcproto.pb.js';
2
2
  import { CommonRPC } from './common-rpc.js';
3
- import { Mux } from './mux.js';
3
+ import { LookupMethod } from './mux.js';
4
4
  export declare class ServerRPC extends CommonRPC {
5
- private mux;
6
- constructor(mux: Mux);
5
+ private lookupMethod;
6
+ constructor(lookupMethod: LookupMethod);
7
7
  handleCallStart(packet: Partial<CallStart>): Promise<void>;
8
8
  handleCallData(packet: Partial<CallData>): Promise<void>;
9
9
  private invokeRPC;
@@ -1,9 +1,9 @@
1
1
  import { CommonRPC } from './common-rpc.js';
2
2
  // ServerRPC is an ongoing RPC from the server side.
3
3
  export class ServerRPC extends CommonRPC {
4
- constructor(mux) {
4
+ constructor(lookupMethod) {
5
5
  super();
6
- this.mux = mux;
6
+ this.lookupMethod = lookupMethod;
7
7
  }
8
8
  // handleCallStart handles a CallStart cket.
9
9
  async handleCallStart(packet) {
@@ -15,7 +15,7 @@ export class ServerRPC extends CommonRPC {
15
15
  if (!this.service || !this.method) {
16
16
  throw new Error('rpcService and rpcMethod cannot be empty');
17
17
  }
18
- const methodDef = await this.mux.lookupMethod(this.service, this.method);
18
+ const methodDef = await this.lookupMethod(this.service, this.method);
19
19
  if (!methodDef) {
20
20
  throw new Error(`not found: ${this.service}/${this.method}`);
21
21
  }
@@ -1,13 +1,13 @@
1
1
  import { Stream } from '@libp2p/interface-connection';
2
2
  import { Duplex } from 'it-stream-types';
3
- import { Mux } from './mux.js';
3
+ import { LookupMethod } from './mux.js';
4
4
  import { ServerRPC } from './server-rpc.js';
5
5
  import { Packet } from './rpcproto.pb.js';
6
6
  import { StreamHandler } from './conn.js';
7
7
  import { RpcStreamHandler } from '../rpcstream/rpcstream.js';
8
8
  export declare class Server implements StreamHandler {
9
- private mux;
10
- constructor(mux: Mux);
9
+ private lookupMethod;
10
+ constructor(lookupMethod: LookupMethod);
11
11
  get rpcStreamHandler(): RpcStreamHandler;
12
12
  startRpc(): ServerRPC;
13
13
  handleStream(stream: Stream): ServerRPC;
@@ -3,8 +3,8 @@ import { ServerRPC } from './server-rpc.js';
3
3
  import { parseLengthPrefixTransform, prependLengthPrefixTransform, decodePacketSource, encodePacketSource, } from './packet.js';
4
4
  // Server implements the SRPC server in TypeScript with a Mux.
5
5
  export class Server {
6
- constructor(mux) {
7
- this.mux = mux;
6
+ constructor(lookupMethod) {
7
+ this.lookupMethod = lookupMethod;
8
8
  }
9
9
  // rpcStreamHandler implements the RpcStreamHandler interface.
10
10
  get rpcStreamHandler() {
@@ -13,7 +13,7 @@ export class Server {
13
13
  // startRpc starts a new server-side RPC.
14
14
  // the returned RPC handles incoming Packets.
15
15
  startRpc() {
16
- return new ServerRPC(this.mux);
16
+ return new ServerRPC(this.lookupMethod);
17
17
  }
18
18
  // handleStream handles an incoming Uint8Array message duplex.
19
19
  handleStream(stream) {
package/e2e/e2e.ts CHANGED
@@ -5,7 +5,7 @@ import { runRpcStreamTest } from '../echo/client-test'
5
5
 
6
6
  async function runRPC() {
7
7
  const mux = createMux()
8
- const server = new Server(mux)
8
+ const server = new Server(mux.lookupMethodFunc)
9
9
  const echoer = new EchoerServer(server)
10
10
  mux.register(createHandler(EchoerDefinition, echoer))
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -34,7 +34,8 @@
34
34
  },
35
35
  "scripts": {
36
36
  "build": "rimraf ./dist && tsc --project tsconfig.build.json --outDir ./dist/",
37
- "check": "tsc",
37
+ "check": "npm run typecheck",
38
+ "typecheck": "tsc --noEmit",
38
39
  "deps": "depcheck --ignores 'bufferutil,utf-8-validate'",
39
40
  "codegen": "npm run gen",
40
41
  "ci": "npm run build && npm run lint:js && npm run lint:go",
@@ -58,16 +59,16 @@
58
59
  "singleQuote": true
59
60
  },
60
61
  "devDependencies": {
61
- "@typescript-eslint/eslint-plugin": "^5.30.3",
62
- "@typescript-eslint/parser": "^5.30.3",
62
+ "@typescript-eslint/eslint-plugin": "^5.30.5",
63
+ "@typescript-eslint/parser": "^5.30.5",
63
64
  "bufferutil": "^4.0.6",
64
65
  "depcheck": "^1.4.3",
65
66
  "esbuild": "^0.14.48",
66
- "eslint": "^8.18.0",
67
+ "eslint": "^8.19.0",
67
68
  "eslint-config-prettier": "^8.5.0",
68
69
  "prettier": "^2.7.1",
69
70
  "rimraf": "^3.0.2",
70
- "ts-proto": "^1.116.1",
71
+ "ts-proto": "^1.117.0",
71
72
  "typescript": "^4.7.4",
72
73
  "utf-8-validate": "^5.0.9"
73
74
  },
@@ -1,8 +1,16 @@
1
1
  diff --git a/node_modules/ts-poet/build/Import.js b/node_modules/ts-poet/build/Import.js
2
- index b92bea3..608add9 100644
2
+ index b92bea3..d35c845 100644
3
3
  --- a/node_modules/ts-poet/build/Import.js
4
4
  +++ b/node_modules/ts-poet/build/Import.js
5
- @@ -293,6 +293,14 @@ function emitImports(imports, ourModulePath, importMappings) {
5
+ @@ -26,6 +26,7 @@ exports.sameModule = exports.maybeRelativePath = exports.emitImports = exports.S
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ const path = __importStar(require("path"));
8
+ const Node_1 = require("./Node");
9
+ +const fs = require('fs');
10
+ const typeImportMarker = '(?:t:)?';
11
+ const fileNamePattern = '(?:[a-zA-Z0-9._-]+)';
12
+ const modulePattern = `@?(?:(?:${fileNamePattern}(?:/${fileNamePattern})*))`;
13
+ @@ -293,6 +294,16 @@ function emitImports(imports, ourModulePath, importMappings) {
6
14
  return '';
7
15
  }
8
16
  let result = '';
@@ -13,11 +21,13 @@ index b92bea3..608add9 100644
13
21
  + // github.com/aperturerobotics/protobuf-project/example/example -> ./example/example
14
22
  + if (thisProject && ourModuleImportPath.startsWith(thisProject)) {
15
23
  + ourModuleImportPath = './' + ourModuleImportPath.substr(thisProject.length + 1);
24
+ + } else {
25
+ + ourModuleImportPath = './vendor/' + ourModuleImportPath;
16
26
  + }
17
27
  const augmentImports = lodash_1.default.groupBy(filterInstances(imports, Augmented), (a) => a.augmented);
18
28
  // Group the imports by source module they're imported from
19
29
  const importsByModule = lodash_1.default.groupBy(imports.filter((it) => it.source !== undefined &&
20
- @@ -307,7 +315,14 @@ function emitImports(imports, ourModulePath, importMappings) {
30
+ @@ -307,7 +318,14 @@ function emitImports(imports, ourModulePath, importMappings) {
21
31
  if (modulePath in importMappings) {
22
32
  modulePath = importMappings[modulePath];
23
33
  }
package/srpc/mux.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  import { InvokeFn, Handler } from './handler'
2
2
 
3
+ // LookupMethod is a function to lookup a RPC method.
4
+ export type LookupMethod = (serviceID: string, methodID: string) => Promise<InvokeFn | null>
5
+
3
6
  // Mux contains a set of <service, method> handlers.
4
7
  export interface Mux {
5
- // register registers a new RPC method handler.
6
- register(handler: Handler): void
7
8
  // lookupMethod looks up the method matching the service & method ID.
8
9
  // returns null if not found.
9
10
  lookupMethod(serviceID: string, methodID: string): Promise<InvokeFn | null>
10
11
  }
11
12
 
12
- // createMux builds a new Mux.
13
- export function createMux(): Mux {
13
+ // createMux builds a new StaticMux.
14
+ export function createMux(): StaticMux {
14
15
  return new StaticMux()
15
16
  }
16
17
 
@@ -22,6 +23,14 @@ type staticMuxMethods = { [methodID: string]: Handler }
22
23
  export class StaticMux implements Mux {
23
24
  // services contains a mapping from service id to handlers.
24
25
  private services: { [id: string]: staticMuxMethods } = {}
26
+ // lookups is the list of lookup methods to call.
27
+ // called if the method is not resolved by the services list.
28
+ private lookups: LookupMethod[] = []
29
+
30
+ // lookupMethodFunc implements the LookupMethod type.
31
+ public get lookupMethodFunc(): LookupMethod {
32
+ return this.lookupMethod.bind(this)
33
+ }
25
34
 
26
35
  public register(handler: Handler): void {
27
36
  const serviceID = handler?.getServiceID()
@@ -36,13 +45,27 @@ export class StaticMux implements Mux {
36
45
  this.services[serviceID] = serviceMethods
37
46
  }
38
47
 
48
+ // registerLookupMethod registers a extra lookup function to the mux.
49
+ public registerLookupMethod(lookupMethod: LookupMethod) {
50
+ this.lookups.push(lookupMethod)
51
+ }
52
+
39
53
  public async lookupMethod(
40
54
  serviceID: string,
41
55
  methodID: string
42
56
  ): Promise<InvokeFn | null> {
43
- if (!serviceID) {
44
- return null
57
+ if (serviceID) {
58
+ const invokeFn = await this.lookupViaMap(serviceID, methodID)
59
+ if (invokeFn) {
60
+ return invokeFn
61
+ }
45
62
  }
63
+
64
+ return await this.lookupViaLookups(serviceID, methodID)
65
+ }
66
+
67
+ // lookupViaMap looks up the method via the services map.
68
+ private async lookupViaMap(serviceID: string, methodID: string): Promise<InvokeFn | null> {
46
69
  const serviceMethods = this.services[serviceID]
47
70
  if (!serviceMethods) {
48
71
  return null
@@ -53,4 +76,16 @@ export class StaticMux implements Mux {
53
76
  }
54
77
  return await handler.lookupMethod(serviceID, methodID)
55
78
  }
79
+
80
+ // lookupViaLookups looks up the method via the lookup funcs.
81
+ private async lookupViaLookups(serviceID: string, methodID: string): Promise<InvokeFn | null> {
82
+ for (const lookupMethod of this.lookups) {
83
+ const invokeFn = await lookupMethod(serviceID, methodID)
84
+ if (invokeFn) {
85
+ return invokeFn
86
+ }
87
+ }
88
+
89
+ return null
90
+ }
56
91
  }
package/srpc/packet.go CHANGED
@@ -58,7 +58,7 @@ func NewCallDataPacket(data []byte, dataIsZero bool, complete bool, err error) *
58
58
 
59
59
  // Validate performs cursory validation of the packet.
60
60
  func (p *CallData) Validate() error {
61
- if len(p.GetData()) == 0 && !p.GetComplete() && len(p.GetError()) == 0 {
61
+ if len(p.GetData()) == 0 && !p.GetComplete() && len(p.GetError()) == 0 && !p.GetDataIsZero() {
62
62
  return ErrEmptyPacket
63
63
  }
64
64
  return nil
@@ -3,16 +3,16 @@ import type { Sink } from 'it-stream-types'
3
3
  import type { CallData, CallStart } from './rpcproto.pb.js'
4
4
  import { CommonRPC } from './common-rpc.js'
5
5
  import { InvokeFn } from './handler.js'
6
- import { Mux } from './mux.js'
6
+ import { LookupMethod } from './mux.js'
7
7
 
8
8
  // ServerRPC is an ongoing RPC from the server side.
9
9
  export class ServerRPC extends CommonRPC {
10
- // mux is used to handle incoming rpcs.
11
- private mux: Mux
10
+ // lookupMethod looks up the incoming RPC methods.
11
+ private lookupMethod: LookupMethod
12
12
 
13
- constructor(mux: Mux) {
13
+ constructor(lookupMethod: LookupMethod) {
14
14
  super()
15
- this.mux = mux
15
+ this.lookupMethod = lookupMethod
16
16
  }
17
17
 
18
18
  // handleCallStart handles a CallStart cket.
@@ -25,7 +25,7 @@ export class ServerRPC extends CommonRPC {
25
25
  if (!this.service || !this.method) {
26
26
  throw new Error('rpcService and rpcMethod cannot be empty')
27
27
  }
28
- const methodDef = await this.mux.lookupMethod(this.service, this.method)
28
+ const methodDef = await this.lookupMethod(this.service, this.method)
29
29
  if (!methodDef) {
30
30
  throw new Error(`not found: ${this.service}/${this.method}`)
31
31
  }
package/srpc/server.ts CHANGED
@@ -2,7 +2,7 @@ import { Stream } from '@libp2p/interface-connection'
2
2
  import { Duplex } from 'it-stream-types'
3
3
  import { pipe } from 'it-pipe'
4
4
 
5
- import { Mux } from './mux.js'
5
+ import { LookupMethod } from './mux.js'
6
6
  import { ServerRPC } from './server-rpc.js'
7
7
  import { Packet } from './rpcproto.pb.js'
8
8
  import {
@@ -16,11 +16,11 @@ import { RpcStreamHandler } from '../rpcstream/rpcstream.js'
16
16
 
17
17
  // Server implements the SRPC server in TypeScript with a Mux.
18
18
  export class Server implements StreamHandler {
19
- // mux is the mux used to handle requests.
20
- private mux: Mux
19
+ // lookupMethod looks up the incoming RPC methods.
20
+ private lookupMethod: LookupMethod
21
21
 
22
- constructor(mux: Mux) {
23
- this.mux = mux
22
+ constructor(lookupMethod: LookupMethod) {
23
+ this.lookupMethod = lookupMethod
24
24
  }
25
25
 
26
26
  // rpcStreamHandler implements the RpcStreamHandler interface.
@@ -31,7 +31,7 @@ export class Server implements StreamHandler {
31
31
  // startRpc starts a new server-side RPC.
32
32
  // the returned RPC handles incoming Packets.
33
33
  public startRpc(): ServerRPC {
34
- return new ServerRPC(this.mux)
34
+ return new ServerRPC(this.lookupMethod)
35
35
  }
36
36
 
37
37
  // handleStream handles an incoming Uint8Array message duplex.