starpc 0.3.4 → 0.4.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.
Files changed (64) hide show
  1. package/Makefile +2 -1
  2. package/README.md +41 -31
  3. package/dist/echo/client-test.js +1 -1
  4. package/dist/echo/{echo.d.ts → echo.pb.d.ts} +0 -0
  5. package/dist/echo/{echo.js → echo.pb.js} +0 -1
  6. package/dist/echo/index.d.ts +1 -1
  7. package/dist/echo/index.js +1 -1
  8. package/dist/echo/server.d.ts +1 -1
  9. package/dist/srpc/broadcast-channel.js +0 -10
  10. package/dist/srpc/client-rpc.d.ts +1 -1
  11. package/dist/srpc/client.d.ts +5 -5
  12. package/dist/srpc/client.js +21 -25
  13. package/dist/srpc/common-rpc.d.ts +2 -2
  14. package/dist/srpc/common-rpc.js +1 -15
  15. package/dist/srpc/conn-duplex.js +1 -3
  16. package/dist/srpc/conn.js +0 -4
  17. package/dist/srpc/handler.js +12 -14
  18. package/dist/srpc/index.d.ts +1 -1
  19. package/dist/srpc/message-port.js +0 -10
  20. package/dist/srpc/mux.js +4 -2
  21. package/dist/srpc/packet.d.ts +1 -1
  22. package/dist/srpc/packet.js +1 -1
  23. package/dist/srpc/{rpcproto.d.ts → rpcproto.pb.d.ts} +0 -0
  24. package/dist/srpc/{rpcproto.js → rpcproto.pb.js} +0 -0
  25. package/dist/srpc/server-rpc.d.ts +1 -1
  26. package/dist/srpc/server-rpc.js +0 -2
  27. package/dist/srpc/server.d.ts +1 -1
  28. package/dist/srpc/server.js +0 -2
  29. package/dist/srpc/stream.d.ts +1 -1
  30. package/dist/srpc/websocket.js +1 -3
  31. package/e2e/debug.test +0 -0
  32. package/e2e/e2e_test.go +20 -2
  33. package/echo/client-test.ts +1 -1
  34. package/echo/{echo.ts → echo.pb.ts} +0 -0
  35. package/echo/index.ts +1 -1
  36. package/echo/server.ts +1 -1
  37. package/go.mod +2 -2
  38. package/go.sum +2 -2
  39. package/integration/integration.ts +2 -2
  40. package/package.json +1 -1
  41. package/srpc/broadcast-channel.ts +1 -1
  42. package/srpc/client-rpc.go +8 -3
  43. package/srpc/client-rpc.ts +1 -1
  44. package/srpc/client.go +4 -4
  45. package/srpc/client.ts +25 -25
  46. package/srpc/common-rpc.ts +2 -2
  47. package/srpc/conn-duplex.ts +1 -1
  48. package/srpc/handler.ts +14 -10
  49. package/srpc/index.ts +1 -1
  50. package/srpc/{rpc-stream.go → msg-stream.go} +13 -13
  51. package/srpc/muxed-conn.go +31 -0
  52. package/srpc/packet.go +4 -3
  53. package/srpc/packet.ts +1 -1
  54. package/srpc/{rpcproto.ts → rpcproto.pb.ts} +0 -0
  55. package/srpc/server-http.go +1 -1
  56. package/srpc/server-pipe.go +3 -3
  57. package/srpc/server-rpc.go +3 -3
  58. package/srpc/server-rpc.ts +1 -1
  59. package/srpc/server.go +37 -3
  60. package/srpc/server.ts +1 -1
  61. package/srpc/stream.ts +1 -1
  62. package/srpc/websocket.go +1 -4
  63. package/srpc/websocket.ts +1 -1
  64. package/srpc/conn.go +0 -7
package/Makefile CHANGED
@@ -99,9 +99,10 @@ gents: $(PROTOWRAP) node_modules
99
99
  -I $$(pwd)/vendor \
100
100
  --plugin=./node_modules/.bin/protoc-gen-ts_proto \
101
101
  --ts_proto_out=$$(pwd)/vendor \
102
+ --ts_proto_opt=esModuleInterop=true \
103
+ --ts_proto_opt=fileSuffix=.pb \
102
104
  --ts_proto_opt=forceLong=long \
103
105
  --ts_proto_opt=oneof=unions \
104
- --ts_proto_opt=esModuleInterop=true \
105
106
  --ts_proto_opt=outputServices=default,outputServices=generic-definitions \
106
107
  --proto_path $$(pwd)/vendor \
107
108
  --print_structure \
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Stream RPC
2
2
 
3
- **starpc** implements [Proto3 services] in both TypeScript and Go.
3
+ **starpc** implements [Proto3 services] (server & client) in both TypeScript and Go.
4
4
 
5
5
  [Proto3 services]: https://developers.google.com/protocol-buffers/docs/proto3#services
6
6
 
@@ -13,8 +13,6 @@ Can use any Stream multiplexer: defaults to [libp2p-mplex] over a WebSocket.
13
13
 
14
14
  [libp2p-mplex]: https://github.com/libp2p/js-libp2p-mplex
15
15
 
16
- Note: the server has not yet been implemented in TypeScript.
17
-
18
16
  # Usage
19
17
 
20
18
  Starting with the [protobuf-project] repository on the "starpc" branch.
@@ -30,6 +28,8 @@ The demo/boilerplate project implements the Echo example below.
30
28
 
31
29
  [protobuf-project]: https://github.com/aperturerobotics/protobuf-project/tree/starpc
32
30
 
31
+ This repository uses protowrap, see the [Makefile](./Makefile).
32
+
33
33
  ## Protobuf
34
34
 
35
35
  The following examples use the [echo](./echo/echo.proto) protobuf sample.
@@ -56,9 +56,9 @@ message EchoMsg {
56
56
  }
57
57
  ```
58
58
 
59
- ## Go: Server & Client
59
+ ## Go
60
60
 
61
- A basic example can be found in the [e2e test]:
61
+ This example demonstrates both the server and client:
62
62
 
63
63
  ```go
64
64
  // construct the server
@@ -96,39 +96,58 @@ if out.GetBody() != bodyTxt {
96
96
 
97
97
  See the ts-proto README to generate the TypeScript for your protobufs.
98
98
 
99
- Also check out the [integration](./integration/integration.ts) test.
99
+ For an example of Go <-> TypeScript interop, see the [integration] test. For an
100
+ example of TypeScript <-> TypeScript interop, see the [e2e] test.
100
101
 
101
- Supports any AsyncIterable communication channel with an included implementation
102
- for WebSockets.
102
+ [e2e]: ./e2e/e2e.ts
103
+ [integration]: ./integration/integration.ts
103
104
 
104
- This repository uses protowrap, see the [Makefile](./Makefile).
105
-
106
- `WebSocketConn` uses [js-libp2p-mplex] to multiplex streams over the WebSocket.
105
+ Supports any AsyncIterable communication channel. `DuplexConn`,
106
+ `MessagePortConn`, and `WebSocketConn` use [js-libp2p-mplex] to multiplex
107
+ streams, but any multiplexer can be used.
107
108
 
108
109
  [js-libp2p-mplex]: https://github.com/libp2p/js-libp2p-mplex
109
110
 
110
- ### Server
111
+ This example demonstrates both the server and client:
111
112
 
112
113
  ```typescript
113
- import { WebSocketConn, Server, createMux } from '../srpc'
114
- import { EchoerClientImpl } from '../echo/echo'
114
+ import { pipe } from 'it-pipe'
115
+ import { createHandler, createMux, Server, Client, Conn } from 'srpc'
116
+ import { EchoerDefinition, EchoerServer, runClientTest } from 'srpc/echo'
115
117
 
116
118
  const mux = createMux()
117
- mux.register(TODO)
119
+ const echoer = new EchoerServer()
120
+ mux.register(createHandler(EchoerDefinition, echoer))
118
121
  const server = new Server(mux)
119
122
 
120
- // TODO: accept a WebSocket-like object.
121
- const ws = TODO
122
- const channel = new WebSocketConn(ws, server)
123
- // incoming streams will be handled by server.
123
+ const clientConn = new Conn()
124
+ const serverConn = new Conn(server)
125
+ pipe(clientConn, serverConn, clientConn)
126
+ const client = new Client(clientConn.buildOpenStreamFunc())
127
+
128
+ console.log('Calling Echo: unary call...')
129
+ let result = await demoServiceClient.Echo({
130
+ body: 'Hello world!',
131
+ })
132
+ console.log('success: output', result.body)
133
+
134
+ const clientRequestStream = new Observable<EchoMsg>(subscriber => {
135
+ subscriber.next({body: 'Hello world from streaming request.'})
136
+ subscriber.complete()
137
+ })
138
+
139
+ console.log('Calling EchoClientStream: client -> server...')
140
+ result = await demoServiceClient.EchoClientStream(clientRequestStream)
141
+ console.log('success: output', result.body)
124
142
  ```
125
143
 
144
+ ## WebSocket
126
145
 
127
- ### Client
146
+ One way to integrate Go and TypeScript is over a WebSocket:
128
147
 
129
148
  ```typescript
130
- import { WebSocketConn } from '../srpc'
131
- import { EchoerClientImpl } from '../echo/echo'
149
+ import { WebSocketConn } from 'srpc'
150
+ import { EchoerClientImpl } from 'srpc/echo'
132
151
 
133
152
  const ws = new WebSocket('ws://localhost:5000/demo')
134
153
  const channel = new WebSocketConn(ws)
@@ -139,15 +158,6 @@ const result = await demoServiceClient.Echo({
139
158
  body: "Hello world!"
140
159
  })
141
160
  console.log('output', result.body)
142
-
143
- const clientRequestStream = new Observable<EchoMsg>(subscriber => {
144
- subscriber.next({body: 'Hello world from streaming request.'})
145
- subscriber.complete()
146
- })
147
-
148
- console.log('Calling EchoClientStream: client -> server...')
149
- result = await demoServiceClient.EchoClientStream(clientRequestStream)
150
- console.log('success: output', result.body)
151
161
  ```
152
162
 
153
163
  # Attribution
@@ -1,4 +1,4 @@
1
- import { EchoerClientImpl } from './echo.js';
1
+ import { EchoerClientImpl } from './echo.pb.js';
2
2
  import { Observable } from 'rxjs';
3
3
  export async function runClientTest(client) {
4
4
  const demoServiceClient = new EchoerClientImpl(client);
File without changes
@@ -47,7 +47,6 @@ export const EchoMsg = {
47
47
  },
48
48
  };
49
49
  export class EchoerClientImpl {
50
- rpc;
51
50
  constructor(rpc) {
52
51
  this.rpc = rpc;
53
52
  this.Echo = this.Echo.bind(this);
@@ -1,3 +1,3 @@
1
- export * from './echo.js';
1
+ export * from './echo.pb.js';
2
2
  export * from './server.js';
3
3
  export { runClientTest } from './client-test.js';
@@ -1,3 +1,3 @@
1
- export * from './echo.js';
1
+ export * from './echo.pb.js';
2
2
  export * from './server.js';
3
3
  export { runClientTest } from './client-test.js';
@@ -1,5 +1,5 @@
1
1
  import { Observable } from 'rxjs';
2
- import { Echoer, EchoMsg } from './echo';
2
+ import { Echoer, EchoMsg } from './echo.pb.js';
3
3
  export declare class EchoerServer implements Echoer {
4
4
  Echo(request: EchoMsg): Promise<EchoMsg>;
5
5
  EchoServerStream(request: EchoMsg): Observable<EchoMsg>;
@@ -2,14 +2,6 @@ import { EventIterator } from 'event-iterator';
2
2
  import { DuplexConn } from './conn-duplex.js';
3
3
  // BroadcastChannelIterable is a AsyncIterable wrapper for BroadcastChannel.
4
4
  export class BroadcastChannelIterable {
5
- // readChannel is the incoming broadcast channel
6
- readChannel;
7
- // writeChannel is the outgoing broadcast channel
8
- writeChannel;
9
- // sink is the sink for incoming messages.
10
- sink;
11
- // source is the source for outgoing messages.
12
- source;
13
5
  constructor(readChannel, writeChannel) {
14
6
  this.readChannel = readChannel;
15
7
  this.writeChannel = writeChannel;
@@ -52,8 +44,6 @@ export function newBroadcastChannelIterable(readName, writeName) {
52
44
  //
53
45
  // expects Uint8Array objects over the BroadcastChannel.
54
46
  export class BroadcastChannelConn extends DuplexConn {
55
- // broadcastChannel is the broadcast channel iterable
56
- broadcastChannel;
57
47
  constructor(readChannel, writeChannel, server, connParams) {
58
48
  const broadcastChannel = new BroadcastChannelIterable(readChannel, writeChannel);
59
49
  super(broadcastChannel, server, connParams);
@@ -1,4 +1,4 @@
1
- import type { CallStart } from './rpcproto.js';
1
+ import type { CallStart } from './rpcproto.pb.js';
2
2
  import { CommonRPC } from './common-rpc.js';
3
3
  export declare class ClientRPC extends CommonRPC {
4
4
  constructor(service: string, method: string);
@@ -2,11 +2,11 @@ import { Observable } from 'rxjs';
2
2
  import type { TsProtoRpc } from './ts-proto-rpc.js';
3
3
  import type { OpenStreamFunc } from './stream.js';
4
4
  export declare class Client implements TsProtoRpc {
5
- private openConnFn;
6
- private _openConnFn?;
7
- constructor(openConnFn?: OpenStreamFunc);
8
- setOpenConnFn(openConnFn?: OpenStreamFunc): Promise<OpenStreamFunc>;
9
- private initOpenConnFn;
5
+ private openStreamFn;
6
+ private _openStreamFn?;
7
+ constructor(openStreamFn?: OpenStreamFunc);
8
+ setOpenStreamFn(openStreamFn?: OpenStreamFunc): Promise<OpenStreamFunc>;
9
+ private initOpenStreamFn;
10
10
  request(service: string, method: string, data: Uint8Array): Promise<Uint8Array>;
11
11
  clientStreamingRequest(service: string, method: string, data: Observable<Uint8Array>): Promise<Uint8Array>;
12
12
  serverStreamingRequest(service: string, method: string, data: Uint8Array): Observable<Uint8Array>;
@@ -19,35 +19,31 @@ function writeClientStream(call, data) {
19
19
  }
20
20
  // Client implements the ts-proto Rpc interface with the drpcproto protocol.
21
21
  export class Client {
22
- // openConnFn is a promise which contains the OpenStreamFunc.
23
- openConnFn;
24
- // _openConnFn resolves openConnFn.
25
- _openConnFn;
26
- constructor(openConnFn) {
27
- this.openConnFn = this.setOpenConnFn(openConnFn);
22
+ constructor(openStreamFn) {
23
+ this.openStreamFn = this.setOpenStreamFn(openStreamFn);
28
24
  }
29
- // setOpenConnFn updates the openConnFn for the Client.
30
- setOpenConnFn(openConnFn) {
31
- if (this._openConnFn) {
32
- if (openConnFn) {
33
- this._openConnFn(openConnFn);
34
- this._openConnFn = undefined;
25
+ // setOpenStreamFn updates the openStreamFn for the Client.
26
+ setOpenStreamFn(openStreamFn) {
27
+ if (this._openStreamFn) {
28
+ if (openStreamFn) {
29
+ this._openStreamFn(openStreamFn);
30
+ this._openStreamFn = undefined;
35
31
  }
36
32
  }
37
33
  else {
38
- if (openConnFn) {
39
- this.openConnFn = Promise.resolve(openConnFn);
34
+ if (openStreamFn) {
35
+ this.openStreamFn = Promise.resolve(openStreamFn);
40
36
  }
41
37
  else {
42
- this.initOpenConnFn();
38
+ this.initOpenStreamFn();
43
39
  }
44
40
  }
45
- return this.openConnFn;
41
+ return this.openStreamFn;
46
42
  }
47
- // initOpenConnFn creates the empty Promise for openConnFn.
48
- initOpenConnFn() {
43
+ // initOpenStreamFn creates the empty Promise for openStreamFn.
44
+ initOpenStreamFn() {
49
45
  const openPromise = new Promise((resolve, reject) => {
50
- this._openConnFn = (conn, err) => {
46
+ this._openStreamFn = (conn, err) => {
51
47
  if (err) {
52
48
  reject(err);
53
49
  }
@@ -56,8 +52,8 @@ export class Client {
56
52
  }
57
53
  };
58
54
  });
59
- this.openConnFn = openPromise;
60
- return this.openConnFn;
55
+ this.openStreamFn = openPromise;
56
+ return this.openStreamFn;
61
57
  }
62
58
  // request starts a non-streaming request.
63
59
  async request(service, method, data) {
@@ -84,7 +80,7 @@ export class Client {
84
80
  }
85
81
  // serverStreamingRequest starts a server-side streaming request.
86
82
  serverStreamingRequest(service, method, data) {
87
- const pushServerData = pushable();
83
+ const pushServerData = pushable({ objectMode: true });
88
84
  const serverData = observableFrom(pushServerData);
89
85
  this.startRpc(service, method, data)
90
86
  .then(async (call) => {
@@ -103,7 +99,7 @@ export class Client {
103
99
  }
104
100
  // bidirectionalStreamingRequest starts a two-way streaming request.
105
101
  bidirectionalStreamingRequest(service, method, data) {
106
- const pushServerData = pushable();
102
+ const pushServerData = pushable({ objectMode: true });
107
103
  const serverData = observableFrom(pushServerData);
108
104
  this.startRpc(service, method, null)
109
105
  .then(async (call) => {
@@ -135,8 +131,8 @@ export class Client {
135
131
  // throws any error starting the rpc call
136
132
  // if data == null and data.length == 0, sends a separate data packet.
137
133
  async startRpc(rpcService, rpcMethod, data) {
138
- const openConnFn = await this.openConnFn;
139
- const conn = await openConnFn();
134
+ const openStreamFn = await this.openStreamFn;
135
+ const conn = await openStreamFn();
140
136
  const call = new ClientRPC(rpcService, rpcMethod);
141
137
  pipe(conn, parseLengthPrefixTransform(), decodePacketSource, call, encodePacketSource, prependLengthPrefixTransform(), conn);
142
138
  await call.writeCallStart(data || undefined);
@@ -1,6 +1,6 @@
1
1
  import type { Source, Sink } from 'it-stream-types';
2
- import type { CallData, CallStart } from './rpcproto.js';
3
- import { Packet } from './rpcproto.js';
2
+ import type { CallData, CallStart } from './rpcproto.pb.js';
3
+ import { Packet } from './rpcproto.pb.js';
4
4
  export declare class CommonRPC {
5
5
  sink: Sink<Packet>;
6
6
  source: AsyncIterable<Packet>;
@@ -1,21 +1,7 @@
1
1
  import { pushable } from 'it-pushable';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  // CommonRPC is common logic between server and client RPCs.
4
4
  export class CommonRPC {
5
- // sink is the data sink for incoming messages.
6
- sink;
7
- // source is the packet source for outgoing Packets.
8
- source;
9
- // _source is used to write to the source.
10
- _source;
11
- // rpcDataSource emits incoming client RPC messages to the caller.
12
- rpcDataSource;
13
- // _rpcDataSource is used to write to the rpc message source.
14
- _rpcDataSource;
15
- // service is the rpc service
16
- service;
17
- // method is the rpc method
18
- method;
19
5
  constructor() {
20
6
  this.sink = this._createSink();
21
7
  const sourcev = this._createSource();
@@ -4,12 +4,10 @@ import { Conn } from './conn.js';
4
4
  //
5
5
  // expects Uint8Array objects
6
6
  export class DuplexConn extends Conn {
7
- // channel is the iterable
8
- channel;
9
7
  constructor(duplex, server, connParams) {
10
8
  super(server, connParams);
11
9
  this.channel = duplex;
12
- pipe(this, this.channel, this);
10
+ pipe(this.channel, this, this.channel);
13
11
  }
14
12
  // getChannelDuplex returns the Duplex channel.
15
13
  getChannelDuplex() {
package/dist/srpc/conn.js CHANGED
@@ -5,10 +5,6 @@ import { Client } from './client.js';
5
5
  // Implements the server by handling incoming streams.
6
6
  // If the server is unset, rejects any incoming streams.
7
7
  export class Conn {
8
- // muxer is the mplex stream muxer.
9
- muxer;
10
- // server is the server side, if set.
11
- server;
12
8
  constructor(server, connParams) {
13
9
  if (server) {
14
10
  this.server = server;
@@ -4,10 +4,6 @@ import { from as observableFrom } from 'rxjs';
4
4
  import { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
5
5
  // StaticHandler is a handler with a definition and implementation.
6
6
  export class StaticHandler {
7
- // service is the service id
8
- service;
9
- // methods is the map of method to invoke fn
10
- methods;
11
7
  constructor(serviceID, methods) {
12
8
  this.service = serviceID;
13
9
  this.methods = methods;
@@ -38,23 +34,27 @@ export function createInvokeFn(methodInfo, methodProto) {
38
34
  objectMode: true,
39
35
  });
40
36
  // pipe responseSink to dataSink.
41
- const responsePipe = pipe(responseSink, buildEncodeMessageTransform(methodInfo.responseType), dataSink);
37
+ pipe(responseSink, buildEncodeMessageTransform(methodInfo.responseType), dataSink);
38
+ // requestSource is a Source of decoded request messages.
39
+ const requestSource = pipe(dataSource, requestDecode);
42
40
  // build the request argument.
43
41
  let requestArg;
44
42
  if (methodInfo.requestStream) {
45
- // requestSource is a Source of decoded request messages.
46
- const requestSource = pipe(dataSource, requestDecode);
47
43
  // convert the request data source into an Observable<T>
48
44
  requestArg = observableFrom(requestSource);
49
45
  }
50
46
  else {
51
47
  // receive a single message for the argument.
52
- const requestRx = requestDecode(dataSource);
53
- for await (const msg of requestRx) {
54
- requestArg = msg;
55
- break;
48
+ for await (const msg of requestSource) {
49
+ if (msg) {
50
+ requestArg = msg;
51
+ break;
52
+ }
56
53
  }
57
54
  }
55
+ if (!requestArg) {
56
+ throw new Error('request object was empty');
57
+ }
58
58
  // Call the implementation.
59
59
  try {
60
60
  const responseObj = methodProto(requestArg);
@@ -77,9 +77,7 @@ export function createInvokeFn(methodInfo, methodProto) {
77
77
  },
78
78
  complete: () => {
79
79
  responseSink.end();
80
- responsePipe.finally(() => {
81
- resolve();
82
- });
80
+ resolve();
83
81
  },
84
82
  });
85
83
  });
@@ -1,4 +1,4 @@
1
- export type { OpenStreamFunc } from './stream.js';
1
+ export type { PacketHandler, Stream, OpenStreamFunc } from './stream.js';
2
2
  export { Client } from './client.js';
3
3
  export { Server } from './server.js';
4
4
  export { Conn, ConnParams } from './conn.js';
@@ -2,14 +2,6 @@ import { EventIterator } from 'event-iterator';
2
2
  import { DuplexConn } from './conn-duplex.js';
3
3
  // MessagePortIterable is a AsyncIterable wrapper for MessagePort.
4
4
  export class MessagePortIterable {
5
- // port is the message port
6
- port;
7
- // sink is the sink for incoming messages.
8
- sink;
9
- // source is the source for outgoing messages.
10
- source;
11
- // _source is the EventIterator for source.
12
- _source;
13
5
  constructor(port) {
14
6
  this.port = port;
15
7
  this.sink = this._createSink();
@@ -51,8 +43,6 @@ export function newMessagePortIterable(port) {
51
43
  //
52
44
  // expects Uint8Array objects over the MessagePort.
53
45
  export class MessagePortConn extends DuplexConn {
54
- // messagePort is the message port iterable.
55
- messagePort;
56
46
  constructor(port, server, connParams) {
57
47
  const messagePort = new MessagePortIterable(port);
58
48
  super(messagePort, server, connParams);
package/dist/srpc/mux.js CHANGED
@@ -5,8 +5,10 @@ export function createMux() {
5
5
  // StaticMux contains a in-memory mapping between service ID and handlers.
6
6
  // implements Mux
7
7
  export class StaticMux {
8
- // services contains a mapping from service id to handlers.
9
- services = {};
8
+ constructor() {
9
+ // services contains a mapping from service id to handlers.
10
+ this.services = {};
11
+ }
10
12
  register(handler) {
11
13
  const serviceID = handler?.getServiceID();
12
14
  if (!serviceID) {
@@ -1,5 +1,5 @@
1
1
  import type { Transform } from 'it-stream-types';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  export declare const decodePacketSource: (source: import("it-stream-types").Source<Uint8Array | Uint8Array[]>) => AsyncIterable<Packet>;
4
4
  export declare const encodePacketSource: (source: import("it-stream-types").Source<Packet | Packet[]>) => AsyncIterable<Uint8Array>;
5
5
  export declare function prependLengthPrefixTransform(): Transform<Uint8Array>;
@@ -1,5 +1,5 @@
1
1
  import { encode as lengthPrefixEncode, decode as lengthPrefixDecode, } from 'it-length-prefixed';
2
- import { Packet } from './rpcproto.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  import { buildDecodeMessageTransform, buildEncodeMessageTransform, } from './message.js';
4
4
  // decodePacketSource decodes packets from a binary data stream.
5
5
  export const decodePacketSource = buildDecodeMessageTransform(Packet);
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- import type { CallData, CallStart } from './rpcproto.js';
1
+ import type { CallData, CallStart } from './rpcproto.pb.js';
2
2
  import { CommonRPC } from './common-rpc.js';
3
3
  import { Mux } from './mux.js';
4
4
  export declare class ServerRPC extends CommonRPC {
@@ -1,8 +1,6 @@
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
- // mux is used to handle incoming rpcs.
5
- mux;
6
4
  constructor(mux) {
7
5
  super();
8
6
  this.mux = mux;
@@ -2,7 +2,7 @@ import { Stream } from '@libp2p/interface-connection';
2
2
  import { Duplex } from 'it-stream-types';
3
3
  import { Mux } from './mux.js';
4
4
  import { ServerRPC } from './server-rpc.js';
5
- import { Packet } from './rpcproto.js';
5
+ import { Packet } from './rpcproto.pb.js';
6
6
  import { StreamHandler } from './conn.js';
7
7
  export declare class Server implements StreamHandler {
8
8
  private mux;
@@ -3,8 +3,6 @@ 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
- // mux is the mux used to handle requests.
7
- mux;
8
6
  constructor(mux) {
9
7
  this.mux = mux;
10
8
  }
@@ -1,4 +1,4 @@
1
- import type { Packet } from './rpcproto';
1
+ import type { Packet } from './rpcproto.pb.js';
2
2
  import type { Duplex } from 'it-stream-types';
3
3
  export declare type PacketHandler = (packet: Packet) => Promise<void>;
4
4
  export declare type Stream = Duplex<Uint8Array>;
@@ -4,15 +4,13 @@ import { Mplex } from '@libp2p/mplex';
4
4
  import { Conn } from './conn.js';
5
5
  // WebSocketConn implements a connection with a WebSocket and optional Server.
6
6
  export class WebSocketConn extends Conn {
7
- // socket is the web socket
8
- socket;
9
7
  constructor(socket, server) {
10
8
  super(server, {
11
9
  muxerFactory: new Mplex(),
12
10
  });
13
11
  this.socket = socket;
14
12
  const socketDuplex = duplex(socket);
15
- pipe(this.source, socketDuplex, this.sink);
13
+ pipe(socketDuplex, this, socketDuplex);
16
14
  }
17
15
  // getSocket returns the websocket.
18
16
  getSocket() {
package/e2e/debug.test ADDED
Binary file
package/e2e/e2e_test.go CHANGED
@@ -3,10 +3,13 @@ package e2e
3
3
  import (
4
4
  "context"
5
5
  "io"
6
+ "net"
6
7
  "testing"
7
8
 
8
9
  "github.com/aperturerobotics/starpc/echo"
9
10
  "github.com/aperturerobotics/starpc/srpc"
11
+ "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
12
+ mp "github.com/libp2p/go-mplex"
10
13
  "github.com/pkg/errors"
11
14
  )
12
15
 
@@ -20,9 +23,24 @@ func RunE2E(t *testing.T, cb func(client echo.SRPCEchoerClient) error) {
20
23
  }
21
24
  server := srpc.NewServer(mux)
22
25
 
26
+ // note: also possible to do without mplex:
27
+ // openStream := srpc.NewServerPipe(server)
28
+ // client := srpc.NewClient(openStream)
29
+
23
30
  // construct the client
24
- openStream := srpc.NewServerPipe(server)
25
- client := srpc.NewClient(openStream)
31
+ clientPipe, serverPipe := net.Pipe()
32
+
33
+ ctx := context.Background()
34
+ go func() {
35
+ serverMp, _ := mp.NewMultiplex(serverPipe, false, nil)
36
+ _ = server.AcceptMuxedConn(ctx, mplex.NewMuxedConn(serverMp))
37
+ }()
38
+
39
+ clientMp, err := mp.NewMultiplex(clientPipe, true, nil)
40
+ if err != nil {
41
+ t.Fatal(err.Error())
42
+ }
43
+ client := srpc.NewClientWithMuxedConn(mplex.NewMuxedConn(clientMp))
26
44
 
27
45
  // construct the client rpc interface
28
46
  clientEcho := echo.NewSRPCEchoerClient(client)
@@ -1,5 +1,5 @@
1
1
  import { Client } from '../srpc/index.js'
2
- import { EchoerClientImpl, EchoMsg } from './echo.js'
2
+ import { EchoerClientImpl, EchoMsg } from './echo.pb.js'
3
3
  import { Observable } from 'rxjs'
4
4
 
5
5
  export async function runClientTest(client: Client) {
File without changes
package/echo/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './echo.js'
1
+ export * from './echo.pb.js'
2
2
  export * from './server.js'
3
3
  export { runClientTest } from './client-test.js'
package/echo/server.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Observable, from as observableFrom } from 'rxjs'
2
- import { Echoer, EchoMsg } from './echo'
2
+ import { Echoer, EchoMsg } from './echo.pb.js'
3
3
  import { pushable, Pushable } from 'it-pushable'
4
4
 
5
5
  // EchoServer implements the Echoer server.