github.com/evdatsion/aphelion-dpos-bft@v0.32.1/rpc/client/helpers.go (about) 1 package client 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/pkg/errors" 8 "github.com/evdatsion/aphelion-dpos-bft/types" 9 ) 10 11 // Waiter is informed of current height, decided whether to quit early 12 type Waiter func(delta int64) (abort error) 13 14 // DefaultWaitStrategy is the standard backoff algorithm, 15 // but you can plug in another one 16 func DefaultWaitStrategy(delta int64) (abort error) { 17 if delta > 10 { 18 return errors.Errorf("waiting for %d blocks... aborting", delta) 19 } else if delta > 0 { 20 // estimate of wait time.... 21 // wait half a second for the next block (in progress) 22 // plus one second for every full block 23 delay := time.Duration(delta-1)*time.Second + 500*time.Millisecond 24 time.Sleep(delay) 25 } 26 return nil 27 } 28 29 // Wait for height will poll status at reasonable intervals until 30 // the block at the given height is available. 31 // 32 // If waiter is nil, we use DefaultWaitStrategy, but you can also 33 // provide your own implementation 34 func WaitForHeight(c StatusClient, h int64, waiter Waiter) error { 35 if waiter == nil { 36 waiter = DefaultWaitStrategy 37 } 38 delta := int64(1) 39 for delta > 0 { 40 s, err := c.Status() 41 if err != nil { 42 return err 43 } 44 delta = h - s.SyncInfo.LatestBlockHeight 45 // wait for the time, or abort early 46 if err := waiter(delta); err != nil { 47 return err 48 } 49 } 50 return nil 51 } 52 53 // WaitForOneEvent subscribes to a websocket event for the given 54 // event time and returns upon receiving it one time, or 55 // when the timeout duration has expired. 56 // 57 // This handles subscribing and unsubscribing under the hood 58 func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (types.TMEventData, error) { 59 const subscriber = "helpers" 60 ctx, cancel := context.WithTimeout(context.Background(), timeout) 61 defer cancel() 62 63 // register for the next event of this type 64 eventCh, err := c.Subscribe(ctx, subscriber, types.QueryForEvent(evtTyp).String()) 65 if err != nil { 66 return nil, errors.Wrap(err, "failed to subscribe") 67 } 68 // make sure to unregister after the test is over 69 defer c.UnsubscribeAll(ctx, subscriber) 70 71 select { 72 case event := <-eventCh: 73 return event.Data.(types.TMEventData), nil 74 case <-ctx.Done(): 75 return nil, errors.New("timed out waiting for event") 76 } 77 }