starpc 0.3.5 → 0.3.6
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/dist/echo/echo.js +0 -1
- package/dist/srpc/broadcast-channel.js +0 -10
- package/dist/srpc/client.js +2 -6
- package/dist/srpc/common-rpc.js +0 -14
- 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/message-port.js +0 -10
- package/dist/srpc/mux.js +4 -2
- package/dist/srpc/server-rpc.js +0 -2
- package/dist/srpc/server.js +0 -2
- package/dist/srpc/websocket.js +1 -3
- package/e2e/debug.test +0 -0
- package/e2e/e2e_test.go +20 -2
- package/go.mod +2 -2
- package/go.sum +2 -2
- package/package.json +1 -1
- package/srpc/client-rpc.go +8 -3
- package/srpc/client.go +2 -2
- package/srpc/client.ts +2 -2
- package/srpc/conn-duplex.ts +1 -1
- package/srpc/handler.ts +14 -10
- package/srpc/muxed-conn.go +31 -0
- package/srpc/packet.go +4 -3
- package/srpc/rpc-stream.go +2 -2
- package/srpc/server-rpc.go +2 -2
- package/srpc/server.go +3 -1
- package/srpc/websocket.go +0 -3
- package/srpc/websocket.ts +1 -1
- package/srpc/conn.go +0 -7
package/dist/echo/echo.js
CHANGED
|
@@ -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.js
CHANGED
|
@@ -19,10 +19,6 @@ 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
22
|
constructor(openConnFn) {
|
|
27
23
|
this.openConnFn = this.setOpenConnFn(openConnFn);
|
|
28
24
|
}
|
|
@@ -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) => {
|
package/dist/srpc/common-rpc.js
CHANGED
|
@@ -2,20 +2,6 @@ import { pushable } from 'it-pushable';
|
|
|
2
2
|
import { Packet } from './rpcproto.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
|
});
|
|
@@ -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/server-rpc.js
CHANGED
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/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/go.mod
CHANGED
|
@@ -9,8 +9,9 @@ require (
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
require (
|
|
12
|
-
github.com/libp2p/go-libp2p v0.20.1
|
|
12
|
+
github.com/libp2p/go-libp2p v0.20.1-0.20220622205512-3cf611ad8c9c
|
|
13
13
|
github.com/libp2p/go-libp2p-core v0.16.1
|
|
14
|
+
github.com/libp2p/go-mplex v0.7.0
|
|
14
15
|
github.com/sirupsen/logrus v1.8.2-0.20220112234510-85981c045988
|
|
15
16
|
)
|
|
16
17
|
|
|
@@ -25,7 +26,6 @@ require (
|
|
|
25
26
|
github.com/klauspost/compress v1.15.1 // indirect
|
|
26
27
|
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
|
27
28
|
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
|
28
|
-
github.com/libp2p/go-mplex v0.7.0 // indirect
|
|
29
29
|
github.com/libp2p/go-openssl v0.0.7 // indirect
|
|
30
30
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
|
31
31
|
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
package/go.sum
CHANGED
|
@@ -65,8 +65,8 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
|
|
65
65
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
|
66
66
|
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
|
|
67
67
|
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
|
|
68
|
-
github.com/libp2p/go-libp2p v0.20.1 h1:
|
|
69
|
-
github.com/libp2p/go-libp2p v0.20.1/go.mod h1:
|
|
68
|
+
github.com/libp2p/go-libp2p v0.20.1-0.20220622205512-3cf611ad8c9c h1:BTR12zXVGQtdk9bT5GLOmdzJrhyFO6YUH3/e8lnkjQ0=
|
|
69
|
+
github.com/libp2p/go-libp2p v0.20.1-0.20220622205512-3cf611ad8c9c/go.mod h1:tqyre7jPbLfhzjQfpiFX6x7wj/sqt1074riPM0Xn/qI=
|
|
70
70
|
github.com/libp2p/go-libp2p-core v0.16.1 h1:bWoiEBqVkpJ13hbv/f69tHODp86t6mvc4fBN4DkK73M=
|
|
71
71
|
github.com/libp2p/go-libp2p-core v0.16.1/go.mod h1:O3i/7y+LqUb0N+qhzXjBjjpchgptWAVMG1Voegk7b4c=
|
|
72
72
|
github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84=
|
package/package.json
CHANGED
package/srpc/client-rpc.go
CHANGED
|
@@ -46,9 +46,8 @@ func NewClientRPC(ctx context.Context, service, method string) *ClientRPC {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Start sets the writer and writes the MsgSend message.
|
|
49
|
-
// firstMsg can be nil, but is usually set if this is a non-streaming rpc.
|
|
50
49
|
// must only be called once!
|
|
51
|
-
func (r *ClientRPC) Start(writer Writer, firstMsg []byte) error {
|
|
50
|
+
func (r *ClientRPC) Start(writer Writer, writeFirstMsg bool, firstMsg []byte) error {
|
|
52
51
|
select {
|
|
53
52
|
case <-r.ctx.Done():
|
|
54
53
|
r.Close()
|
|
@@ -56,7 +55,13 @@ func (r *ClientRPC) Start(writer Writer, firstMsg []byte) error {
|
|
|
56
55
|
default:
|
|
57
56
|
}
|
|
58
57
|
r.writer = writer
|
|
59
|
-
|
|
58
|
+
var firstMsgEmpty bool
|
|
59
|
+
if writeFirstMsg {
|
|
60
|
+
firstMsgEmpty = len(firstMsg) == 0
|
|
61
|
+
} else {
|
|
62
|
+
firstMsg = nil
|
|
63
|
+
}
|
|
64
|
+
pkt := NewCallStartPacket(r.service, r.method, firstMsg, firstMsgEmpty)
|
|
60
65
|
if err := writer.WritePacket(pkt); err != nil {
|
|
61
66
|
r.Close()
|
|
62
67
|
return err
|
package/srpc/client.go
CHANGED
|
@@ -48,7 +48,7 @@ func (c *client) Invoke(rctx context.Context, service, method string, in, out Me
|
|
|
48
48
|
if err != nil {
|
|
49
49
|
return err
|
|
50
50
|
}
|
|
51
|
-
if err := clientRPC.Start(writer, firstMsg); err != nil {
|
|
51
|
+
if err := clientRPC.Start(writer, true, firstMsg); err != nil {
|
|
52
52
|
return err
|
|
53
53
|
}
|
|
54
54
|
msgs, err := clientRPC.ReadAll()
|
|
@@ -85,7 +85,7 @@ func (c *client) NewStream(ctx context.Context, service, method string, firstMsg
|
|
|
85
85
|
if err != nil {
|
|
86
86
|
return nil, err
|
|
87
87
|
}
|
|
88
|
-
if err := clientRPC.Start(writer, firstMsgData); err != nil {
|
|
88
|
+
if err := clientRPC.Start(writer, firstMsg != nil, firstMsgData); err != nil {
|
|
89
89
|
return nil, err
|
|
90
90
|
}
|
|
91
91
|
|
package/srpc/client.ts
CHANGED
|
@@ -109,7 +109,7 @@ export class Client implements TsProtoRpc {
|
|
|
109
109
|
method: string,
|
|
110
110
|
data: Uint8Array
|
|
111
111
|
): Observable<Uint8Array> {
|
|
112
|
-
const pushServerData: Pushable<Uint8Array> = pushable()
|
|
112
|
+
const pushServerData: Pushable<Uint8Array> = pushable({ objectMode: true })
|
|
113
113
|
const serverData = observableFrom(pushServerData)
|
|
114
114
|
this.startRpc(service, method, data)
|
|
115
115
|
.then(async (call) => {
|
|
@@ -132,7 +132,7 @@ export class Client implements TsProtoRpc {
|
|
|
132
132
|
method: string,
|
|
133
133
|
data: Observable<Uint8Array>
|
|
134
134
|
): Observable<Uint8Array> {
|
|
135
|
-
const pushServerData: Pushable<Uint8Array> = pushable()
|
|
135
|
+
const pushServerData: Pushable<Uint8Array> = pushable({ objectMode: true })
|
|
136
136
|
const serverData = observableFrom(pushServerData)
|
|
137
137
|
this.startRpc(service, method, null)
|
|
138
138
|
.then(async (call) => {
|
package/srpc/conn-duplex.ts
CHANGED
package/srpc/handler.ts
CHANGED
|
@@ -84,28 +84,34 @@ export function createInvokeFn(
|
|
|
84
84
|
})
|
|
85
85
|
|
|
86
86
|
// pipe responseSink to dataSink.
|
|
87
|
-
|
|
87
|
+
pipe(
|
|
88
88
|
responseSink,
|
|
89
89
|
buildEncodeMessageTransform(methodInfo.responseType),
|
|
90
90
|
dataSink
|
|
91
91
|
)
|
|
92
92
|
|
|
93
|
+
// requestSource is a Source of decoded request messages.
|
|
94
|
+
const requestSource = pipe(dataSource, requestDecode)
|
|
95
|
+
|
|
93
96
|
// build the request argument.
|
|
94
97
|
let requestArg: any
|
|
95
98
|
if (methodInfo.requestStream) {
|
|
96
|
-
// requestSource is a Source of decoded request messages.
|
|
97
|
-
const requestSource = pipe(dataSource, requestDecode)
|
|
98
99
|
// convert the request data source into an Observable<T>
|
|
99
100
|
requestArg = observableFrom(requestSource)
|
|
100
101
|
} else {
|
|
101
102
|
// receive a single message for the argument.
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
for await (const msg of requestSource) {
|
|
104
|
+
if (msg) {
|
|
105
|
+
requestArg = msg
|
|
106
|
+
break
|
|
107
|
+
}
|
|
106
108
|
}
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
if (!requestArg) {
|
|
112
|
+
throw new Error('request object was empty')
|
|
113
|
+
}
|
|
114
|
+
|
|
109
115
|
// Call the implementation.
|
|
110
116
|
try {
|
|
111
117
|
const responseObj = methodProto(requestArg)
|
|
@@ -128,9 +134,7 @@ export function createInvokeFn(
|
|
|
128
134
|
},
|
|
129
135
|
complete: () => {
|
|
130
136
|
responseSink.end()
|
|
131
|
-
|
|
132
|
-
resolve()
|
|
133
|
-
})
|
|
137
|
+
resolve()
|
|
134
138
|
},
|
|
135
139
|
})
|
|
136
140
|
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package srpc
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
|
|
6
|
+
"github.com/libp2p/go-libp2p-core/network"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// NewClientWithMuxedConn constructs a new client with a MuxedConn.
|
|
10
|
+
func NewClientWithMuxedConn(conn network.MuxedConn) Client {
|
|
11
|
+
openStreamFn := NewOpenStreamWithMuxedConn(conn)
|
|
12
|
+
return NewClient(openStreamFn)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// NewOpenStreamWithMuxedConn constructs a OpenStream func with a MuxedConn.
|
|
16
|
+
func NewOpenStreamWithMuxedConn(conn network.MuxedConn) OpenStreamFunc {
|
|
17
|
+
return func(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
|
|
18
|
+
mstrm, err := conn.OpenStream(ctx)
|
|
19
|
+
if err != nil {
|
|
20
|
+
return nil, err
|
|
21
|
+
}
|
|
22
|
+
rw := NewPacketReadWriter(mstrm, msgHandler)
|
|
23
|
+
go func() {
|
|
24
|
+
err := rw.ReadPump()
|
|
25
|
+
if err != nil {
|
|
26
|
+
_ = rw.Close()
|
|
27
|
+
}
|
|
28
|
+
}()
|
|
29
|
+
return rw, nil
|
|
30
|
+
}
|
|
31
|
+
}
|
package/srpc/packet.go
CHANGED
|
@@ -16,12 +16,13 @@ func (p *Packet) Validate() error {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// NewCallStartPacket constructs a new CallStart packet.
|
|
19
|
-
func NewCallStartPacket(service, method string, data []byte) *Packet {
|
|
19
|
+
func NewCallStartPacket(service, method string, data []byte, dataIsZero bool) *Packet {
|
|
20
20
|
return &Packet{Body: &Packet_CallStart{
|
|
21
21
|
CallStart: &CallStart{
|
|
22
22
|
RpcService: service,
|
|
23
23
|
RpcMethod: method,
|
|
24
24
|
Data: data,
|
|
25
|
+
DataIsZero: dataIsZero,
|
|
25
26
|
},
|
|
26
27
|
}}
|
|
27
28
|
}
|
|
@@ -40,7 +41,7 @@ func (p *CallStart) Validate() error {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// NewCallDataPacket constructs a new CallData packet.
|
|
43
|
-
func NewCallDataPacket(data []byte, complete bool, err error) *Packet {
|
|
44
|
+
func NewCallDataPacket(data []byte, dataIsZero bool, complete bool, err error) *Packet {
|
|
44
45
|
var errStr string
|
|
45
46
|
if err != nil {
|
|
46
47
|
errStr = err.Error()
|
|
@@ -48,7 +49,7 @@ func NewCallDataPacket(data []byte, complete bool, err error) *Packet {
|
|
|
48
49
|
return &Packet{Body: &Packet_CallData{
|
|
49
50
|
CallData: &CallData{
|
|
50
51
|
Data: data,
|
|
51
|
-
DataIsZero:
|
|
52
|
+
DataIsZero: dataIsZero,
|
|
52
53
|
Complete: err != nil || complete,
|
|
53
54
|
Error: errStr,
|
|
54
55
|
},
|
package/srpc/rpc-stream.go
CHANGED
|
@@ -42,7 +42,7 @@ func (r *RPCStream) MsgSend(msg Message) error {
|
|
|
42
42
|
if err != nil {
|
|
43
43
|
return err
|
|
44
44
|
}
|
|
45
|
-
outPkt := NewCallDataPacket(msgData, false, nil)
|
|
45
|
+
outPkt := NewCallDataPacket(msgData, len(msgData) == 0, false, nil)
|
|
46
46
|
return r.writer.WritePacket(outPkt)
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -62,7 +62,7 @@ func (r *RPCStream) MsgRecv(msg Message) error {
|
|
|
62
62
|
|
|
63
63
|
// CloseSend signals to the remote that we will no longer send any messages.
|
|
64
64
|
func (r *RPCStream) CloseSend() error {
|
|
65
|
-
outPkt := NewCallDataPacket(nil, true, nil)
|
|
65
|
+
outPkt := NewCallDataPacket(nil, false, true, nil)
|
|
66
66
|
return r.writer.WritePacket(outPkt)
|
|
67
67
|
}
|
|
68
68
|
|
package/srpc/server-rpc.go
CHANGED
|
@@ -138,7 +138,7 @@ func (r *ServerRPC) invokeRPC() {
|
|
|
138
138
|
if err == nil && !ok {
|
|
139
139
|
err = ErrUnimplemented
|
|
140
140
|
}
|
|
141
|
-
outPkt := NewCallDataPacket(nil, true, err)
|
|
141
|
+
outPkt := NewCallDataPacket(nil, false, true, err)
|
|
142
142
|
_ = r.writer.WritePacket(outPkt)
|
|
143
143
|
r.ctxCancel()
|
|
144
144
|
_ = r.writer.Close()
|
|
@@ -149,7 +149,7 @@ func (r *ServerRPC) invokeRPC() {
|
|
|
149
149
|
func (r *ServerRPC) Close() {
|
|
150
150
|
r.ctxCancel()
|
|
151
151
|
if r.service == "" {
|
|
152
|
-
// invokeRPC has not been called
|
|
152
|
+
// invokeRPC has not been called, otherwise it would call Close()
|
|
153
153
|
_ = r.writer.Close()
|
|
154
154
|
}
|
|
155
155
|
}
|
package/srpc/server.go
CHANGED
|
@@ -27,7 +27,9 @@ func (s *Server) HandleStream(ctx context.Context, rwc io.ReadWriteCloser) error
|
|
|
27
27
|
serverRPC := NewServerRPC(subCtx, s.mux)
|
|
28
28
|
prw := NewPacketReadWriter(rwc, serverRPC.HandlePacket)
|
|
29
29
|
serverRPC.SetWriter(prw)
|
|
30
|
-
|
|
30
|
+
err := prw.ReadPump()
|
|
31
|
+
_ = rwc.Close()
|
|
32
|
+
return err
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
// AcceptMuxedConn runs a loop which calls Accept on a muxer to handle streams.
|
package/srpc/websocket.go
CHANGED
package/srpc/websocket.ts
CHANGED