package timer import ( "github.com/fox/fox/log" "github.com/fox/fox/safeChan" cmap "github.com/orcaman/concurrent-map/v2" "math" "sync/atomic" "time" ) type timerData struct { timer *time.Timer id uint32 Func func() desc string needLog bool } type Timer struct { chTimer *safeChan.SafeChan[*timerData] timers cmap.ConcurrentMap[uint32, *timerData] no uint32 stop int32 } func NewTimer() *Timer { rt := &Timer{} rt.chTimer = safeChan.NewSafeChan[*timerData](16) rt.timers = cmap.NewWithCustomShardingFunction[uint32, *timerData](func(key uint32) uint32 { return key }) rt.no = math.MaxUint32 - 2 rt.stop = 0 return rt } func (rt *Timer) NewTimer(duration time.Duration, cb func(), needLog bool, desc ...string) uint32 { tData := &timerData{ timer: nil, id: atomic.AddUint32(&rt.no, 1), Func: cb, needLog: needLog, } if len(desc) > 0 { tData.desc = desc[0] } t := time.AfterFunc(duration, func() { _ = rt.chTimer.Write(tData) rt.timers.Remove(tData.id) if needLog { if tData.desc != "" { log.DebugF("移除定时器:%v NewTimer desc:%v time:%v", tData.id, tData.desc, duration) } else { log.DebugF("移除定时器:%v NewTimer", tData.id) } } }) tData.timer = t rt.timers.Set(tData.id, tData) if needLog { if tData.desc != "" { log.DebugF("设置定时器:%v NewTimer desc:%v", tData.id, tData.desc) } else { log.DebugF("设置定时器:%v NewTimer", tData.id) } } return tData.id } func (rt *Timer) CancelTimer(timerId uint32) { if t, _ := rt.timers.Get(timerId); t != nil { if t.timer != nil { _ = t.timer.Stop() } rt.timers.Remove(timerId) if t.needLog { if t.desc != "" { log.DebugF("移除定时器:%v CancelTimer desc:%v", t.id, t.desc) } else { log.DebugF("移除定时器:%v CancelTimer", t.id) } } } } func (rt *Timer) CancelAllTimer() { rt.timers.IterCb(func(_ uint32, t *timerData) { if t.timer != nil { t.timer.Stop() if t.needLog { if t.desc != "" { log.DebugF("移除定时器:%v CancelAllTimer desc:%v", t.id, t.desc) } else { log.DebugF("移除定时器:%v CancelAllTimer", t.id) } } } }) rt.timers.Clear() } func (rt *Timer) Reader() <-chan *timerData { return rt.chTimer.Reader() } func (rt *Timer) Close() { rt.chTimer.Close() }