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 CHANGED
@@ -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);
@@ -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);
@@ -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) => {
@@ -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();
@@ -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
  });
@@ -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,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;
@@ -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
  }
@@ -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)
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:tCgC8yXtleyOg/mp+ZoCcA+aryAhueCfFmAVXURT/PM=
69
- github.com/libp2p/go-libp2p v0.20.1/go.mod h1:XgJHsOhEBVBXp/2Sj9bm/yEyD94uunAaP6oaegdcKks=
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -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
- pkt := NewCallStartPacket(r.service, r.method, firstMsg)
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) => {
@@ -18,7 +18,7 @@ export class DuplexConn extends Conn {
18
18
  ) {
19
19
  super(server, connParams)
20
20
  this.channel = duplex
21
- pipe(this, this.channel, this)
21
+ pipe(this.channel, this, this.channel)
22
22
  }
23
23
 
24
24
  // getChannelDuplex returns the Duplex channel.
package/srpc/handler.ts CHANGED
@@ -84,28 +84,34 @@ export function createInvokeFn(
84
84
  })
85
85
 
86
86
  // pipe responseSink to dataSink.
87
- const responsePipe = pipe(
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 requestRx = requestDecode(dataSource)
103
- for await (const msg of requestRx) {
104
- requestArg = msg
105
- break
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
- responsePipe.finally(() => {
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: len(data) == 0 && !complete && err == nil,
52
+ DataIsZero: dataIsZero,
52
53
  Complete: err != nil || complete,
53
54
  Error: errStr,
54
55
  },
@@ -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
 
@@ -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
- return prw.ReadPump()
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
@@ -63,6 +63,3 @@ func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler func(pkt *Pac
63
63
  func (w *WebSocketConn) Close() error {
64
64
  return w.conn.Close(websocket.StatusGoingAway, "conn closed")
65
65
  }
66
-
67
- // _ is a type assertion
68
- var _ Conn = ((*WebSocketConn)(nil))
package/srpc/websocket.ts CHANGED
@@ -17,7 +17,7 @@ export class WebSocketConn extends Conn {
17
17
  })
18
18
  this.socket = socket
19
19
  const socketDuplex = duplex(socket)
20
- pipe(this.source, socketDuplex, this.sink)
20
+ pipe(socketDuplex, this, socketDuplex)
21
21
  }
22
22
 
23
23
  // getSocket returns the websocket.
package/srpc/conn.go DELETED
@@ -1,7 +0,0 @@
1
- package srpc
2
-
3
- // Conn represents a connection to a remote.
4
- type Conn interface {
5
- // GetOpenStreamFunc returns the OpenStream func.
6
- GetOpenStreamFunc() OpenStreamFunc
7
- }