starpc 0.3.5 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/Makefile +22 -13
  2. package/README.md +4 -0
  3. package/dist/echo/client-test.js +1 -1
  4. package/dist/echo/{echo.d.ts → echo.pb.d.ts} +0 -0
  5. package/dist/echo/{echo.js → echo.pb.js} +0 -1
  6. package/dist/echo/index.d.ts +1 -1
  7. package/dist/echo/index.js +1 -1
  8. package/dist/echo/server.d.ts +1 -1
  9. package/dist/rpcstream/rpcstream.d.ts +19 -0
  10. package/dist/rpcstream/rpcstream.js +94 -0
  11. package/dist/rpcstream/rpcstream.pb.d.ts +85 -0
  12. package/dist/rpcstream/rpcstream.pb.js +160 -0
  13. package/dist/srpc/broadcast-channel.js +0 -10
  14. package/dist/srpc/client-rpc.d.ts +1 -1
  15. package/dist/srpc/client.d.ts +5 -5
  16. package/dist/srpc/client.js +21 -25
  17. package/dist/srpc/common-rpc.d.ts +2 -2
  18. package/dist/srpc/common-rpc.js +1 -15
  19. package/dist/srpc/conn-duplex.js +1 -3
  20. package/dist/srpc/conn.d.ts +1 -1
  21. package/dist/srpc/conn.js +0 -4
  22. package/dist/srpc/handler.js +12 -14
  23. package/dist/srpc/index.d.ts +2 -1
  24. package/dist/srpc/index.js +1 -0
  25. package/dist/srpc/message-port.js +0 -10
  26. package/dist/srpc/mux.js +4 -2
  27. package/dist/srpc/observable-source.d.ts +9 -0
  28. package/dist/srpc/observable-source.js +25 -0
  29. package/dist/srpc/packet.d.ts +1 -1
  30. package/dist/srpc/packet.js +1 -1
  31. package/dist/srpc/{rpcproto.d.ts → rpcproto.pb.d.ts} +0 -0
  32. package/dist/srpc/{rpcproto.js → rpcproto.pb.js} +0 -0
  33. package/dist/srpc/server-rpc.d.ts +1 -1
  34. package/dist/srpc/server-rpc.js +0 -2
  35. package/dist/srpc/server.d.ts +4 -4
  36. package/dist/srpc/server.js +6 -7
  37. package/dist/srpc/stream.d.ts +1 -1
  38. package/dist/srpc/websocket.js +1 -3
  39. package/e2e/debug.test +0 -0
  40. package/e2e/e2e_test.go +20 -2
  41. package/echo/client-test.ts +1 -1
  42. package/echo/{echo.ts → echo.pb.ts} +0 -0
  43. package/echo/index.ts +1 -1
  44. package/echo/server.ts +1 -1
  45. package/go.mod +2 -2
  46. package/go.sum +2 -2
  47. package/integration/integration.ts +2 -2
  48. package/package.json +4 -3
  49. package/srpc/broadcast-channel.ts +1 -1
  50. package/srpc/client-rpc.go +8 -3
  51. package/srpc/client-rpc.ts +1 -1
  52. package/srpc/client.go +4 -4
  53. package/srpc/client.ts +27 -25
  54. package/srpc/common-rpc.ts +2 -2
  55. package/srpc/conn-duplex.ts +1 -1
  56. package/srpc/conn.ts +1 -1
  57. package/srpc/handler.ts +14 -10
  58. package/srpc/index.ts +2 -2
  59. package/srpc/{rpc-stream.go → msg-stream.go} +13 -13
  60. package/srpc/muxed-conn.go +31 -0
  61. package/srpc/observable-source.ts +40 -0
  62. package/srpc/packet.go +4 -3
  63. package/srpc/packet.ts +1 -1
  64. package/srpc/{rpcproto.ts → rpcproto.pb.ts} +0 -0
  65. package/srpc/server-pipe.go +1 -1
  66. package/srpc/server-rpc.go +3 -3
  67. package/srpc/server-rpc.ts +1 -1
  68. package/srpc/server.go +8 -1
  69. package/srpc/server.ts +8 -7
  70. package/srpc/stream.ts +1 -1
  71. package/srpc/websocket.go +1 -4
  72. package/srpc/websocket.ts +1 -1
  73. package/srpc/conn.go +0 -7
@@ -1,8 +1,8 @@
1
1
  import type { Source, Sink } from 'it-stream-types'
2
2
  import { pushable } from 'it-pushable'
3
3
 
4
- import type { CallData, CallStart } from './rpcproto.js'
5
- import { Packet } from './rpcproto.js'
4
+ import type { CallData, CallStart } from './rpcproto.pb.js'
5
+ import { Packet } from './rpcproto.pb.js'
6
6
 
7
7
  // CommonRPC is common logic between server and client RPCs.
8
8
  export class CommonRPC {
@@ -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/conn.ts CHANGED
@@ -19,7 +19,7 @@ export interface ConnParams {
19
19
  // Implemented by Server.
20
20
  export interface StreamHandler {
21
21
  // handleStream handles an incoming stream.
22
- handleStream(strm: Duplex<Uint8Array>): Promise<void>
22
+ handleStream(strm: Duplex<Uint8Array>): void
23
23
  }
24
24
 
25
25
  // Conn implements a generic connection with a two-way stream.
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
  })
package/srpc/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { OpenStreamFunc } from './stream.js'
1
+ export type { PacketHandler, Stream, OpenStreamFunc } from './stream.js'
2
2
  export { Client } from './client.js'
3
3
  export { Server } from './server.js'
4
4
  export { Conn, ConnParams } from './conn.js'
@@ -9,9 +9,9 @@ export {
9
9
  newBroadcastChannelIterable,
10
10
  BroadcastChannelConn,
11
11
  } from './broadcast-channel.js'
12
-
13
12
  export {
14
13
  MessagePortIterable,
15
14
  newMessagePortIterable,
16
15
  MessagePortConn,
17
16
  } from './message-port.js'
17
+ export { ObservableSource } from './observable-source.js'
@@ -5,8 +5,8 @@ import (
5
5
  "io"
6
6
  )
7
7
 
8
- // RPCStream implements the stream interface passed to implementations.
9
- type RPCStream struct {
8
+ // MsgStream implements the stream interface passed to implementations.
9
+ type MsgStream struct {
10
10
  // ctx is the stream context
11
11
  ctx context.Context
12
12
  // writer is the stream writer
@@ -15,10 +15,10 @@ type RPCStream struct {
15
15
  dataCh chan []byte
16
16
  }
17
17
 
18
- // NewRPCStream constructs a new Stream with a ClientRPC.
18
+ // NewMsgStream constructs a new Stream with a ClientRPC.
19
19
  // dataCh should be closed when no more messages will arrive.
20
- func NewRPCStream(ctx context.Context, writer Writer, dataCh chan []byte) *RPCStream {
21
- return &RPCStream{
20
+ func NewMsgStream(ctx context.Context, writer Writer, dataCh chan []byte) *MsgStream {
21
+ return &MsgStream{
22
22
  ctx: ctx,
23
23
  writer: writer,
24
24
  dataCh: dataCh,
@@ -26,12 +26,12 @@ func NewRPCStream(ctx context.Context, writer Writer, dataCh chan []byte) *RPCSt
26
26
  }
27
27
 
28
28
  // Context is canceled when the Stream is no longer valid.
29
- func (r *RPCStream) Context() context.Context {
29
+ func (r *MsgStream) Context() context.Context {
30
30
  return r.ctx
31
31
  }
32
32
 
33
33
  // MsgSend sends the message to the remote.
34
- func (r *RPCStream) MsgSend(msg Message) error {
34
+ func (r *MsgStream) MsgSend(msg Message) error {
35
35
  select {
36
36
  case <-r.ctx.Done():
37
37
  return context.Canceled
@@ -42,13 +42,13 @@ 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
 
49
49
  // MsgRecv receives an incoming message from the remote.
50
50
  // Parses the message into the object at msg.
51
- func (r *RPCStream) MsgRecv(msg Message) error {
51
+ func (r *MsgStream) MsgRecv(msg Message) error {
52
52
  select {
53
53
  case <-r.Context().Done():
54
54
  return context.Canceled
@@ -61,16 +61,16 @@ func (r *RPCStream) MsgRecv(msg Message) error {
61
61
  }
62
62
 
63
63
  // CloseSend signals to the remote that we will no longer send any messages.
64
- func (r *RPCStream) CloseSend() error {
65
- outPkt := NewCallDataPacket(nil, true, nil)
64
+ func (r *MsgStream) CloseSend() error {
65
+ outPkt := NewCallDataPacket(nil, false, true, nil)
66
66
  return r.writer.WritePacket(outPkt)
67
67
  }
68
68
 
69
69
  // Close closes the stream.
70
- func (r *RPCStream) Close() error {
70
+ func (r *MsgStream) Close() error {
71
71
  _ = r.writer.Close()
72
72
  return nil
73
73
  }
74
74
 
75
75
  // _ is a type assertion
76
- var _ Stream = ((*RPCStream)(nil))
76
+ var _ Stream = ((*MsgStream)(nil))
@@ -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 PacketHandler) (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
+ }
@@ -0,0 +1,40 @@
1
+ import { Source } from 'it-stream-types'
2
+ import { pushable, Pushable } from 'it-pushable'
3
+ import { Observable, Subscription } from 'rxjs'
4
+
5
+ // ObservableSource wraps an Observable into a Source.
6
+ export class ObservableSource<T> {
7
+ // source is the source for observable objects.
8
+ public readonly source: Source<T>
9
+ // _source emits incoming data to the source.
10
+ private readonly _source: {
11
+ push: (val: T) => void
12
+ end: (err?: Error) => void
13
+ }
14
+ // subscription is the observable subscription
15
+ private readonly subscription: Subscription
16
+
17
+ constructor(observable: Observable<T>) {
18
+ const source: Pushable<T> = pushable({ objectMode: true })
19
+ this.source = source
20
+ this._source = source
21
+
22
+ this.subscription = observable.subscribe({
23
+ next: (value: T) => {
24
+ this._source.push(value)
25
+ },
26
+ error: (err) => {
27
+ this._source.end(err)
28
+ },
29
+ complete: () => {
30
+ this._source.end()
31
+ },
32
+ })
33
+ }
34
+
35
+ // close closes the subscription.
36
+ public close(err?: Error) {
37
+ this._source.end(err)
38
+ this.subscription.unsubscribe()
39
+ }
40
+ }
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
  },
package/srpc/packet.ts CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  decode as lengthPrefixDecode,
5
5
  } from 'it-length-prefixed'
6
6
 
7
- import { Packet } from './rpcproto.js'
7
+ import { Packet } from './rpcproto.pb.js'
8
8
  import {
9
9
  buildDecodeMessageTransform,
10
10
  buildEncodeMessageTransform,
File without changes
@@ -9,7 +9,7 @@ import (
9
9
  // Stream with the given Server. Starts read pumps for both. Starts the
10
10
  // HandleStream function on the server in a separate goroutine.
11
11
  func NewServerPipe(server *Server) OpenStreamFunc {
12
- return func(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
12
+ return func(ctx context.Context, msgHandler PacketHandler) (Writer, error) {
13
13
  srvPipe, clientPipe := net.Pipe()
14
14
  go func() {
15
15
  _ = server.HandleStream(ctx, srvPipe)
@@ -133,12 +133,12 @@ func (r *ServerRPC) HandleCallData(pkt *CallData) error {
133
133
  func (r *ServerRPC) invokeRPC() {
134
134
  // ctx := r.ctx
135
135
  serviceID, methodID := r.service, r.method
136
- strm := NewRPCStream(r.ctx, r.writer, r.dataCh)
136
+ strm := NewMsgStream(r.ctx, r.writer, r.dataCh)
137
137
  ok, err := r.mux.InvokeMethod(serviceID, methodID, strm)
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
  }
@@ -1,6 +1,6 @@
1
1
  import type { Sink } from 'it-stream-types'
2
2
 
3
- import type { CallData, CallStart } from './rpcproto.js'
3
+ import type { CallData, CallStart } from './rpcproto.pb.js'
4
4
  import { CommonRPC } from './common-rpc.js'
5
5
  import { InvokeFn } from './handler.js'
6
6
  import { Mux } from './mux.js'
package/srpc/server.go CHANGED
@@ -20,6 +20,11 @@ func NewServer(mux Mux) *Server {
20
20
  }
21
21
  }
22
22
 
23
+ // GetMux returns the mux.
24
+ func (s *Server) GetMux() Mux {
25
+ return s.mux
26
+ }
27
+
23
28
  // HandleStream handles an incoming ReadWriteCloser stream.
24
29
  func (s *Server) HandleStream(ctx context.Context, rwc io.ReadWriteCloser) error {
25
30
  subCtx, subCtxCancel := context.WithCancel(ctx)
@@ -27,7 +32,9 @@ func (s *Server) HandleStream(ctx context.Context, rwc io.ReadWriteCloser) error
27
32
  serverRPC := NewServerRPC(subCtx, s.mux)
28
33
  prw := NewPacketReadWriter(rwc, serverRPC.HandlePacket)
29
34
  serverRPC.SetWriter(prw)
30
- return prw.ReadPump()
35
+ err := prw.ReadPump()
36
+ _ = rwc.Close()
37
+ return err
31
38
  }
32
39
 
33
40
  // AcceptMuxedConn runs a loop which calls Accept on a muxer to handle streams.
package/srpc/server.ts CHANGED
@@ -4,7 +4,7 @@ import { pipe } from 'it-pipe'
4
4
 
5
5
  import { Mux } from './mux.js'
6
6
  import { ServerRPC } from './server-rpc.js'
7
- import { Packet } from './rpcproto.js'
7
+ import { Packet } from './rpcproto.pb.js'
8
8
  import {
9
9
  parseLengthPrefixTransform,
10
10
  prependLengthPrefixTransform,
@@ -29,15 +29,14 @@ export class Server implements StreamHandler {
29
29
  }
30
30
 
31
31
  // handleStream handles an incoming Uint8Array message duplex.
32
- // closes the stream when the rpc completes.
33
- public handleStream(stream: Stream): Promise<void> {
32
+ public handleStream(stream: Stream): ServerRPC {
34
33
  return this.handleDuplex(stream)
35
34
  }
36
35
 
37
36
  // handleDuplex handles an incoming message duplex.
38
- public async handleDuplex(stream: Duplex<Uint8Array>): Promise<void> {
37
+ public handleDuplex(stream: Duplex<Uint8Array>): ServerRPC {
39
38
  const rpc = this.startRpc()
40
- await pipe(
39
+ pipe(
41
40
  stream,
42
41
  parseLengthPrefixTransform(),
43
42
  decodePacketSource,
@@ -46,11 +45,13 @@ export class Server implements StreamHandler {
46
45
  prependLengthPrefixTransform(),
47
46
  stream
48
47
  )
48
+ return rpc
49
49
  }
50
50
 
51
51
  // handlePacketStream handles an incoming Packet duplex.
52
- public async handlePacketStream(stream: Duplex<Packet>): Promise<void> {
52
+ public handlePacketStream(stream: Duplex<Packet>): ServerRPC {
53
53
  const rpc = this.startRpc()
54
- await pipe(stream, rpc, stream)
54
+ pipe(stream, rpc, stream)
55
+ return rpc
55
56
  }
56
57
  }
package/srpc/stream.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Packet } from './rpcproto'
1
+ import type { Packet } from './rpcproto.pb.js'
2
2
  import type { Duplex } from 'it-stream-types'
3
3
 
4
4
  // PacketHandler handles incoming packets.
package/srpc/websocket.go CHANGED
@@ -43,7 +43,7 @@ func (w *WebSocketConn) AcceptStream() (io.ReadWriteCloser, error) {
43
43
  }
44
44
 
45
45
  // OpenStream tries to open a stream with the remote.
46
- func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler func(pkt *Packet) error) (Writer, error) {
46
+ func (w *WebSocketConn) OpenStream(ctx context.Context, msgHandler PacketHandler) (Writer, error) {
47
47
  muxedStream, err := w.mconn.OpenStream(ctx)
48
48
  if err != nil {
49
49
  return nil, err
@@ -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
- }