starpc 0.25.5 → 0.26.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.
@@ -54,14 +54,14 @@ export async function runAbortControllerTest(client) {
54
54
  });
55
55
  await testRpc(async (signal) => {
56
56
  const stream = demoServiceClient.EchoServerStream({ body: 'test' }, signal);
57
- let gotMsgs = 0;
57
+ const msgs = [];
58
58
  try {
59
59
  for await (const msg of stream) {
60
- gotMsgs++;
60
+ msgs.push(msg);
61
61
  }
62
62
  }
63
63
  catch (err) {
64
- if (gotMsgs < 3) {
64
+ if (msgs.length < 3) {
65
65
  throw new Error('expected at least three messages before error');
66
66
  }
67
67
  throw err;
@@ -7,6 +7,7 @@ import { ERR_STREAM_IDLE } from './errors.js';
7
7
  // This implementation sends a "closed" message when close() is called.
8
8
  // However: if the remote is removed w/o closing cleanly, the stream will be left open!
9
9
  // Enable keepAliveMs and idleTimeoutMs to mitigate this issue with keep-alive messages.
10
+ // NOTE: Browsers will throttle setTimeout in background tabs.
10
11
  export class ChannelStream {
11
12
  // isAcked checks if the stream is acknowledged by the remote.
12
13
  get isAcked() {
@@ -1,4 +1,5 @@
1
1
  // Watchdog must be fed every timeoutDuration or it will call the expired callback.
2
+ // NOTE: Browsers will throttle setTimeout in background tabs.
2
3
  export class Watchdog {
3
4
  /**
4
5
  * Constructs a Watchdog instance.
@@ -63,13 +63,13 @@ export async function runAbortControllerTest(client: Client) {
63
63
 
64
64
  await testRpc(async (signal) => {
65
65
  const stream = demoServiceClient.EchoServerStream({ body: 'test' }, signal)
66
- let gotMsgs = 0
66
+ const msgs = []
67
67
  try {
68
68
  for await (const msg of stream) {
69
- gotMsgs++
69
+ msgs.push(msg)
70
70
  }
71
71
  } catch (err) {
72
- if (gotMsgs < 3) {
72
+ if (msgs.length < 3) {
73
73
  throw new Error('expected at least three messages before error')
74
74
  }
75
75
  throw err
package/go.mod CHANGED
@@ -9,7 +9,7 @@ require (
9
9
  )
10
10
 
11
11
  require (
12
- github.com/aperturerobotics/util v1.13.5 // latest
12
+ github.com/aperturerobotics/util v1.13.6 // latest
13
13
  github.com/libp2p/go-libp2p v0.32.2 // latest
14
14
  github.com/libp2p/go-yamux/v4 v4.0.2-0.20240206065824-7222fbc3459d // master
15
15
  github.com/sirupsen/logrus v1.9.3 // latest
package/go.sum CHANGED
@@ -4,6 +4,8 @@ github.com/aperturerobotics/util v1.13.3 h1:N4JXKYql0R/A2hMuV79SZ2vaftf8tiN8DUJ8
4
4
  github.com/aperturerobotics/util v1.13.3/go.mod h1:JdziNd9tR6lWqc9bSMIe1At8Gagrg986rmtZuPCv6+w=
5
5
  github.com/aperturerobotics/util v1.13.5 h1:g8Q9VKBUYR5Nu5Ee/ZygVbe0JkGXeNq1fBkT0ipLBMY=
6
6
  github.com/aperturerobotics/util v1.13.5/go.mod h1:8AfpGb9RJqUItLBb5ec3sprpl9swYyHlgOw0HzkE+S8=
7
+ github.com/aperturerobotics/util v1.13.6 h1:8FKBjj+vs23QZBiwkGod5WUY19Cisda48Rbg1zaqzZU=
8
+ github.com/aperturerobotics/util v1.13.6/go.mod h1:8AfpGb9RJqUItLBb5ec3sprpl9swYyHlgOw0HzkE+S8=
7
9
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8
10
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9
11
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.25.5",
3
+ "version": "0.26.0",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -67,7 +67,7 @@
67
67
  "esbuild": "^0.20.0",
68
68
  "prettier": "^3.2.4",
69
69
  "rimraf": "^5.0.1",
70
- "ts-poet": "6.6.0",
70
+ "ts-poet": "6.7.0",
71
71
  "ts-proto": "^1.166.1",
72
72
  "typescript": "^5.3.2",
73
73
  "utf-8-validate": "^6.0.3"
package/srpc/channel.ts CHANGED
@@ -43,6 +43,7 @@ export interface ChannelStreamOpts {
43
43
  // This implementation sends a "closed" message when close() is called.
44
44
  // However: if the remote is removed w/o closing cleanly, the stream will be left open!
45
45
  // Enable keepAliveMs and idleTimeoutMs to mitigate this issue with keep-alive messages.
46
+ // NOTE: Browsers will throttle setTimeout in background tabs.
46
47
  export class ChannelStream<T = Uint8Array>
47
48
  implements Duplex<AsyncGenerator<T>, Source<T>, Promise<void>>
48
49
  {
@@ -57,7 +57,7 @@ func (i *PrefixClient) stripCheckServiceIDPrefix(service string) (string, error)
57
57
  // NewRawStream opens a new raw stream with the remote.
58
58
  // Implements OpenStreamFunc.
59
59
  // msgHandler must not be called concurrently.
60
- func (i *PrefixClient) NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (Writer, error) {
60
+ func (i *PrefixClient) NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (PacketWriter, error) {
61
61
  return i.client.NewRawStream(ctx, msgHandler, closeHandler)
62
62
  }
63
63
 
@@ -25,7 +25,7 @@ func NewClientRPC(ctx context.Context, service, method string) *ClientRPC {
25
25
 
26
26
  // Start sets the writer and writes the MsgSend message.
27
27
  // must only be called once!
28
- func (r *ClientRPC) Start(writer Writer, writeFirstMsg bool, firstMsg []byte) error {
28
+ func (r *ClientRPC) Start(writer PacketWriter, writeFirstMsg bool, firstMsg []byte) error {
29
29
  select {
30
30
  case <-r.ctx.Done():
31
31
  r.ctxCancel()
@@ -48,7 +48,7 @@ func (c *ClientSet) NewRawStream(
48
48
  ctx context.Context,
49
49
  msgHandler PacketDataHandler,
50
50
  closeHandler CloseHandler,
51
- ) (Writer, error) {
51
+ ) (PacketWriter, error) {
52
52
  for _, client := range c.clients {
53
53
  if client == nil {
54
54
  continue
@@ -65,7 +65,7 @@ func (c *VClient) NewStream(ctx context.Context, service, method string, firstMs
65
65
  // NewRawStream opens a new raw stream with the remote.
66
66
  // Implements OpenStreamFunc.
67
67
  // msgHandler must not be called concurrently.
68
- func (c *VClient) NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (writer Writer, err error) {
68
+ func (c *VClient) NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (writer PacketWriter, err error) {
69
69
  t1 := time.Now()
70
70
 
71
71
  defer func() {
package/srpc/client.go CHANGED
@@ -18,7 +18,7 @@ type Client interface {
18
18
  // NewRawStream opens a new raw stream with the remote.
19
19
  // Implements OpenStreamFunc.
20
20
  // msgHandler must not be called concurrently.
21
- NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (Writer, error)
21
+ NewRawStream(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (PacketWriter, error)
22
22
  }
23
23
 
24
24
  // OpenStreamFunc opens a stream with a remote.
@@ -27,7 +27,7 @@ type OpenStreamFunc = func(
27
27
  ctx context.Context,
28
28
  msgHandler PacketDataHandler,
29
29
  closeHandler CloseHandler,
30
- ) (Writer, error)
30
+ ) (PacketWriter, error)
31
31
 
32
32
  // client implements Client with a transport.
33
33
  type client struct {
@@ -102,7 +102,7 @@ func (c *client) NewRawStream(
102
102
  ctx context.Context,
103
103
  msgHandler PacketDataHandler,
104
104
  closeHandler CloseHandler,
105
- ) (Writer, error) {
105
+ ) (PacketWriter, error) {
106
106
  return c.openStream(ctx, msgHandler, closeHandler)
107
107
  }
108
108
 
@@ -24,7 +24,7 @@ type commonRPC struct {
24
24
  // bcast broadcasts when below fields change
25
25
  bcast broadcast.Broadcast
26
26
  // writer is the writer to write messages to
27
- writer Writer
27
+ writer PacketWriter
28
28
  // dataQueue contains incoming data packets.
29
29
  // note: packets may be len() == 0
30
30
  dataQueue [][]byte
@@ -72,7 +72,7 @@ func NewClientWithMuxedConn(conn network.MuxedConn) Client {
72
72
 
73
73
  // NewOpenStreamWithMuxedConn constructs a OpenStream func with a MuxedConn.
74
74
  func NewOpenStreamWithMuxedConn(conn network.MuxedConn) OpenStreamFunc {
75
- return func(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (Writer, error) {
75
+ return func(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (PacketWriter, error) {
76
76
  mstrm, err := conn.OpenStream(ctx)
77
77
  if err != nil {
78
78
  return nil, err
package/srpc/packet-rw.go CHANGED
@@ -146,4 +146,4 @@ func (r *PacketReadWriter) readLengthPrefix(b []byte) uint32 {
146
146
  }
147
147
 
148
148
  // _ is a type assertion
149
- var _ Writer = (*PacketReadWriter)(nil)
149
+ var _ PacketWriter = (*PacketReadWriter)(nil)
package/srpc/packet.go CHANGED
@@ -1,6 +1,7 @@
1
1
  package srpc
2
2
 
3
- import "context"
3
+ // CloseHandler handles the stream closing with an optional error.
4
+ type CloseHandler = func(closeErr error)
4
5
 
5
6
  // PacketHandler handles a packet.
6
7
  //
@@ -11,12 +12,6 @@ type PacketHandler = func(pkt *Packet) error
11
12
  // PacketDataHandler handles a packet before it is parsed.
12
13
  type PacketDataHandler = func(data []byte) error
13
14
 
14
- // CloseHandler handles the stream closing with an optional error.
15
- type CloseHandler = func(closeErr error)
16
-
17
- // RawStreamCtor is a function that builds a raw stream.
18
- type RawStreamCtor func(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (Writer, error)
19
-
20
15
  // NewPacketDataHandler wraps a PacketHandler with a decoding step.
21
16
  func NewPacketDataHandler(handler PacketHandler) PacketDataHandler {
22
17
  return func(data []byte) error {
@@ -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 PacketDataHandler, closeHandler CloseHandler) (Writer, error) {
12
+ return func(ctx context.Context, msgHandler PacketDataHandler, closeHandler CloseHandler) (PacketWriter, error) {
13
13
  srvPipe, clientPipe := net.Pipe()
14
14
  go server.HandleStream(ctx, srvPipe)
15
15
  clientPrw := NewPacketReadWriter(clientPipe)
@@ -15,7 +15,7 @@ type ServerRPC struct {
15
15
 
16
16
  // NewServerRPC constructs a new ServerRPC session.
17
17
  // note: call SetWriter before handling any incoming messages.
18
- func NewServerRPC(ctx context.Context, invoker Invoker, writer Writer) *ServerRPC {
18
+ func NewServerRPC(ctx context.Context, invoker Invoker, writer PacketWriter) *ServerRPC {
19
19
  rpc := &ServerRPC{invoker: invoker}
20
20
  initCommonRPC(ctx, &rpc.commonRPC)
21
21
  rpc.writer = writer
package/srpc/watchdog.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  // Watchdog must be fed every timeoutDuration or it will call the expired callback.
2
+ // NOTE: Browsers will throttle setTimeout in background tabs.
2
3
  export class Watchdog {
3
4
  private timeoutDuration: number
4
5
  private expiredCallback: () => void
package/srpc/writer.go CHANGED
@@ -1,9 +1,7 @@
1
1
  package srpc
2
2
 
3
- // Writer is the interface used to write messages to the remote.
4
- type Writer interface {
5
- // Write writes raw data to the remote.
6
- Write(p []byte) (n int, err error)
3
+ // PacketWriter is the interface used to write messages to a PacketStream.
4
+ type PacketWriter interface {
7
5
  // WritePacket writes a packet to the remote.
8
6
  WritePacket(p *Packet) error
9
7
  // Close closes the writer.
@@ -1,161 +0,0 @@
1
- package srpc
2
-
3
- import (
4
- "context"
5
- "io"
6
- "sync"
7
-
8
- "github.com/aperturerobotics/util/broadcast"
9
- )
10
-
11
- // RawStreamRwc implements io.ReadWriteCloser with a raw stream.
12
- type RawStreamRwc struct {
13
- // writer is used to write messages to the remote.
14
- writer Writer
15
- // mtx guards below fields
16
- mtx sync.Mutex
17
- // bcast is broadcasted when data is added to readQueue
18
- bcast broadcast.Broadcast
19
- // readQueue holds incoming data to read
20
- readQueue [][]byte
21
- // closed indicates whether the stream is closed
22
- closed bool
23
- // closeErr stores the error, if any, when closing the stream
24
- closeErr error
25
- }
26
-
27
- func NewRawStreamRwc(ctx context.Context, ctorFn RawStreamCtor) (*RawStreamRwc, error) {
28
- rwc := &RawStreamRwc{}
29
- var err error
30
- rwc.writer, err = ctorFn(ctx, rwc.handlePacketData, rwc.handleClose)
31
- if err != nil {
32
- return nil, err
33
- }
34
- return rwc, nil
35
- }
36
-
37
- // handlePacketData implements PacketDataHandler.
38
- func (r *RawStreamRwc) handlePacketData(pkt []byte) error {
39
- r.mtx.Lock()
40
- defer r.mtx.Unlock()
41
-
42
- if r.closed {
43
- return io.ErrClosedPipe
44
- }
45
-
46
- r.readQueue = append(r.readQueue, pkt)
47
- r.bcast.Broadcast()
48
- return nil
49
- }
50
-
51
- // handleClose handles the stream closing with an optional error.
52
- func (r *RawStreamRwc) handleClose(closeErr error) {
53
- r.mtx.Lock()
54
- defer r.mtx.Unlock()
55
- if r.closed {
56
- return
57
- }
58
- r.closed = true
59
- r.closeErr = closeErr
60
- r.bcast.Broadcast()
61
- }
62
-
63
- // Read reads data from the stream to p.
64
- // Implements io.Reader.
65
- func (r *RawStreamRwc) Read(p []byte) (n int, err error) {
66
- readBuf := p
67
- for len(readBuf) != 0 && err == nil {
68
- // if the buffer has data, read from it.
69
- var rn int
70
- var read []byte
71
-
72
- r.mtx.Lock()
73
- if len(r.readQueue) != 0 {
74
- nrq := r.readQueue[0]
75
- // rn = amount of data to read
76
- // minimum of len(readBuf) (length of space remaining in p) and len(nrq) (size of next pkt in read queue)
77
- rn = min(len(readBuf), len(nrq))
78
- // read the contents of nrq up to rn bytes
79
- read = nrq[:rn]
80
- // get the remainder of the packet that we won't read this time
81
- nrq = nrq[rn:]
82
- // if there is no more to read drop the pkt from the queue
83
- if len(nrq) == 0 {
84
- r.readQueue[0] = nil
85
- r.readQueue = r.readQueue[1:]
86
- } else {
87
- // otherwise update the queued packet to be just the remainder
88
- r.readQueue[0] = nrq
89
- }
90
- }
91
-
92
- // check if the stream is closed
93
- closed, closedErr := r.closed, r.closeErr
94
- var wait <-chan struct{}
95
-
96
- // if we didn't read anything and !closed, wait till something changes.
97
- if rn == 0 && !closed {
98
- wait = r.bcast.GetWaitCh()
99
- }
100
- r.mtx.Unlock()
101
-
102
- // if we read data, copy it to the output buf
103
- if rn != 0 {
104
- // copy data to output buf
105
- copy(readBuf, read)
106
- n += rn
107
- // advance readBuf by rn
108
- readBuf = readBuf[rn:]
109
- continue
110
- }
111
-
112
- // if we read data to p already, return now.
113
- if n != 0 {
114
- break
115
- }
116
-
117
- // if closed or error, return.
118
- if closed {
119
- if closedErr != nil {
120
- return n, closedErr
121
- }
122
- return n, io.EOF
123
- }
124
-
125
- // wait for data or closed
126
- <-wait
127
- }
128
-
129
- return n, err
130
- }
131
-
132
- // Write writes data to the stream.
133
- func (r *RawStreamRwc) Write(p []byte) (int, error) {
134
- return r.writer.Write(p)
135
- }
136
-
137
- // WritePacket writes a packet to the remote.
138
- func (r *RawStreamRwc) WritePacket(p *Packet) error {
139
- return r.writer.WritePacket(p)
140
- }
141
-
142
- // Close closes the stream.
143
- func (r *RawStreamRwc) Close() error {
144
- r.mtx.Lock()
145
- defer r.mtx.Unlock()
146
-
147
- if r.closed {
148
- return r.closeErr
149
- }
150
-
151
- r.closed = true
152
- r.closeErr = r.writer.Close()
153
- r.bcast.Broadcast()
154
- return r.closeErr
155
- }
156
-
157
- // _ is a type assertion
158
- var (
159
- _ io.ReadWriteCloser = ((*RawStreamRwc)(nil))
160
- _ Writer = ((*RawStreamRwc)(nil))
161
- )