| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- // package count_time -- счётчик обратного времени в мсек
- //
- // Похоже, нигде не используется
- package count_time
- import (
- "context"
- "fmt"
- // "log"
- "sync"
- "time"
- "wartank/pkg/components/parsetime"
- "wartank/pkg/components/safebool"
- "wartank/pkg/components/safeint"
- "wartank/pkg/types"
- )
- const (
- sleepInterval = time.Millisecond * 100 // Малый интервал сна в 100 мсек
- )
- // CountTime -- счётчик обратного времени для игровой зоны (анга, база, битва и т.п.)
- type CountTime struct {
- zone types.IZone
- val *safeint.SafeInt
- parser *parsetime.ParseTime
- chTick chan int // Канал секундных интервалов сна
- chCall chan int // Канал для отправки сигналов
- isWork *safebool.SafeBool // Признак работы
- timeTarget *safeint.SafeInt // Целевое время срабатывания
- ctx context.Context // Контекст для счётчика времени
- fnCancel func() // Функция отмены контекста для счётчика времени
- block sync.RWMutex
- }
- // NewCountTime -- возвращает новый *CountTime
- func NewCountTime(zone types.IZone) *CountTime {
- if zone == nil {
- panic("NewCountTime(): IZone == nil")
- }
- ctx, fnCancel := context.WithCancel(zone.Ctx())
- sf := &CountTime{
- zone: zone,
- val: safeint.NewSafeInt(),
- chTick: make(chan int, 3),
- chCall: make(chan int, 2),
- isWork: safebool.NewSafeBool(),
- parser: parsetime.NewParseTime(),
- timeTarget: safeint.NewSafeInt(),
- ctx: ctx,
- fnCancel: fnCancel,
- }
- sf.isWork.Set()
- go sf.makeTick()
- go sf.run()
- return sf
- }
- // Запускает тикер для секундных интервалов
- func (sf *CountTime) makeTick() {
- defer func() {
- if !sf.isWork.Get() {
- return
- }
- sf.fnCancel()
- sf.isWork.Reset()
- close(sf.chTick)
- // log._rintf("CountTime.makeTick(): работа завершена")
- }()
- countSleep := 0 // Счётчик сна (10 периодов -- 1 секунда)
- for {
- select {
- case <-sf.ctx.Done(): // Отмена контекста бота
- // log._rintf("CountTime.makeTick(): отмена контекста бота\n")
- return
- default:
- if !sf.isWork.Get() {
- return
- }
- if countSleep >= 10 {
- sf.chTick <- 1
- countSleep = 0
- }
- countSleep++
- time.Sleep(sleepInterval)
- }
- }
- }
- // Главный цикл обратного отсчёта
- func (sf *CountTime) run() {
- for range sf.chTick {
- timeNow := time.Now().UTC().Unix()
- if sf.timeTarget.Get() > int(timeNow) {
- val := sf.timeTarget.Get() - int(timeNow)
- val -= 1
- sf.Set(val)
- continue
- }
- close(sf.chCall)
- sf.fnCancel()
- return
- }
- }
- // Stop -- останавливает работу cчётчика
- func (sf *CountTime) Stop() {
- sf.isWork.Reset()
- }
- // Get -- возвращает число оставшихся сек
- func (sf *CountTime) Get() int {
- return sf.val.Get()
- }
- // Parse -- устанавливает число оставшихся сек
- func (sf *CountTime) Parse(val string) error {
- sf.block.Lock()
- defer sf.block.Unlock()
- if val == "" {
- return fmt.Errorf("CountTime.Set(): val is empty")
- }
- sf.parser.Parse(val)
- _val := sf.parser.Hour().Get()*3600 + sf.parser.Min().Get()*60 + sf.parser.Min().Get()
- sf.val.Set(_val)
- _val = int(time.Now().UTC().Unix()) + sf.val.Get()
- sf.timeTarget.Set(_val)
- return nil
- }
- // Set -- устанавливает число оставшихся сек
- func (sf *CountTime) Set(val int) error {
- sf.block.Lock()
- defer sf.block.Unlock()
- if val < 0 {
- return fmt.Errorf("CountTime.Set(): val(%v)<0", val)
- }
- sf.val.Set(val)
- { // Обновить локальные счётчики
- if val < 60 {
- sf.parser.Hour().Reset()
- sf.parser.Min().Reset()
- sf.parser.Sec().Set(val)
- return nil
- }
- if 60 < val && val < 3600 {
- sf.parser.Hour().Reset()
- iMin := val / 60
- sf.parser.Min().Set(iMin)
- val -= iMin * 60
- sf.parser.Sec().Set(val)
- return nil
- }
- sf.parser.Hour().Set(val / 3600)
- val -= sf.parser.Hour().Get() * 3600
- sf.parser.Min().Set(val / 60)
- val -= sf.parser.Min().Get() * 60
- sf.parser.Sec().Set(val)
- val = int(time.Now().UTC().Unix()) + sf.val.Get()
- sf.timeTarget.Set(val)
- }
- return nil
- }
- // String -- возвращает строковое представление оставшихся сек
- func (sf *CountTime) String() string {
- sf.block.RLock()
- defer sf.block.RUnlock()
- return sf.parser.String()
- }
- // ChanSig -- возвращает канал чтения тиков
- func (sf *CountTime) ChanSig() <-chan int {
- return sf.chCall
- }
|