starpc 0.12.2 → 0.13.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  PROTOWRAP=hack/bin/protowrap
4
4
  PROTOC_GEN_GO=hack/bin/protoc-gen-go
5
- PROTOC_GEN_GO_STARPC=hack/bin/protoc-gen-go-starpc
5
+ PROTOC_GEN_STARPC=hack/bin/protoc-gen-go-starpc
6
6
  PROTOC_GEN_VTPROTO=hack/bin/protoc-gen-go-vtproto
7
7
  GOIMPORTS=hack/bin/goimports
8
8
  GOLANGCI_LINT=hack/bin/golangci-lint
@@ -24,18 +24,18 @@ $(PROTOC_GEN_GO):
24
24
  -o ./bin/protoc-gen-go \
25
25
  google.golang.org/protobuf/cmd/protoc-gen-go
26
26
 
27
- $(PROTOC_GEN_GO_STARPC):
28
- cd ./hack; \
29
- go build -v \
30
- -o ./bin/protoc-gen-go-starpc \
31
- github.com/aperturerobotics/starpc/cmd/protoc-gen-go-starpc
32
-
33
27
  $(PROTOC_GEN_VTPROTO):
34
28
  cd ./hack; \
35
29
  go build -v \
36
30
  -o ./bin/protoc-gen-go-vtproto \
37
31
  github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
38
32
 
33
+ $(PROTOC_GEN_STARPC):
34
+ cd ./hack; \
35
+ go build -v \
36
+ -o ./bin/protoc-gen-go-starpc \
37
+ github.com/aperturerobotics/starpc/cmd/protoc-gen-go-starpc
38
+
39
39
  $(GOIMPORTS):
40
40
  cd ./hack; \
41
41
  go build -v \
@@ -46,7 +46,7 @@ $(PROTOWRAP):
46
46
  cd ./hack; \
47
47
  go build -v \
48
48
  -o ./bin/protowrap \
49
- github.com/square/goprotowrap/cmd/protowrap
49
+ github.com/aperturerobotics/goprotowrap/cmd/protowrap
50
50
 
51
51
  $(GOLANGCI_LINT):
52
52
  cd ./hack; \
@@ -61,7 +61,7 @@ $(GO_MOD_OUTDATED):
61
61
  github.com/psampaz/go-mod-outdated
62
62
 
63
63
  .PHONY: gengo
64
- gengo: $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTOC_GEN_GO_STARPC) $(PROTOC_GEN_VTPROTO)
64
+ gengo: $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTOC_GEN_VTPROTO) $(PROTOC_GEN_STARPC)
65
65
  go mod vendor
66
66
  shopt -s globstar; \
67
67
  set -eo pipefail; \
@@ -73,9 +73,9 @@ gengo: $(GOIMPORTS) $(PROTOWRAP) $(PROTOC_GEN_GO) $(PROTOC_GEN_GO_STARPC) $(PROT
73
73
  $(PROTOWRAP) \
74
74
  -I $$(pwd)/vendor \
75
75
  --go_out=$$(pwd)/vendor \
76
- --go-starpc_out=$$(pwd)/vendor \
77
76
  --go-vtproto_out=$$(pwd)/vendor \
78
- --go-vtproto_opt=features=marshal+unmarshal+size+equal \
77
+ --go-vtproto_opt=features=marshal+unmarshal+size+equal+clone \
78
+ --go-starpc_out=$$(pwd)/vendor \
79
79
  --proto_path $$(pwd)/vendor \
80
80
  --print_structure \
81
81
  --only_specified_files \
@@ -110,6 +110,7 @@ gents: $(PROTOWRAP) node_modules
110
110
  --ts_proto_opt=forceLong=long \
111
111
  --ts_proto_opt=oneof=unions \
112
112
  --ts_proto_opt=outputServices=default,outputServices=generic-definitions \
113
+ --ts_proto_opt=useDate=true \
113
114
  --ts_proto_opt=useAsyncIterable=true \
114
115
  --proto_path $$(pwd)/vendor \
115
116
  --print_structure \
package/README.md CHANGED
@@ -15,14 +15,9 @@
15
15
 
16
16
  [Proto3 services]: https://developers.google.com/protocol-buffers/docs/proto3#services
17
17
 
18
- Supports **client-to-server streaming** RPCs in the web browser, currently not
19
- supported by any of the other RPC libraries.
18
+ Supports **client-to-server and bidirectional streaming** in the web browser.
20
19
 
21
- The [rpcproto](./srpc/rpcproto.proto) file describes the protocol.
22
-
23
- Can use any Stream multiplexer: defaults to [libp2p-mplex] over a WebSocket.
24
-
25
- [libp2p-mplex]: https://github.com/libp2p/js-libp2p-mplex
20
+ [rpcproto.proto](./srpc/rpcproto.proto) contains the protocol definition.
26
21
 
27
22
  [rpcstream] supports sub-streams for per-component sub-services.
28
23
 
@@ -115,11 +110,7 @@ example of TypeScript <-> TypeScript interop, see the [e2e] test.
115
110
  [e2e]: ./e2e/e2e.ts
116
111
  [integration]: ./integration/integration.ts
117
112
 
118
- Supports any AsyncIterable communication channel. `DuplexConn`,
119
- `MessagePortConn`, and `WebSocketConn` use [js-libp2p-mplex] to multiplex
120
- streams, but any multiplexer can be used.
121
-
122
- [js-libp2p-mplex]: https://github.com/libp2p/js-libp2p-mplex
113
+ Supports any AsyncIterable communication channel.
123
114
 
124
115
  This example demonstrates both the server and client:
125
116
 
@@ -185,7 +176,7 @@ const result = await demoServiceClient.Echo({
185
176
  console.log('output', result.body)
186
177
  ```
187
178
 
188
- # Attribution
179
+ ## Attribution
189
180
 
190
181
  `protoc-gen-go-starpc` is a heavily modified version of `protoc-gen-go-drpc`.
191
182
 
@@ -199,15 +190,11 @@ Uses [vtprotobuf] to generate Protobuf marshal / unmarshal code.
199
190
 
200
191
  ## Support
201
192
 
202
- Starpc is built & supported by Aperture Robotics, LLC.
203
-
204
- Community contributions and discussion are welcomed!
205
-
206
- Please open a [GitHub issue] with any questions / issues.
193
+ Please file a [GitHub issue] and/or [Join Discord] with any questions.
207
194
 
208
195
  [GitHub issue]: https://github.com/aperturerobotics/starpc/issues/new
209
196
 
210
- ... or feel free to reach out on [Matrix Chat] or [Discord].
197
+ ... or feel free to reach out on [Matrix Chat].
211
198
 
212
- [Discord]: https://discord.gg/KJutMESRsT
199
+ [Join Discord]: https://discord.gg/KJutMESRsT
213
200
  [Matrix Chat]: https://matrix.to/#/#aperturerobotics:matrix.org
package/dist/e2e/e2e.js CHANGED
@@ -17,6 +17,7 @@ async function runRPC() {
17
17
  runRPC()
18
18
  .then(() => {
19
19
  console.log('finished successfully');
20
+ process.exit(0);
20
21
  })
21
22
  .catch((err) => {
22
23
  console.error(err);
@@ -35,7 +35,9 @@ export interface Echoer {
35
35
  export declare class EchoerClientImpl implements Echoer {
36
36
  private readonly rpc;
37
37
  private readonly service;
38
- constructor(rpc: Rpc, service?: string);
38
+ constructor(rpc: Rpc, opts?: {
39
+ service?: string;
40
+ });
39
41
  Echo(request: EchoMsg): Promise<EchoMsg>;
40
42
  EchoServerStream(request: EchoMsg): AsyncIterable<EchoMsg>;
41
43
  EchoClientStream(request: AsyncIterable<EchoMsg>): Promise<EchoMsg>;
@@ -73,8 +73,8 @@ export const EchoMsg = {
73
73
  },
74
74
  };
75
75
  export class EchoerClientImpl {
76
- constructor(rpc, service) {
77
- this.service = service || "echo.Echoer";
76
+ constructor(rpc, opts) {
77
+ this.service = opts?.service || "echo.Echoer";
78
78
  this.rpc = rpc;
79
79
  this.Echo = this.Echo.bind(this);
80
80
  this.EchoServerStream = this.EchoServerStream.bind(this);
@@ -116,7 +116,7 @@ export class CommonRPC {
116
116
  }
117
117
  catch (err) {
118
118
  const anyErr = err;
119
- if (anyErr?.code !== 'ERR_MPLEX_STREAM_RESET') {
119
+ if (anyErr?.code !== 'ERR_STREAM_RESET' && anyErr?.code !== 'ERR_STREAM_ABORT') {
120
120
  this.close(err);
121
121
  }
122
122
  }
package/dist/srpc/conn.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { pipe } from 'it-pipe';
2
- import { mplex } from '@libp2p/mplex';
2
+ import { yamux } from '@chainsafe/libp2p-yamux';
3
3
  import isPromise from 'is-promise';
4
4
  import { Client } from './client.js';
5
5
  import { combineUint8ArrayListTransform } from './array-list.js';
@@ -21,7 +21,7 @@ export class Conn {
21
21
  }
22
22
  let muxerFactory = connParams?.muxerFactory;
23
23
  if (!muxerFactory) {
24
- muxerFactory = mplex()();
24
+ muxerFactory = yamux()();
25
25
  }
26
26
  this.muxer = muxerFactory.createStreamMuxer({
27
27
  onIncomingStream: this.handleIncomingStream.bind(this),
@@ -1,14 +1,10 @@
1
1
  import { duplex } from 'it-ws';
2
2
  import { pipe } from 'it-pipe';
3
- import { mplex } from '@libp2p/mplex';
4
3
  import { Conn } from './conn.js';
5
4
  // WebSocketConn implements a connection with a WebSocket and optional Server.
6
5
  export class WebSocketConn extends Conn {
7
6
  constructor(socket, direction, server) {
8
- super(server, {
9
- direction,
10
- muxerFactory: mplex()(),
11
- });
7
+ super(server, { direction });
12
8
  this.socket = socket;
13
9
  const socketDuplex = duplex(socket);
14
10
  pipe(socketDuplex, this, socketDuplex);
package/e2e/e2e.ts CHANGED
@@ -21,6 +21,7 @@ async function runRPC() {
21
21
  runRPC()
22
22
  .then(() => {
23
23
  console.log('finished successfully')
24
+ process.exit(0)
24
25
  })
25
26
  .catch((err) => {
26
27
  console.error(err)
package/e2e/e2e_test.go CHANGED
@@ -5,13 +5,10 @@ import (
5
5
  "io"
6
6
  "net"
7
7
  "testing"
8
- "time"
9
8
 
10
9
  "github.com/aperturerobotics/starpc/echo"
11
10
  "github.com/aperturerobotics/starpc/rpcstream"
12
11
  "github.com/aperturerobotics/starpc/srpc"
13
- "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
14
- mp "github.com/libp2p/go-mplex"
15
12
  "github.com/pkg/errors"
16
13
  )
17
14
 
@@ -25,7 +22,7 @@ func RunE2E(t *testing.T, cb func(client echo.SRPCEchoerClient) error) {
25
22
  }
26
23
  server := srpc.NewServer(mux)
27
24
 
28
- // note: also possible to do without mplex:
25
+ // Alternatively:
29
26
  // openStream := srpc.NewServerPipe(server)
30
27
  // client := srpc.NewClient(openStream)
31
28
 
@@ -33,23 +30,22 @@ func RunE2E(t *testing.T, cb func(client echo.SRPCEchoerClient) error) {
33
30
  clientPipe, serverPipe := net.Pipe()
34
31
 
35
32
  // outbound=true
36
- clientMp, err := mp.NewMultiplex(clientPipe, true, nil)
33
+ clientMp, err := srpc.NewMuxedConn(clientPipe, true)
37
34
  if err != nil {
38
35
  t.Fatal(err.Error())
39
36
  }
40
- client := srpc.NewClientWithMuxedConn(mplex.NewMuxedConn(clientMp))
37
+ client := srpc.NewClientWithMuxedConn(clientMp)
41
38
 
42
39
  ctx := context.Background()
43
40
  // outbound=false
44
- serverMp, _ := mp.NewMultiplex(serverPipe, false, nil)
41
+ serverMp, err := srpc.NewMuxedConn(serverPipe, false)
42
+ if err != nil {
43
+ t.Fatal(err.Error())
44
+ }
45
45
  go func() {
46
- _ = server.AcceptMuxedConn(ctx, mplex.NewMuxedConn(serverMp))
46
+ _ = server.AcceptMuxedConn(ctx, serverMp)
47
47
  }()
48
48
 
49
- // TODO: requires a moment for the listener to start: not sure why.
50
- // the packets /should/ be buffered in the pipe.
51
- <-time.After(time.Millisecond * 100)
52
-
53
49
  // construct the client rpc interface
54
50
  clientEcho := echo.NewSRPCEchoerClient(client)
55
51
 
package/echo/echo.pb.ts CHANGED
@@ -106,8 +106,8 @@ export interface Echoer {
106
106
  export class EchoerClientImpl implements Echoer {
107
107
  private readonly rpc: Rpc;
108
108
  private readonly service: string;
109
- constructor(rpc: Rpc, service?: string) {
110
- this.service = service || "echo.Echoer";
109
+ constructor(rpc: Rpc, opts?: { service?: string }) {
110
+ this.service = opts?.service || "echo.Echoer";
111
111
  this.rpc = rpc;
112
112
  this.Echo = this.Echo.bind(this);
113
113
  this.EchoServerStream = this.EchoServerStream.bind(this);
@@ -1,5 +1,5 @@
1
1
  // Code generated by protoc-gen-srpc. DO NOT EDIT.
2
- // protoc-gen-srpc version: v0.9.2
2
+ // protoc-gen-srpc version: v0.12.3-0.20221016080028-3e0cb248fdee
3
3
  // source: github.com/aperturerobotics/starpc/echo/echo.proto
4
4
 
5
5
  package echo
@@ -9,6 +9,7 @@ import (
9
9
  io "io"
10
10
  bits "math/bits"
11
11
 
12
+ proto "google.golang.org/protobuf/proto"
12
13
  protoimpl "google.golang.org/protobuf/runtime/protoimpl"
13
14
  )
14
15
 
@@ -19,6 +20,24 @@ const (
19
20
  _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
20
21
  )
21
22
 
23
+ func (m *EchoMsg) CloneVT() *EchoMsg {
24
+ if m == nil {
25
+ return (*EchoMsg)(nil)
26
+ }
27
+ r := &EchoMsg{
28
+ Body: m.Body,
29
+ }
30
+ if len(m.unknownFields) > 0 {
31
+ r.unknownFields = make([]byte, len(m.unknownFields))
32
+ copy(r.unknownFields, m.unknownFields)
33
+ }
34
+ return r
35
+ }
36
+
37
+ func (m *EchoMsg) CloneGenericVT() proto.Message {
38
+ return m.CloneVT()
39
+ }
40
+
22
41
  func (this *EchoMsg) EqualVT(that *EchoMsg) bool {
23
42
  if this == nil {
24
43
  return that == nil
package/go.mod CHANGED
@@ -9,8 +9,8 @@ require (
9
9
  )
10
10
 
11
11
  require (
12
- github.com/libp2p/go-libp2p v0.23.2
13
- github.com/libp2p/go-mplex v0.7.1-0.20220919134208-b0cc3e9c41a9
12
+ github.com/libp2p/go-libp2p v0.23.3-0.20221025171119-7465a509d011
13
+ github.com/libp2p/go-yamux/v4 v4.0.1-0.20220919134236-1c09f2ab3ec1
14
14
  github.com/sirupsen/logrus v1.9.0
15
15
  )
16
16
 
@@ -18,12 +18,10 @@ require (
18
18
  github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
19
19
  github.com/gogo/protobuf v1.3.2 // indirect
20
20
  github.com/ipfs/go-cid v0.3.2 // indirect
21
- github.com/ipfs/go-log/v2 v2.5.1 // indirect
22
21
  github.com/klauspost/compress v1.15.10 // indirect
23
22
  github.com/klauspost/cpuid/v2 v2.1.1 // indirect
24
23
  github.com/libp2p/go-buffer-pool v0.1.0 // indirect
25
24
  github.com/libp2p/go-openssl v0.1.0 // indirect
26
- github.com/mattn/go-isatty v0.0.16 // indirect
27
25
  github.com/mattn/go-pointer v0.0.1 // indirect
28
26
  github.com/minio/sha256-simd v1.0.0 // indirect
29
27
  github.com/mr-tron/base58 v1.2.0 // indirect
@@ -36,9 +34,6 @@ require (
36
34
  github.com/multiformats/go-varint v0.0.6 // indirect
37
35
  github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
38
36
  github.com/spaolacci/murmur3 v1.1.0 // indirect
39
- go.uber.org/atomic v1.10.0 // indirect
40
- go.uber.org/multierr v1.8.0 // indirect
41
- go.uber.org/zap v1.23.0 // indirect
42
37
  golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
43
38
  golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
44
39
  lukechampine.com/blake3 v1.1.7 // indirect
package/go.sum CHANGED
@@ -1,5 +1,3 @@
1
- github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
2
- github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
3
1
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4
2
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5
3
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -37,8 +35,6 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
37
35
  github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
38
36
  github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
39
37
  github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
40
- github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
41
- github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
42
38
  github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
43
39
  github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
44
40
  github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -50,24 +46,19 @@ github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
50
46
  github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
51
47
  github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
52
48
  github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
53
- github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
54
- github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
55
- github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
56
49
  github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
57
50
  github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
58
51
  github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
59
52
  github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
60
- github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE=
61
- github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI=
53
+ github.com/libp2p/go-libp2p v0.23.3-0.20221025171119-7465a509d011 h1:HCFywK5/BqCNO8peqtP1DK52y2FKDVilZE5b5g5Gg4s=
54
+ github.com/libp2p/go-libp2p v0.23.3-0.20221025171119-7465a509d011/go.mod h1:9lqLgktzI5Gn2bplyrZvFSuDirYRBMU+Tu/FYBIjvek=
62
55
  github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
63
- github.com/libp2p/go-mplex v0.7.1-0.20220919134208-b0cc3e9c41a9 h1:PolwtQpl5xZ7j59zsvFEF3oEDxXDcLH6cVYK3qAFiMc=
64
- github.com/libp2p/go-mplex v0.7.1-0.20220919134208-b0cc3e9c41a9/go.mod h1:bUU7Bl6gVaLs+DK8DyT4VKY2XhsgxLmafxHCesUq+j0=
65
56
  github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo=
66
57
  github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc=
58
+ github.com/libp2p/go-yamux/v4 v4.0.1-0.20220919134236-1c09f2ab3ec1 h1:fxyHejZvFIBqlznQDuHUkw9BThYKyoT3DclP/C2g8Wc=
59
+ github.com/libp2p/go-yamux/v4 v4.0.1-0.20220919134236-1c09f2ab3ec1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
67
60
  github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
68
- github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
69
61
  github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
70
- github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
71
62
  github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
72
63
  github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
73
64
  github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
@@ -92,7 +83,6 @@ github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d
92
83
  github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
93
84
  github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
94
85
  github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
95
- github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
96
86
  github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
97
87
  github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
98
88
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -114,60 +104,36 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
114
104
  github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
115
105
  github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
116
106
  github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
117
- github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
118
- go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
119
- go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
120
- go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
121
- go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
122
- go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
123
- go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
124
- go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
125
- go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
126
- go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
127
- go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
128
- go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
129
107
  golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
130
108
  golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
131
109
  golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
132
110
  golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
133
111
  golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
134
- golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
135
112
  golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
136
113
  golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
137
- golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
138
- golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
139
114
  golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
140
115
  golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
141
116
  golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
142
117
  golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
143
- golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
144
118
  golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
145
119
  golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
146
120
  golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
147
- golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
148
121
  golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
149
122
  golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
150
123
  golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
151
124
  golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
152
- golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
153
- golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
154
- golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
155
- golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
156
125
  golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
157
126
  golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
158
127
  golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
159
128
  golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
160
- golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
161
129
  golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
162
130
  golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
163
131
  golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
164
132
  golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
165
133
  golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
166
- golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
167
134
  golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
168
135
  golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
169
136
  golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
170
- golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
171
137
  golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
172
138
  golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
173
139
  golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -177,12 +143,10 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
177
143
  google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
178
144
  google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
179
145
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
180
- gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
181
146
  gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
182
147
  gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
183
148
  gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
184
149
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
185
- gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
186
150
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
187
151
  lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
188
152
  lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -36,7 +36,7 @@
36
36
  "build": "rimraf ./dist && tsc --project tsconfig.build.json --outDir ./dist/",
37
37
  "check": "npm run typecheck",
38
38
  "typecheck": "tsc --noEmit",
39
- "deps": "depcheck --ignores 'bufferutil,utf-8-validate'",
39
+ "deps": "depcheck --ignores 'bufferutil,utf-8-validate,ts-proto'",
40
40
  "codegen": "npm run gen",
41
41
  "ci": "npm run build && npm run lint:js && npm run lint:go",
42
42
  "format": "prettier --write './{srpc,echo,e2e,integration,rpcstream}/**/(*.ts|*.tsx|*.html|*.css)'",
@@ -59,36 +59,36 @@
59
59
  "singleQuote": true
60
60
  },
61
61
  "devDependencies": {
62
- "@typescript-eslint/eslint-plugin": "^5.40.0",
63
- "@typescript-eslint/parser": "^5.40.0",
64
- "bufferutil": "^4.0.6",
62
+ "@typescript-eslint/eslint-plugin": "^5.41.0",
63
+ "@typescript-eslint/parser": "^5.41.0",
64
+ "bufferutil": "^4.0.7",
65
65
  "depcheck": "^1.4.3",
66
- "esbuild": "^0.15.11",
67
- "eslint": "^8.25.0",
66
+ "esbuild": "^0.15.12",
67
+ "eslint": "^8.26.0",
68
68
  "eslint-config-prettier": "^8.5.0",
69
69
  "prettier": "^2.7.1",
70
70
  "rimraf": "^3.0.2",
71
- "ts-proto": "^1.128.0",
71
+ "ts-proto": "^1.130.0",
72
72
  "typescript": "^4.8.4",
73
- "utf-8-validate": "^5.0.9"
73
+ "utf-8-validate": "^5.0.10"
74
74
  },
75
75
  "dependencies": {
76
+ "@chainsafe/libp2p-yamux": "^3.0.2",
76
77
  "@libp2p/interface-connection": "^3.0.2",
77
78
  "@libp2p/interface-stream-muxer": "^3.0.0",
78
- "@libp2p/mplex": "^7.0.0",
79
79
  "event-iterator": "^2.0.0",
80
80
  "is-promise": "^4.0.0",
81
81
  "isomorphic-ws": "^5.0.0",
82
- "it-first": "^1.0.7",
82
+ "it-first": "^2.0.0",
83
83
  "it-length-prefixed": "^8.0.3",
84
84
  "it-pipe": "^2.0.4",
85
85
  "it-pushable": "^3.1.0",
86
86
  "it-stream-types": "^1.0.4",
87
87
  "it-ws": "^5.0.3",
88
88
  "long": "^5.2.0",
89
- "patch-package": "^6.4.7",
89
+ "patch-package": "^6.5.0",
90
90
  "protobufjs": "^7.1.2",
91
91
  "uint8arraylist": "^2.3.3",
92
- "ws": "^8.9.0"
92
+ "ws": "^8.10.0"
93
93
  }
94
94
  }
package/srpc/accept.go CHANGED
@@ -7,7 +7,7 @@ import (
7
7
 
8
8
  // AcceptMuxedListener accepts incoming connections from a net.Listener.
9
9
  //
10
- // Uses the default mplex muxer.
10
+ // Uses the default yamux muxer.
11
11
  func AcceptMuxedListener(ctx context.Context, lis net.Listener, srv *Server) error {
12
12
  for {
13
13
  nc, err := lis.Accept()
@@ -185,5 +185,7 @@ func (r *ClientRPC) HandleCallData(pkt *CallData) error {
185
185
  // not concurrency safe with HandlePacket.
186
186
  func (r *ClientRPC) Close() {
187
187
  r.ctxCancel()
188
- _ = r.writer.Close()
188
+ if r.writer != nil {
189
+ _ = r.writer.Close()
190
+ }
189
191
  }
package/srpc/client.go CHANGED
@@ -87,7 +87,7 @@ func (c *client) NewStream(ctx context.Context, service, method string, firstMsg
87
87
  return nil, err
88
88
  }
89
89
 
90
- return NewMsgStream(ctx, clientRPC.writer, clientRPC.dataCh), nil
90
+ return NewMsgStream(ctx, clientRPC.writer, clientRPC.dataCh, clientRPC.ctxCancel), nil
91
91
  }
92
92
 
93
93
  // _ is a type assertion
@@ -159,7 +159,7 @@ export class CommonRPC {
159
159
  }
160
160
  } catch (err) {
161
161
  const anyErr = err as any
162
- if (anyErr?.code !== 'ERR_MPLEX_STREAM_RESET') {
162
+ if (anyErr?.code !== 'ERR_STREAM_RESET' && anyErr?.code !== 'ERR_STREAM_ABORT') {
163
163
  this.close(err as Error)
164
164
  }
165
165
  }
package/srpc/conn.ts CHANGED
@@ -5,7 +5,7 @@ import type {
5
5
  } from '@libp2p/interface-stream-muxer'
6
6
  import { pipe } from 'it-pipe'
7
7
  import type { Duplex } from 'it-stream-types'
8
- import { mplex } from '@libp2p/mplex'
8
+ import { yamux } from '@chainsafe/libp2p-yamux'
9
9
  import { Uint8ArrayList } from 'uint8arraylist'
10
10
  import isPromise from 'is-promise'
11
11
 
@@ -15,10 +15,10 @@ import { combineUint8ArrayListTransform } from './array-list.js'
15
15
 
16
16
  // ConnParams are parameters that can be passed to the Conn constructor.
17
17
  export interface ConnParams {
18
- // muxerFactory overrides using the default factory (@libp2p/mplex).
18
+ // muxerFactory overrides using the default yamux factory.
19
19
  muxerFactory?: StreamMuxerFactory
20
20
  // direction is the muxer connection direction.
21
- // defaults to outbound.
21
+ // defaults to outbound (client).
22
22
  direction?: Direction
23
23
  }
24
24
 
@@ -44,7 +44,7 @@ export function streamToSRPCStream(
44
44
  // Implements the server by handling incoming streams.
45
45
  // If the server is unset, rejects any incoming streams.
46
46
  export class Conn implements Duplex<Uint8Array> {
47
- // muxer is the mplex stream muxer.
47
+ // muxer is the stream muxer.
48
48
  private muxer: StreamMuxer
49
49
  // server is the server side, if set.
50
50
  private server?: StreamHandler
@@ -55,7 +55,7 @@ export class Conn implements Duplex<Uint8Array> {
55
55
  }
56
56
  let muxerFactory = connParams?.muxerFactory
57
57
  if (!muxerFactory) {
58
- muxerFactory = mplex()()
58
+ muxerFactory = yamux()()
59
59
  }
60
60
  this.muxer = muxerFactory.createStreamMuxer({
61
61
  onIncomingStream: this.handleIncomingStream.bind(this),
@@ -3,6 +3,7 @@ package srpc
3
3
  import (
4
4
  "context"
5
5
  "io"
6
+ "sync/atomic"
6
7
  )
7
8
 
8
9
  // MsgStream implements the stream interface passed to implementations.
@@ -13,15 +14,25 @@ type MsgStream struct {
13
14
  writer Writer
14
15
  // dataCh is the incoming data channel.
15
16
  dataCh chan []byte
17
+ // closeCb is the close callback
18
+ closeCb func()
19
+ // sendClosed indicates sending is closed.
20
+ sendClosed atomic.Bool
16
21
  }
17
22
 
18
23
  // NewMsgStream constructs a new Stream with a ClientRPC.
19
24
  // dataCh should be closed when no more messages will arrive.
20
- func NewMsgStream(ctx context.Context, writer Writer, dataCh chan []byte) *MsgStream {
25
+ func NewMsgStream(
26
+ ctx context.Context,
27
+ writer Writer,
28
+ dataCh chan []byte,
29
+ closeCb func(),
30
+ ) *MsgStream {
21
31
  return &MsgStream{
22
- ctx: ctx,
23
- writer: writer,
24
- dataCh: dataCh,
32
+ ctx: ctx,
33
+ writer: writer,
34
+ dataCh: dataCh,
35
+ closeCb: closeCb,
25
36
  }
26
37
  }
27
38
 
@@ -32,6 +43,9 @@ func (r *MsgStream) Context() context.Context {
32
43
 
33
44
  // MsgSend sends the message to the remote.
34
45
  func (r *MsgStream) MsgSend(msg Message) error {
46
+ if r.sendClosed.Load() {
47
+ return context.Canceled
48
+ }
35
49
  select {
36
50
  case <-r.ctx.Done():
37
51
  return context.Canceled
@@ -62,14 +76,34 @@ func (r *MsgStream) MsgRecv(msg Message) error {
62
76
 
63
77
  // CloseSend signals to the remote that we will no longer send any messages.
64
78
  func (r *MsgStream) CloseSend() error {
65
- outPkt := NewCallDataPacket(nil, false, true, nil)
66
- return r.writer.WritePacket(outPkt)
79
+ // if already closed, return
80
+ if r.sendClosed.Swap(true) {
81
+ return nil
82
+ }
83
+
84
+ return r.closeSend()
67
85
  }
68
86
 
69
87
  // Close closes the stream.
70
88
  func (r *MsgStream) Close() error {
71
- _ = r.writer.Close()
72
- return nil
89
+ // if already closed, return
90
+ if r.sendClosed.Swap(true) {
91
+ return nil
92
+ }
93
+
94
+ // don't close the writer: we will need to write the call result after the
95
+ // RPC function returns.
96
+ if r.closeCb != nil {
97
+ r.closeCb()
98
+ }
99
+
100
+ return r.closeSend()
101
+ }
102
+
103
+ // closeSend writes the CloseSend packet.
104
+ func (r *MsgStream) closeSend() error {
105
+ outPkt := NewCallDataPacket(nil, false, true, nil)
106
+ return r.writer.WritePacket(outPkt)
73
107
  }
74
108
 
75
109
  // _ is a type assertion
package/srpc/mux.go CHANGED
@@ -20,6 +20,9 @@ type muxMethods map[string]Handler
20
20
 
21
21
  // mux is the default implementation of Mux.
22
22
  type mux struct {
23
+ // fallback is the list of fallback invokers
24
+ // if the mux doesn't match the service, calls the invokers.
25
+ fallback []Invoker
23
26
  // rmtx guards below fields
24
27
  rmtx sync.RWMutex
25
28
  // services contains a mapping from services to handlers.
@@ -27,8 +30,14 @@ type mux struct {
27
30
  }
28
31
 
29
32
  // NewMux constructs a new Mux.
30
- func NewMux() Mux {
31
- return &mux{services: make(map[string]muxMethods)}
33
+ //
34
+ // fallbackInvokers is the list of fallback Invokers to call in the case that
35
+ // the service/method is not found on this mux.
36
+ func NewMux(fallbackInvokers ...Invoker) Mux {
37
+ return &mux{
38
+ fallback: fallbackInvokers,
39
+ services: make(map[string]muxMethods),
40
+ }
32
41
  }
33
42
 
34
43
  // Register registers a new RPC method handler (service).
@@ -95,17 +104,34 @@ func (m *mux) HasServiceMethod(serviceID, methodID string) bool {
95
104
  func (m *mux) InvokeMethod(serviceID, methodID string, strm Stream) (bool, error) {
96
105
  var handler Handler
97
106
  m.rmtx.RLock()
98
- svcMethods := m.services[serviceID]
99
- if svcMethods != nil {
100
- handler = svcMethods[methodID]
107
+ if serviceID == "" {
108
+ for _, svc := range m.services {
109
+ if handler = svc[methodID]; handler != nil {
110
+ break
111
+ }
112
+ }
113
+ } else {
114
+ svcMethods := m.services[serviceID]
115
+ if svcMethods != nil {
116
+ handler = svcMethods[methodID]
117
+ }
101
118
  }
102
119
  m.rmtx.RUnlock()
103
120
 
104
- if handler == nil {
105
- return false, nil
121
+ if handler != nil {
122
+ return handler.InvokeMethod(serviceID, methodID, strm)
123
+ }
124
+
125
+ for _, invoker := range m.fallback {
126
+ if invoker != nil {
127
+ handled, err := invoker.InvokeMethod(serviceID, methodID, strm)
128
+ if err != nil || handled {
129
+ return handled, err
130
+ }
131
+ }
106
132
  }
107
133
 
108
- return handler.InvokeMethod(serviceID, methodID, strm)
134
+ return false, nil
109
135
  }
110
136
 
111
137
  // _ is a type assertion
@@ -6,17 +6,33 @@ import (
6
6
  "net"
7
7
 
8
8
  "github.com/libp2p/go-libp2p/core/network"
9
- mplex "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
10
- mp "github.com/libp2p/go-mplex"
9
+ ymuxer "github.com/libp2p/go-libp2p/p2p/muxer/yamux"
10
+ yamux "github.com/libp2p/go-yamux/v4"
11
11
  )
12
12
 
13
+ // NewYamuxConfig builds the default yamux configuration.
14
+ func NewYamuxConfig() *yamux.Config {
15
+ // Configuration options from go-libp2p-yamux:
16
+ config := *ymuxer.DefaultTransport.Config()
17
+ return &config
18
+ }
19
+
13
20
  // NewMuxedConn constructs a new MuxedConn from a net.Conn.
14
21
  func NewMuxedConn(conn net.Conn, outbound bool) (network.MuxedConn, error) {
15
- m, err := mp.NewMultiplex(conn, outbound, nil)
22
+ yamuxConf := NewYamuxConfig()
23
+
24
+ var sess *yamux.Session
25
+ var err error
26
+ if outbound {
27
+ sess, err = yamux.Client(conn, yamuxConf, nil)
28
+ } else {
29
+ sess, err = yamux.Server(conn, yamuxConf, nil)
30
+ }
16
31
  if err != nil {
17
32
  return nil, err
18
33
  }
19
- return mplex.NewMuxedConn(m), nil
34
+
35
+ return ymuxer.NewMuxedConn(sess), nil
20
36
  }
21
37
 
22
38
  // NewMuxedConnWithRwc builds a new MuxedConn with a io.ReadWriteCloser.
@@ -25,8 +41,6 @@ func NewMuxedConnWithRwc(ctx context.Context, rwc io.ReadWriteCloser, outbound b
25
41
  }
26
42
 
27
43
  // NewClientWithConn constructs the muxer and the client.
28
- //
29
- // uses libp2p mplex
30
44
  func NewClientWithConn(conn net.Conn, outbound bool) (Client, error) {
31
45
  mconn, err := NewMuxedConn(conn, outbound)
32
46
  if err != nil {
package/srpc/packet-rw.go CHANGED
@@ -5,6 +5,7 @@ import (
5
5
  "context"
6
6
  "encoding/binary"
7
7
  "io"
8
+ "sync"
8
9
 
9
10
  "github.com/pkg/errors"
10
11
  )
@@ -19,6 +20,8 @@ type PacketReaderWriter struct {
19
20
  rw io.ReadWriteCloser
20
21
  // buf is the buffered data
21
22
  buf bytes.Buffer
23
+ // writeMtx is the write mutex
24
+ writeMtx sync.Mutex
22
25
  }
23
26
 
24
27
  // NewPacketReadWriter constructs a new read/writer.
@@ -28,6 +31,9 @@ func NewPacketReadWriter(rw io.ReadWriteCloser) *PacketReaderWriter {
28
31
 
29
32
  // WritePacket writes a packet to the writer.
30
33
  func (r *PacketReaderWriter) WritePacket(p *Packet) error {
34
+ r.writeMtx.Lock()
35
+ defer r.writeMtx.Unlock()
36
+
31
37
  msgSize := p.SizeVT()
32
38
  data := make([]byte, 4+msgSize)
33
39
  binary.LittleEndian.PutUint32(data, uint32(msgSize))
@@ -9,6 +9,7 @@ import (
9
9
  io "io"
10
10
  bits "math/bits"
11
11
 
12
+ proto "google.golang.org/protobuf/proto"
12
13
  protoimpl "google.golang.org/protobuf/runtime/protoimpl"
13
14
  )
14
15
 
@@ -19,6 +20,95 @@ const (
19
20
  _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
20
21
  )
21
22
 
23
+ func (m *Packet) CloneVT() *Packet {
24
+ if m == nil {
25
+ return (*Packet)(nil)
26
+ }
27
+ r := &Packet{}
28
+ if m.Body != nil {
29
+ r.Body = m.Body.(interface{ CloneVT() isPacket_Body }).CloneVT()
30
+ }
31
+ if len(m.unknownFields) > 0 {
32
+ r.unknownFields = make([]byte, len(m.unknownFields))
33
+ copy(r.unknownFields, m.unknownFields)
34
+ }
35
+ return r
36
+ }
37
+
38
+ func (m *Packet) CloneGenericVT() proto.Message {
39
+ return m.CloneVT()
40
+ }
41
+
42
+ func (m *Packet_CallStart) CloneVT() isPacket_Body {
43
+ if m == nil {
44
+ return (*Packet_CallStart)(nil)
45
+ }
46
+ r := &Packet_CallStart{
47
+ CallStart: m.CallStart.CloneVT(),
48
+ }
49
+ return r
50
+ }
51
+
52
+ func (m *Packet_CallData) CloneVT() isPacket_Body {
53
+ if m == nil {
54
+ return (*Packet_CallData)(nil)
55
+ }
56
+ r := &Packet_CallData{
57
+ CallData: m.CallData.CloneVT(),
58
+ }
59
+ return r
60
+ }
61
+
62
+ func (m *CallStart) CloneVT() *CallStart {
63
+ if m == nil {
64
+ return (*CallStart)(nil)
65
+ }
66
+ r := &CallStart{
67
+ RpcService: m.RpcService,
68
+ RpcMethod: m.RpcMethod,
69
+ DataIsZero: m.DataIsZero,
70
+ }
71
+ if rhs := m.Data; rhs != nil {
72
+ tmpBytes := make([]byte, len(rhs))
73
+ copy(tmpBytes, rhs)
74
+ r.Data = tmpBytes
75
+ }
76
+ if len(m.unknownFields) > 0 {
77
+ r.unknownFields = make([]byte, len(m.unknownFields))
78
+ copy(r.unknownFields, m.unknownFields)
79
+ }
80
+ return r
81
+ }
82
+
83
+ func (m *CallStart) CloneGenericVT() proto.Message {
84
+ return m.CloneVT()
85
+ }
86
+
87
+ func (m *CallData) CloneVT() *CallData {
88
+ if m == nil {
89
+ return (*CallData)(nil)
90
+ }
91
+ r := &CallData{
92
+ DataIsZero: m.DataIsZero,
93
+ Complete: m.Complete,
94
+ Error: m.Error,
95
+ }
96
+ if rhs := m.Data; rhs != nil {
97
+ tmpBytes := make([]byte, len(rhs))
98
+ copy(tmpBytes, rhs)
99
+ r.Data = tmpBytes
100
+ }
101
+ if len(m.unknownFields) > 0 {
102
+ r.unknownFields = make([]byte, len(m.unknownFields))
103
+ copy(r.unknownFields, m.unknownFields)
104
+ }
105
+ return r
106
+ }
107
+
108
+ func (m *CallData) CloneGenericVT() proto.Message {
109
+ return m.CloneVT()
110
+ }
111
+
22
112
  func (this *Packet) EqualVT(that *Packet) bool {
23
113
  if this == nil {
24
114
  return that == nil
@@ -164,7 +164,7 @@ func (r *ServerRPC) HandleCallData(pkt *CallData) error {
164
164
  func (r *ServerRPC) invokeRPC() {
165
165
  // ctx := r.ctx
166
166
  serviceID, methodID := r.service, r.method
167
- strm := NewMsgStream(r.ctx, r.writer, r.dataCh)
167
+ strm := NewMsgStream(r.ctx, r.writer, r.dataCh, r.ctxCancel)
168
168
  ok, err := r.invoker.InvokeMethod(serviceID, methodID, strm)
169
169
  if err == nil && !ok {
170
170
  err = ErrUnimplemented
@@ -181,7 +181,7 @@ func (r *ServerRPC) Close() {
181
181
  if r.clientErr == nil {
182
182
  r.clientErr = context.Canceled
183
183
  }
184
- if r.service == "" {
184
+ if r.writer != nil && r.service == "" {
185
185
  // invokeRPC has not been called, otherwise it would call Close()
186
186
  _ = r.writer.Close()
187
187
  }
package/srpc/server.go CHANGED
@@ -40,18 +40,18 @@ func (s *Server) HandleStream(ctx context.Context, rwc io.ReadWriteCloser) error
40
40
  //
41
41
  // Starts HandleStream in a separate goroutine to handle the stream.
42
42
  // Returns context.Canceled or io.EOF when the loop is complete / closed.
43
- func (s *Server) AcceptMuxedConn(ctx context.Context, mplex network.MuxedConn) error {
43
+ func (s *Server) AcceptMuxedConn(ctx context.Context, mc network.MuxedConn) error {
44
44
  for {
45
45
  select {
46
46
  case <-ctx.Done():
47
47
  return context.Canceled
48
48
  default:
49
- if mplex.IsClosed() {
49
+ if mc.IsClosed() {
50
50
  return io.EOF
51
51
  }
52
52
  }
53
53
 
54
- muxedStream, err := mplex.AcceptStream()
54
+ muxedStream, err := mc.AcceptStream()
55
55
  if err != nil {
56
56
  return err
57
57
  }
package/srpc/websocket.go CHANGED
@@ -5,7 +5,6 @@ import (
5
5
  "io"
6
6
 
7
7
  "github.com/libp2p/go-libp2p/core/network"
8
- "github.com/libp2p/go-libp2p/p2p/muxer/mplex"
9
8
  "nhooyr.io/websocket"
10
9
  )
11
10
 
@@ -20,7 +19,7 @@ type WebSocketConn struct {
20
19
  // NewWebSocketConn constructs a new WebSocket connection.
21
20
  func NewWebSocketConn(ctx context.Context, conn *websocket.Conn, isServer bool) (*WebSocketConn, error) {
22
21
  nc := websocket.NetConn(ctx, conn, websocket.MessageBinary)
23
- muxedConn, err := mplex.DefaultTransport.NewConn(nc, isServer, network.NullScope)
22
+ muxedConn, err := NewMuxedConn(nc, !isServer)
24
23
  if err != nil {
25
24
  return nil, err
26
25
  }
package/srpc/websocket.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { duplex } from 'it-ws'
2
2
  import { pipe } from 'it-pipe'
3
- import { mplex } from '@libp2p/mplex'
4
3
  import { Direction } from '@libp2p/interface-connection'
5
4
  import type WebSocket from 'isomorphic-ws'
6
5
 
@@ -13,10 +12,7 @@ export class WebSocketConn extends Conn {
13
12
  private socket: WebSocket
14
13
 
15
14
  constructor(socket: WebSocket, direction: Direction, server?: Server) {
16
- super(server, {
17
- direction,
18
- muxerFactory: mplex()(),
19
- })
15
+ super(server, {direction})
20
16
  this.socket = socket
21
17
  const socketDuplex = duplex(socket)
22
18
  pipe(socketDuplex, this, socketDuplex)