starpc 0.33.1 → 0.33.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.33.1",
3
+ "version": "0.33.4",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -32,21 +32,26 @@ func (r *ClientRPC) Start(writer PacketWriter, writeFirstMsg bool, firstMsg []by
32
32
  return context.Canceled
33
33
  }
34
34
 
35
- r.mtx.Lock()
36
- defer r.mtx.Unlock()
37
- defer r.bcast.Broadcast()
38
- r.writer = writer
39
35
  var firstMsgEmpty bool
40
- if writeFirstMsg {
41
- firstMsgEmpty = len(firstMsg) == 0
42
- }
43
- pkt := NewCallStartPacket(r.service, r.method, firstMsg, firstMsgEmpty)
44
- if err := writer.WritePacket(pkt); err != nil {
45
- r.ctxCancel()
46
- _ = writer.Close()
47
- return err
48
- }
49
- return nil
36
+ var err error
37
+ r.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
38
+ r.writer = writer
39
+
40
+ if writeFirstMsg {
41
+ firstMsgEmpty = len(firstMsg) == 0
42
+ }
43
+
44
+ pkt := NewCallStartPacket(r.service, r.method, firstMsg, firstMsgEmpty)
45
+ err = writer.WritePacket(pkt)
46
+ if err != nil {
47
+ r.ctxCancel()
48
+ _ = writer.Close()
49
+ }
50
+
51
+ broadcast()
52
+ })
53
+
54
+ return err
50
55
  }
51
56
 
52
57
  // HandlePacketData handles an incoming unparsed message packet.
@@ -60,14 +65,14 @@ func (r *ClientRPC) HandlePacketData(data []byte) error {
60
65
 
61
66
  // HandleStreamClose handles the stream closing optionally w/ an error.
62
67
  func (r *ClientRPC) HandleStreamClose(closeErr error) {
63
- r.mtx.Lock()
64
- defer r.mtx.Unlock()
65
- defer r.bcast.Broadcast()
66
- if closeErr != nil && r.remoteErr == nil {
67
- r.remoteErr = closeErr
68
- }
69
- r.dataClosed = true
70
- r.ctxCancel()
68
+ r.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
69
+ if closeErr != nil && r.remoteErr == nil {
70
+ r.remoteErr = closeErr
71
+ }
72
+ r.dataClosed = true
73
+ r.ctxCancel()
74
+ broadcast()
75
+ })
71
76
  }
72
77
 
73
78
  // HandlePacket handles an incoming parsed message packet.
@@ -102,8 +107,8 @@ func (r *ClientRPC) Close() {
102
107
  if r.writer != nil {
103
108
  _ = r.WriteCancel()
104
109
  }
105
- r.mtx.Lock()
106
- r.closeLocked()
107
- r.bcast.Broadcast()
108
- r.mtx.Unlock()
110
+
111
+ r.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
112
+ r.closeLocked(broadcast)
113
+ })
109
114
  }
@@ -3,7 +3,6 @@ package srpc
3
3
  import (
4
4
  "context"
5
5
  "io"
6
- "sync"
7
6
 
8
7
  "github.com/aperturerobotics/util/broadcast"
9
8
  "github.com/pkg/errors"
@@ -19,9 +18,7 @@ type commonRPC struct {
19
18
  service string
20
19
  // method is the rpc method
21
20
  method string
22
- // mtx guards below fields
23
- mtx sync.Mutex
24
- // bcast broadcasts when below fields change
21
+ // bcast guards below fields
25
22
  bcast broadcast.Broadcast
26
23
  // writer is the writer to write messages to
27
24
  writer PacketWriter
@@ -45,21 +42,25 @@ func (c *commonRPC) Context() context.Context {
45
42
  return c.ctx
46
43
  }
47
44
 
48
- // Wait waits for the RPC to finish.
45
+ // Wait waits for the RPC to finish (remote end closed the stream).
49
46
  func (c *commonRPC) Wait(ctx context.Context) error {
50
47
  for {
51
- c.mtx.Lock()
52
- if c.dataClosed {
53
- err := c.remoteErr
54
- c.mtx.Unlock()
48
+ var dataClosed bool
49
+ var err error
50
+ var waitCh <-chan struct{}
51
+ c.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
52
+ dataClosed, err = c.dataClosed, c.remoteErr
53
+ waitCh = getWaitCh()
54
+ })
55
+
56
+ if dataClosed {
55
57
  return err
56
58
  }
57
- waiter := c.bcast.GetWaitCh()
58
- c.mtx.Unlock()
59
+
59
60
  select {
60
61
  case <-ctx.Done():
61
62
  return context.Canceled
62
- case <-waiter:
63
+ case <-waitCh:
63
64
  }
64
65
  }
65
66
  }
@@ -68,39 +69,43 @@ func (c *commonRPC) Wait(ctx context.Context) error {
68
69
  //
69
70
  // returns io.EOF if the stream ended without a packet.
70
71
  func (c *commonRPC) ReadOne() ([]byte, error) {
72
+ var hasMsg bool
71
73
  var msg []byte
72
74
  var err error
73
75
  var ctxDone bool
74
76
  for {
75
- c.mtx.Lock()
76
- waiter := c.bcast.GetWaitCh()
77
- if ctxDone && !c.dataClosed {
78
- // context must have been canceled locally
79
- c.closeLocked()
80
- err = context.Canceled
81
- c.mtx.Unlock()
82
- return nil, err
83
- }
84
- if len(c.dataQueue) != 0 {
85
- msg = c.dataQueue[0]
86
- c.dataQueue[0] = nil
87
- c.dataQueue = c.dataQueue[1:]
88
- c.mtx.Unlock()
89
- return msg, nil
90
- }
91
- if c.dataClosed || c.remoteErr != nil {
92
- err = c.remoteErr
93
- if err == nil {
94
- err = io.EOF
77
+ var waitCh <-chan struct{}
78
+ c.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
79
+ if ctxDone && !c.dataClosed {
80
+ // context must have been canceled locally
81
+ c.closeLocked(broadcast)
82
+ err = context.Canceled
83
+ return
95
84
  }
96
- c.mtx.Unlock()
97
- return nil, err
85
+
86
+ if len(c.dataQueue) != 0 {
87
+ msg = c.dataQueue[0]
88
+ hasMsg = true
89
+ c.dataQueue[0] = nil
90
+ c.dataQueue = c.dataQueue[1:]
91
+ } else if c.dataClosed || c.remoteErr != nil {
92
+ err = c.remoteErr
93
+ if err == nil {
94
+ err = io.EOF
95
+ }
96
+ }
97
+
98
+ waitCh = getWaitCh()
99
+ })
100
+
101
+ if hasMsg || err != nil {
102
+ return msg, err
98
103
  }
99
- c.mtx.Unlock()
104
+
100
105
  select {
101
106
  case <-c.ctx.Done():
102
107
  ctxDone = true
103
- case <-waiter:
108
+ case <-waitCh:
104
109
  }
105
110
  }
106
111
  }
@@ -116,17 +121,17 @@ func (c *commonRPC) WriteCallData(data []byte, complete bool, err error) error {
116
121
 
117
122
  // HandleStreamClose handles the incoming stream closing w/ optional error.
118
123
  func (c *commonRPC) HandleStreamClose(closeErr error) {
119
- c.mtx.Lock()
120
- defer c.mtx.Unlock()
121
- if closeErr != nil && c.remoteErr == nil {
122
- c.remoteErr = closeErr
123
- }
124
- c.dataClosed = true
125
- c.ctxCancel()
126
- if c.writer != nil {
127
- _ = c.writer.Close()
128
- }
129
- c.bcast.Broadcast()
124
+ c.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
125
+ if closeErr != nil && c.remoteErr == nil {
126
+ c.remoteErr = closeErr
127
+ }
128
+ c.dataClosed = true
129
+ c.ctxCancel()
130
+ if c.writer != nil {
131
+ _ = c.writer.Close()
132
+ }
133
+ broadcast()
134
+ })
130
135
  }
131
136
 
132
137
  // HandleCallCancel handles the call cancel packet.
@@ -137,29 +142,31 @@ func (c *commonRPC) HandleCallCancel() error {
137
142
 
138
143
  // HandleCallData handles the call data packet.
139
144
  func (c *commonRPC) HandleCallData(pkt *CallData) error {
140
- c.mtx.Lock()
141
- defer c.mtx.Unlock()
145
+ var err error
146
+ c.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
147
+ if c.dataClosed {
148
+ err = ErrCompleted
149
+ return
150
+ }
142
151
 
143
- if c.dataClosed {
144
- return ErrCompleted
145
- }
152
+ if data := pkt.GetData(); len(data) != 0 || pkt.GetDataIsZero() {
153
+ c.dataQueue = append(c.dataQueue, data)
154
+ }
146
155
 
147
- if data := pkt.GetData(); len(data) != 0 || pkt.GetDataIsZero() {
148
- c.dataQueue = append(c.dataQueue, data)
149
- }
156
+ complete := pkt.GetComplete()
157
+ if err := pkt.GetError(); len(err) != 0 {
158
+ complete = true
159
+ c.remoteErr = errors.New(err)
160
+ }
150
161
 
151
- complete := pkt.GetComplete()
152
- if err := pkt.GetError(); len(err) != 0 {
153
- complete = true
154
- c.remoteErr = errors.New(err)
155
- }
162
+ if complete {
163
+ c.dataClosed = true
164
+ }
156
165
 
157
- if complete {
158
- c.dataClosed = true
159
- }
166
+ broadcast()
167
+ })
160
168
 
161
- c.bcast.Broadcast()
162
- return nil
169
+ return err
163
170
  }
164
171
 
165
172
  // WriteCancel writes a call cancel packet.
@@ -171,7 +178,7 @@ func (c *commonRPC) WriteCancel() error {
171
178
  }
172
179
 
173
180
  // closeLocked releases resources held by the RPC.
174
- func (c *commonRPC) closeLocked() {
181
+ func (c *commonRPC) closeLocked(broadcast func()) {
175
182
  c.dataClosed = true
176
183
  if c.remoteErr == nil {
177
184
  c.remoteErr = context.Canceled
@@ -179,6 +186,6 @@ func (c *commonRPC) closeLocked() {
179
186
  if c.writer != nil {
180
187
  _ = c.writer.Close()
181
188
  }
182
- c.bcast.Broadcast()
189
+ broadcast()
183
190
  c.ctxCancel()
184
191
  }
@@ -57,27 +57,33 @@ func (r *ServerRPC) HandlePacket(msg *Packet) error {
57
57
 
58
58
  // HandleCallStart handles the call start packet.
59
59
  func (r *ServerRPC) HandleCallStart(pkt *CallStart) error {
60
- r.mtx.Lock()
61
- defer r.mtx.Unlock()
62
- // process start: method and service
63
- if r.method != "" || r.service != "" {
64
- return errors.New("call start must be sent only once")
65
- }
66
- if r.dataClosed {
67
- return ErrCompleted
68
- }
69
- service, method := pkt.GetRpcService(), pkt.GetRpcMethod()
70
- r.service, r.method = service, method
60
+ var err error
71
61
 
72
- // process first data packet, if included
73
- if data := pkt.GetData(); len(data) != 0 || pkt.GetDataIsZero() {
74
- r.dataQueue = append(r.dataQueue, data)
75
- }
62
+ r.bcast.HoldLock(func(broadcast func(), getWaitCh func() <-chan struct{}) {
63
+ // process start: method and service
64
+ if r.method != "" || r.service != "" {
65
+ err = errors.New("call start must be sent only once")
66
+ return
67
+ }
68
+ if r.dataClosed {
69
+ err = ErrCompleted
70
+ return
71
+ }
72
+
73
+ service, method := pkt.GetRpcService(), pkt.GetRpcMethod()
74
+ r.service, r.method = service, method
75
+
76
+ // process first data packet, if included
77
+ if data := pkt.GetData(); len(data) != 0 || pkt.GetDataIsZero() {
78
+ r.dataQueue = append(r.dataQueue, data)
79
+ }
80
+
81
+ // invoke the rpc
82
+ broadcast()
83
+ go r.invokeRPC(service, method)
84
+ })
76
85
 
77
- // invoke the rpc
78
- r.bcast.Broadcast()
79
- go r.invokeRPC(service, method)
80
- return nil
86
+ return err
81
87
  }
82
88
 
83
89
  // invokeRPC invokes the RPC after CallStart is received.