// Copyright 2018 The dexon-consensus Authors // This file is part of the dexon-consensus library. // // The dexon-consensus library is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // The dexon-consensus library is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the dexon-consensus library. If not, see // . package core import ( "context" "fmt" "sync" "time" "github.com/dexon-foundation/dexon-consensus/core/utils" ) // TickerType is the type of ticker. type TickerType int // TickerType enum. const ( TickerBA TickerType = iota TickerDKG TickerCRS ) // defaultTicker is a wrapper to implement ticker interface based on // time.Ticker. type defaultTicker struct { ticker *time.Ticker tickerChan chan time.Time duration time.Duration ctx context.Context ctxCancel context.CancelFunc waitGroup sync.WaitGroup } // newDefaultTicker constructs an defaultTicker instance by giving an interval. func newDefaultTicker(lambda time.Duration) *defaultTicker { ticker := &defaultTicker{duration: lambda} ticker.init() return ticker } // Tick implements Tick method of ticker interface. func (t *defaultTicker) Tick() <-chan time.Time { return t.tickerChan } // Stop implements Stop method of ticker interface. func (t *defaultTicker) Stop() { t.ticker.Stop() t.ctxCancel() t.waitGroup.Wait() t.ctx = nil t.ctxCancel = nil close(t.tickerChan) t.tickerChan = nil } // Restart implements Stop method of ticker interface. func (t *defaultTicker) Restart() { t.Stop() t.init() } func (t *defaultTicker) init() { t.ticker = time.NewTicker(t.duration) t.tickerChan = make(chan time.Time) t.ctx, t.ctxCancel = context.WithCancel(context.Background()) t.waitGroup.Add(1) go t.monitor() } func (t *defaultTicker) monitor() { defer t.waitGroup.Done() loop: for { select { case <-t.ctx.Done(): break loop case v := <-t.ticker.C: select { case t.tickerChan <- v: default: } } } } // newTicker is a helper to setup a ticker by giving an Governance. If // the governace object implements a ticker generator, a ticker from that // generator would be returned, else constructs a default one. func newTicker(gov Governance, round uint64, tickerType TickerType) (t Ticker) { type tickerGenerator interface { NewTicker(TickerType) Ticker } if gen, ok := gov.(tickerGenerator); ok { t = gen.NewTicker(tickerType) } if t == nil { var duration time.Duration switch tickerType { case TickerBA: duration = utils.GetConfigWithPanic(gov, round, nil).LambdaBA case TickerDKG: duration = utils.GetConfigWithPanic(gov, round, nil).LambdaDKG default: panic(fmt.Errorf("unknown ticker type: %d", tickerType)) } t = newDefaultTicker(duration) } return }