rpc: add subscription id to events (#6386)

Addresses  #3931
This commit is contained in:
Sam Kleinman
2021-06-15 17:33:47 +00:00
committed by GitHub
parent 8d0c38257e
commit 886519e3ca
12 changed files with 221 additions and 70 deletions
+29 -9
View File
@@ -52,7 +52,13 @@ type wsEvents struct {
ws *jsonrpcclient.WSClient
mtx tmsync.RWMutex
subscriptions map[string]chan ctypes.ResultEvent // query -> chan
subscriptions map[string]*wsSubscription
}
type wsSubscription struct {
res chan ctypes.ResultEvent
id string
query string
}
var _ rpcclient.EventsClient = (*wsEvents)(nil)
@@ -70,7 +76,7 @@ func newWsEvents(remote string, wso WSOptions) (*wsEvents, error) {
}
w := &wsEvents{
subscriptions: make(map[string]chan ctypes.ResultEvent),
subscriptions: make(map[string]*wsSubscription),
}
w.BaseService = *service.NewBaseService(nil, "wsEvents", w)
@@ -136,10 +142,10 @@ func (w *wsEvents) Subscribe(ctx context.Context, subscriber, query string,
outc := make(chan ctypes.ResultEvent, outCap)
w.mtx.Lock()
defer w.mtx.Unlock()
// subscriber param is ignored because Tendermint will override it with
// remote IP anyway.
w.subscriptions[query] = outc
w.mtx.Unlock()
w.subscriptions[query] = &wsSubscription{res: outc, query: query}
return outc, nil
}
@@ -158,9 +164,12 @@ func (w *wsEvents) Unsubscribe(ctx context.Context, subscriber, query string) er
}
w.mtx.Lock()
_, ok := w.subscriptions[query]
info, ok := w.subscriptions[query]
if ok {
delete(w.subscriptions, query)
if info.id != "" {
delete(w.subscriptions, info.id)
}
delete(w.subscriptions, info.query)
}
w.mtx.Unlock()
@@ -181,7 +190,7 @@ func (w *wsEvents) UnsubscribeAll(ctx context.Context, subscriber string) error
}
w.mtx.Lock()
w.subscriptions = make(map[string]chan ctypes.ResultEvent)
w.subscriptions = make(map[string]*wsSubscription)
w.mtx.Unlock()
return nil
@@ -196,7 +205,11 @@ func (w *wsEvents) redoSubscriptionsAfter(d time.Duration) {
w.mtx.Lock()
defer w.mtx.Unlock()
for q := range w.subscriptions {
for q, info := range w.subscriptions {
if q != "" && q == info.id {
continue
}
err := w.ws.Subscribe(ctx, q)
if err != nil {
w.Logger.Error("failed to resubscribe", "query", q, "err", err)
@@ -240,10 +253,17 @@ func (w *wsEvents) eventListener() {
w.mtx.RLock()
out, ok := w.subscriptions[result.Query]
if ok {
if _, idOk := w.subscriptions[result.SubscriptionID]; !idOk {
out.id = result.SubscriptionID
w.subscriptions[result.SubscriptionID] = out
}
}
w.mtx.RUnlock()
if ok {
select {
case out <- *result:
case out.res <- *result:
case <-w.Quit():
return
}
+17 -4
View File
@@ -248,7 +248,13 @@ func (c *Local) eventsRoutine(
for {
select {
case msg := <-sub.Out():
result := ctypes.ResultEvent{Query: q.String(), Data: msg.Data(), Events: msg.Events()}
result := ctypes.ResultEvent{
SubscriptionID: msg.SubscriptionID(),
Query: q.String(),
Data: msg.Data(),
Events: msg.Events(),
}
if cap(outc) == 0 {
outc <- result
} else {
@@ -293,11 +299,18 @@ func (c *Local) resubscribe(subscriber string, q tmpubsub.Query) types.Subscript
}
func (c *Local) Unsubscribe(ctx context.Context, subscriber, query string) error {
q, err := tmquery.New(query)
args := tmpubsub.UnsubscribeArgs{Subscriber: subscriber}
var err error
args.Query, err = tmquery.New(query)
if err != nil {
return fmt.Errorf("failed to parse query: %w", err)
// if this isn't a valid query it might be an ID, so
// we'll try that. It'll turn into an error when we
// try to unsubscribe. Eventually, perhaps, we'll want
// to change the interface to only allow
// unsubscription by ID, but that's a larger change.
args.ID = query
}
return c.EventBus.Unsubscribe(ctx, subscriber, q)
return c.EventBus.Unsubscribe(ctx, args)
}
func (c *Local) UnsubscribeAll(ctx context.Context, subscriber string) error {