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.
- package/Makefile +2 -1
- package/README.md +41 -31
- package/dist/echo/client-test.js +1 -1
- package/dist/echo/{echo.d.ts → echo.pb.d.ts} +0 -0
- package/dist/echo/{echo.js → echo.pb.js} +0 -1
- package/dist/echo/index.d.ts +1 -1
- package/dist/echo/index.js +1 -1
- package/dist/echo/server.d.ts +1 -1
- package/dist/srpc/broadcast-channel.js +0 -10
- package/dist/srpc/client-rpc.d.ts +1 -1
- package/dist/srpc/client.d.ts +5 -5
- package/dist/srpc/client.js +21 -25
- package/dist/srpc/common-rpc.d.ts +2 -2
- package/dist/srpc/common-rpc.js +1 -15
- package/dist/srpc/conn-duplex.js +1 -3
- package/dist/srpc/conn.js +0 -4
- package/dist/srpc/handler.js +12 -14
- package/dist/srpc/index.d.ts +1 -1
- package/dist/srpc/message-port.js +0 -10
- package/dist/srpc/mux.js +4 -2
- package/dist/srpc/packet.d.ts +1 -1
- package/dist/srpc/packet.js +1 -1
- package/dist/srpc/{rpcproto.d.ts → rpcproto.pb.d.ts} +0 -0
- package/dist/srpc/{rpcproto.js → rpcproto.pb.js} +0 -0
- package/dist/srpc/server-rpc.d.ts +1 -1
- package/dist/srpc/server-rpc.js +0 -2
- package/dist/srpc/server.d.ts +1 -1
- package/dist/srpc/server.js +0 -2
- package/dist/srpc/stream.d.ts +1 -1
- package/dist/srpc/websocket.js +1 -3
- package/e2e/debug.test +0 -0
- package/e2e/e2e_test.go +20 -2
- package/echo/client-test.ts +1 -1
- package/echo/{echo.ts → echo.pb.ts} +0 -0
- package/echo/index.ts +1 -1
- package/echo/server.ts +1 -1
- package/go.mod +2 -2
- package/go.sum +2 -2
- package/integration/integration.ts +2 -2
- package/package.json +1 -1
- package/srpc/broadcast-channel.ts +1 -1
- package/srpc/client-rpc.go +8 -3
- package/srpc/client-rpc.ts +1 -1
- package/srpc/client.go +4 -4
- package/srpc/client.ts +25 -25
- package/srpc/common-rpc.ts +2 -2
- package/srpc/conn-duplex.ts +1 -1
- package/srpc/handler.ts +14 -10
- package/srpc/index.ts +1 -1
- package/srpc/{rpc-stream.go → msg-stream.go} +13 -13
- package/srpc/muxed-conn.go +31 -0
- package/srpc/packet.go +4 -3
- package/srpc/packet.ts +1 -1
- package/srpc/{rpcproto.ts → rpcproto.pb.ts} +0 -0
- package/srpc/server-http.go +1 -1
- package/srpc/server-pipe.go +3 -3
- package/srpc/server-rpc.go +3 -3
- package/srpc/server-rpc.ts +1 -1
- package/srpc/server.go +37 -3
- package/srpc/server.ts +1 -1
- package/srpc/stream.ts +1 -1
- package/srpc/websocket.go +1 -4
- package/srpc/websocket.ts +1 -1
- 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
|
|
59
|
+
## Go
|
|
60
60
|
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
-
|
|
102
|
+
[e2e]: ./e2e/e2e.ts
|
|
103
|
+
[integration]: ./integration/integration.ts
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
111
|
+
This example demonstrates both the server and client:
|
|
111
112
|
|
|
112
113
|
```typescript
|
|
113
|
-
import {
|
|
114
|
-
import {
|
|
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
|
-
|
|
119
|
+
const echoer = new EchoerServer()
|
|
120
|
+
mux.register(createHandler(EchoerDefinition, echoer))
|
|
118
121
|
const server = new Server(mux)
|
|
119
122
|
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
146
|
+
One way to integrate Go and TypeScript is over a WebSocket:
|
|
128
147
|
|
|
129
148
|
```typescript
|
|
130
|
-
import { WebSocketConn } from '
|
|
131
|
-
import { EchoerClientImpl } from '
|
|
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
|
package/dist/echo/client-test.js
CHANGED
|
File without changes
|
package/dist/echo/index.d.ts
CHANGED
package/dist/echo/index.js
CHANGED
package/dist/echo/server.d.ts
CHANGED
|
@@ -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);
|
package/dist/srpc/client.d.ts
CHANGED
|
@@ -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
|
|
6
|
-
private
|
|
7
|
-
constructor(
|
|
8
|
-
|
|
9
|
-
private
|
|
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>;
|
package/dist/srpc/client.js
CHANGED
|
@@ -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
|
-
|
|
23
|
-
|
|
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
|
-
//
|
|
30
|
-
|
|
31
|
-
if (this.
|
|
32
|
-
if (
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
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 (
|
|
39
|
-
this.
|
|
34
|
+
if (openStreamFn) {
|
|
35
|
+
this.openStreamFn = Promise.resolve(openStreamFn);
|
|
40
36
|
}
|
|
41
37
|
else {
|
|
42
|
-
this.
|
|
38
|
+
this.initOpenStreamFn();
|
|
43
39
|
}
|
|
44
40
|
}
|
|
45
|
-
return this.
|
|
41
|
+
return this.openStreamFn;
|
|
46
42
|
}
|
|
47
|
-
//
|
|
48
|
-
|
|
43
|
+
// initOpenStreamFn creates the empty Promise for openStreamFn.
|
|
44
|
+
initOpenStreamFn() {
|
|
49
45
|
const openPromise = new Promise((resolve, reject) => {
|
|
50
|
-
this.
|
|
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.
|
|
60
|
-
return this.
|
|
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
|
|
139
|
-
const conn = await
|
|
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>;
|
package/dist/srpc/common-rpc.js
CHANGED
|
@@ -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();
|
package/dist/srpc/conn-duplex.js
CHANGED
|
@@ -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
|
|
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;
|
package/dist/srpc/handler.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
81
|
-
resolve();
|
|
82
|
-
});
|
|
80
|
+
resolve();
|
|
83
81
|
},
|
|
84
82
|
});
|
|
85
83
|
});
|
package/dist/srpc/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
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) {
|
package/dist/srpc/packet.d.ts
CHANGED
|
@@ -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>;
|
package/dist/srpc/packet.js
CHANGED
|
@@ -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
|
package/dist/srpc/server-rpc.js
CHANGED
package/dist/srpc/server.d.ts
CHANGED
|
@@ -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;
|
package/dist/srpc/server.js
CHANGED
|
@@ -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
|
}
|
package/dist/srpc/stream.d.ts
CHANGED
package/dist/srpc/websocket.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
25
|
-
|
|
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)
|
package/echo/client-test.ts
CHANGED
|
File without changes
|
package/echo/index.ts
CHANGED
package/echo/server.ts
CHANGED