| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- package counttime
- import (
- "fmt"
- // "log"
- "sync"
- "time"
- . "gitp78su.ipnodns.ru/svi/kern"
- . "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
- . "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
- "wartank/pkg/components/parsetime"
- )
- /*
- Счётчик обратного временив мсек
- */
- const (
- iSleep = time.Millisecond * 100
- )
- // CountTime -- счётчик обратного времени
- type CountTime struct {
- kCtx IKernelCtx
- val ISafeInt
- parser *parsetime.ParseTime
- chTick chan int
- chCall chan int // Канал для отправки сигналов
- isWork ISafeBool // Признак работы
- timeTarget ISafeInt // Целевое время срабатывания
- block sync.RWMutex
- }
- // NewCountTime -- возвращает новый *CountTime
- func NewCountTime() *CountTime {
- sf := &CountTime{
- kCtx: GetKernelCtx(),
- val: NewSafeInt(),
- chTick: make(chan int, 3),
- chCall: make(chan int, 2),
- isWork: NewSafeBool(),
- parser: parsetime.NewParseTime(),
- timeTarget: NewSafeInt(),
- }
- sf.isWork.Set()
- go sf.makeTick()
- go sf.run()
- return sf
- }
- // Запускает тикер для секундных интервалов
- func (sf *CountTime) makeTick() {
- defer func() {
- if !sf.isWork.Get() {
- return
- }
- sf.isWork.Reset()
- close(sf.chTick)
- // log._rintf("CountTime.makeTick(): работа завершена")
- }()
- countSleep := time.Duration(0)
- for {
- select {
- case <-sf.kCtx.Ctx().Done(): // Отмена контекста приложения
- // log._rintf("CountTime.makeTick(): глобальная отмена контекста\n")
- return
- default:
- if !sf.isWork.Get() {
- return
- }
- if countSleep >= time.Second {
- sf.chTick <- 1
- countSleep = 0
- }
- countSleep += iSleep
- time.Sleep(iSleep)
- }
- }
- }
- // Главный цикл обратного отсчёта
- 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
- err := sf.Set(val)
- Hassert(err == nil, "err=%v", err)
- continue
- }
- sf.chCall <- 1
- continue
- }
- close(sf.chCall)
- }
- // Stop -- останавливает работу счётчика
- 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")
- }
- err := sf.parser.Parse(val)
- Hassert(err == nil, "err=%v", err)
- _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()
- err := sf.parser.Sec().Set(val)
- Hassert(err == nil, "err==%v", err)
- return nil
- }
- if 60 < val && val < 3600 {
- sf.parser.Hour().Reset()
- iMin := val / 60
- err := sf.parser.Min().Set(iMin)
- Hassert(err == nil, "err=%v", err)
- val -= iMin * 60
- err = sf.parser.Sec().Set(val)
- Hassert(err == nil, "err=%v", err)
- return nil
- }
- err := sf.parser.Hour().Set(val / 3600)
- Hassert(err == nil, "err=%v", err)
- val -= sf.parser.Hour().Get() * 3600
- err = sf.parser.Min().Set(val / 60)
- Hassert(err == nil, "err=%v", err)
- val -= sf.parser.Min().Get() * 60
- err = sf.parser.Sec().Set(val)
- Hassert(err == nil, "err=%v", err)
- 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
- }
|