@@ -37,7 +37,7 @@ type Client struct {
37
37
38
38
// Callbacks for RPC responses.
39
39
cbMu sync.RWMutex
40
- callbacks map [int ]chan rpcResponse
40
+ callbacks map [int ]callback
41
41
42
42
wg * sync.WaitGroup
43
43
}
@@ -80,7 +80,7 @@ func New(conn net.Conn, options ...OptionFunc) (*Client, error) {
80
80
client .c = jsonrpc .NewConn (conn , client .ll )
81
81
82
82
// Set up callbacks.
83
- client .callbacks = make (map [int ]chan rpcResponse )
83
+ client .callbacks = make (map [int ]callback )
84
84
85
85
// Start up any background routines.
86
86
var wg sync.WaitGroup
@@ -134,8 +134,10 @@ func (c *Client) rpc(ctx context.Context, method string, out interface{}, args .
134
134
135
135
// Add callback for this RPC ID to return results via channel.
136
136
ch := make (chan rpcResponse , 1 )
137
- defer close (ch )
138
- c .addCallback (req .ID , ch )
137
+ c .addCallback (req .ID , callback {
138
+ Ctx : ctx ,
139
+ Response : ch ,
140
+ })
139
141
140
142
if err := c .c .Send (req ); err != nil {
141
143
return err
@@ -184,9 +186,15 @@ func (c *Client) listen() {
184
186
}
185
187
}
186
188
187
- // addCallback registers a callback for an RPC response for the specified ID,
188
- // and accepts a channel to return the results on.
189
- func (c * Client ) addCallback (id int , ch chan rpcResponse ) {
189
+ // A callback can be used to send a message back to a caller, or
190
+ // allow the caller to cancel waiting for a message.
191
+ type callback struct {
192
+ Ctx context.Context
193
+ Response chan rpcResponse
194
+ }
195
+
196
+ // addCallback registers a callback for an RPC response for the specified ID.
197
+ func (c * Client ) addCallback (id int , cb callback ) {
190
198
c .cbMu .Lock ()
191
199
defer c .cbMu .Unlock ()
192
200
@@ -195,7 +203,7 @@ func (c *Client) addCallback(id int, ch chan rpcResponse) {
195
203
panicf ("OVSDB callback with ID %d already registered" , id )
196
204
}
197
205
198
- c .callbacks [id ] = ch
206
+ c .callbacks [id ] = cb
199
207
}
200
208
201
209
// doCallback performs a callback for an RPC response and clears the
@@ -204,14 +212,23 @@ func (c *Client) doCallback(id int, res rpcResponse) {
204
212
c .cbMu .Lock ()
205
213
defer c .cbMu .Unlock ()
206
214
207
- ch , ok := c .callbacks [id ]
215
+ cb , ok := c .callbacks [id ]
208
216
if ! ok {
209
217
// Nobody is listening to this callback.
210
218
return
211
219
}
212
220
213
- // Return result and remove this callback.
214
- ch <- res
221
+ // Producer can safely close channel on return.
222
+ defer close (cb .Response )
223
+
224
+ // Wait for send or cancelation.
225
+ select {
226
+ case <- cb .Ctx .Done ():
227
+ // Request's context was canceled.
228
+ case cb .Response <- res :
229
+ // Message was successfully sent.
230
+ }
231
+
215
232
delete (c .callbacks , id )
216
233
}
217
234
0 commit comments