github.com/annchain/OG@v0.0.9/poc/tendermint/waiter.go (about) 1 package tendermint 2 3 import ( 4 "github.com/annchain/OG/ffchan" 5 "github.com/sirupsen/logrus" 6 "time" 7 ) 8 9 type WaiterContext interface { 10 Equal(WaiterContext) bool 11 IsAfter(WaiterContext) bool 12 } 13 14 type WaiterRequest struct { 15 WaitTime time.Duration 16 Context WaiterContext 17 TimeoutCallback func(WaiterContext) 18 } 19 20 // Waiter provides a way to wait for some context to be changed in a certain time. 21 // If the context is not changed, callback function will be triggered. 22 type Waiter struct { 23 currentRequest *WaiterRequest 24 requestChannel chan *WaiterRequest 25 contextChannel chan WaiterContext 26 callbackEventChanel chan *WaiterRequest 27 quit chan bool 28 } 29 30 func NewWaiter(callbackEventChannel chan *WaiterRequest) *Waiter { 31 return &Waiter{ 32 requestChannel: make(chan *WaiterRequest, 10), 33 contextChannel: make(chan WaiterContext, 10), 34 quit: make(chan bool), 35 callbackEventChanel: callbackEventChannel, 36 } 37 } 38 39 func (w *Waiter) StartEventLoop() { 40 timer := time.NewTimer(time.Duration(10)) 41 for { 42 select { 43 case <-w.quit: 44 break 45 case request := <-w.requestChannel: 46 // could be an updated request 47 // if it is really updated request, 48 if w.currentRequest != nil && !request.Context.IsAfter(w.currentRequest.Context) { 49 // this request is before current waiting request, ignore. 50 continue 51 } 52 logrus.WithField("request ", request).Trace("request is newer and we will reset") 53 w.currentRequest = request 54 if !timer.Stop() { 55 // drain the timer but do not use the method in document 56 // timer may already be consumed so use a select 57 select { 58 case <-timer.C: 59 default: 60 } 61 } 62 timer.Reset(request.WaitTime) 63 case latestContext := <-w.contextChannel: 64 if w.currentRequest == nil || latestContext.IsAfter(w.currentRequest.Context) { 65 // a new state is updated, cancel all pending timeouts 66 if w.currentRequest != nil { 67 logrus.WithField("new", latestContext.(*TendermintContext).StepType). 68 WithField("old", w.currentRequest.Context.(*TendermintContext).StepType). 69 Debug("new state updated") 70 } else { 71 logrus.WithField("new", latestContext.(*TendermintContext).StepType). 72 WithField("old", nil). 73 Debug("new state updated") 74 } 75 if !timer.Stop() { 76 // drain the timer but do not use the method in document 77 // timer may already be consumed so use a select 78 select { 79 case <-timer.C: 80 default: 81 } 82 } 83 } 84 case <-timer.C: 85 // timeout, trigger callback 86 if w.currentRequest != nil { 87 <-ffchan.NewTimeoutSenderShort(w.callbackEventChanel, w.currentRequest, "waiterCallback").C 88 //w.currentRequest.TimeoutCallback(w.currentRequest.Context) 89 } 90 } 91 } 92 } 93 94 func (w *Waiter) UpdateRequest(req *WaiterRequest) { 95 w.requestChannel <- req 96 //ffchan.NewTimeoutSenderShort(w.requestChannel, req, "waiterrequest") 97 } 98 99 func (w *Waiter) UpdateContext(context WaiterContext) { 100 w.contextChannel <- context 101 //ffchan.NewTimeoutSenderShort(w.contextChannel, context, "waitercontext") 102 }