package otherutils import ( "sync" "time" ) type event struct { timer *time.Timer ticker *time.Ticker endtime time.Time duration time.Duration parameter interface{} } func (e *event) expire() bool { if e.timer != nil { select { case <-e.timer.C: return true default: } } if e.ticker != nil { select { case <-e.ticker.C: return true default: } } return false } // Scheduler 调度程序 type Scheduler interface { OnTimer(id int, parameter interface{}) } // Schedule 时间表 // 定时时间精确到秒,不精确管理goroutine的退出 // 目前只用来管理房间 type Schedule struct { scheduler Scheduler mutex sync.Mutex events map[int]*event } // NewSchedule 创建时间表 func NewSchedule(scheduler Scheduler) *Schedule { return &Schedule{ scheduler: scheduler, events: make(map[int]*event), } } // Start 开始 func (s *Schedule) Start() { for { time.Sleep(time.Second) s.mutex.Lock() for k, v := range s.events { if v.expire() { if v.timer != nil { delete(s.events, k) } if v.ticker != nil { v.endtime = v.endtime.Add(v.duration) } go s.scheduler.OnTimer(k, v.parameter) } } s.mutex.Unlock() } } // Add 添加 func (s *Schedule) Add(id int, duration time.Duration, parameter interface{}, persistence bool) { s.mutex.Lock() defer s.mutex.Unlock() ev, ok := s.events[id] if ok { if ev.timer == nil { return } if !ev.timer.Stop() { <-ev.timer.C // 必须这样做,不然Reset之后有可能立刻到期 } ev.timer.Reset(duration) } else { ev = new(event) s.events[id] = ev if !persistence { ev.timer = time.NewTimer(duration) } else { ev.ticker = time.NewTicker(duration) } } ev.duration = duration ev.parameter = parameter ev.endtime = time.Now().Add(duration) } // Remove 移除 func (s *Schedule) Remove(id int) { s.mutex.Lock() defer s.mutex.Unlock() if ev, ok := s.events[id]; ok { if ev.timer != nil && !ev.timer.Stop() { <-ev.timer.C } if ev.ticker != nil { ev.ticker.Stop() } delete(s.events, id) } } // Surplus 剩余 func (s *Schedule) Surplus(id int) (duration time.Duration) { s.mutex.Lock() defer s.mutex.Unlock() if ev, ok := s.events[id]; ok { duration = ev.endtime.Sub(time.Now()) } if duration < 0 { duration = 0 } return }