count_time.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // package count_time -- счётчик обратного времени в мсек
  2. //
  3. // Похоже, нигде не используется
  4. package count_time
  5. import (
  6. "fmt"
  7. // "log"
  8. "sync"
  9. "time"
  10. "wartank/pkg/components/parsetime"
  11. "wartank/pkg/components/safebool"
  12. "wartank/pkg/components/safeint"
  13. "wartank/pkg/types"
  14. )
  15. const (
  16. iSleep = time.Millisecond * 100
  17. )
  18. // CountTime -- счётчик обратного времени
  19. type CountTime struct {
  20. bot types.IBot
  21. val *safeint.SafeInt
  22. parser *parsetime.ParseTime
  23. chTick chan int
  24. chCall chan int // Канал для отправки сигналов
  25. isWork *safebool.SafeBool // Признак работы
  26. timeTarget *safeint.SafeInt // Целевое время срабатывания
  27. block sync.RWMutex
  28. }
  29. // NewCountTime -- возвращает новый *CountTime
  30. func NewCountTime(bot types.IBot) *CountTime {
  31. if bot == nil {
  32. panic("NewCountTime(): IBot == nil")
  33. }
  34. sf := &CountTime{
  35. bot: bot,
  36. val: safeint.NewSafeInt(),
  37. chTick: make(chan int, 3),
  38. chCall: make(chan int, 2),
  39. isWork: safebool.NewSafeBool(),
  40. parser: parsetime.NewParseTime(),
  41. timeTarget: safeint.NewSafeInt(),
  42. }
  43. sf.isWork.Set()
  44. go sf.makeTick()
  45. go sf.run()
  46. return sf
  47. }
  48. // Запускает тикер для секундных интервалов
  49. func (sf *CountTime) makeTick() {
  50. defer func() {
  51. if !sf.isWork.Get() {
  52. return
  53. }
  54. sf.isWork.Reset()
  55. close(sf.chTick)
  56. // log._rintf("CountTime.makeTick(): работа завершена")
  57. }()
  58. countSleep := time.Duration(0)
  59. for {
  60. select {
  61. case <-sf.bot.Ctx().Done(): // Отмена контекста бота
  62. // log._rintf("CountTime.makeTick(): глобальная отмена контекста\n")
  63. return
  64. default:
  65. if !sf.isWork.Get() {
  66. return
  67. }
  68. if countSleep >= time.Second {
  69. sf.chTick <- 1
  70. countSleep = 0
  71. }
  72. countSleep += iSleep
  73. time.Sleep(iSleep)
  74. }
  75. }
  76. }
  77. // Главный цикл обратного отсчёта
  78. func (sf *CountTime) run() {
  79. for range sf.chTick {
  80. timeNow := time.Now().UTC().Unix()
  81. if sf.timeTarget.Get() > int(timeNow) {
  82. val := sf.timeTarget.Get() - int(timeNow)
  83. val -= 1
  84. sf.Set(val)
  85. continue
  86. }
  87. sf.chCall <- 1
  88. continue
  89. }
  90. close(sf.chCall)
  91. }
  92. // Stop -- останавливает работу чяётчика
  93. func (sf *CountTime) Stop() {
  94. sf.isWork.Reset()
  95. }
  96. // Get -- возвращает число оставшихся сек
  97. func (sf *CountTime) Get() int {
  98. return sf.val.Get()
  99. }
  100. // Parse -- устанавливает число оставшихся сек
  101. func (sf *CountTime) Parse(val string) error {
  102. sf.block.Lock()
  103. defer sf.block.Unlock()
  104. if val == "" {
  105. return fmt.Errorf("CountTime.Set(): val is empty")
  106. }
  107. sf.parser.Parse(val)
  108. _val := sf.parser.Hour().Get()*3600 + sf.parser.Min().Get()*60 + sf.parser.Min().Get()
  109. sf.val.Set(_val)
  110. _val = int(time.Now().UTC().Unix()) + sf.val.Get()
  111. sf.timeTarget.Set(_val)
  112. return nil
  113. }
  114. // Set -- устанавливает число оставшихся сек
  115. func (sf *CountTime) Set(val int) error {
  116. sf.block.Lock()
  117. defer sf.block.Unlock()
  118. if val < 0 {
  119. return fmt.Errorf("CountTime.Set(): val(%v)<0", val)
  120. }
  121. sf.val.Set(val)
  122. { // Обновить локальные счётчики
  123. if val < 60 {
  124. sf.parser.Hour().Reset()
  125. sf.parser.Min().Reset()
  126. sf.parser.Sec().Set(val)
  127. return nil
  128. }
  129. if 60 < val && val < 3600 {
  130. sf.parser.Hour().Reset()
  131. iMin := val / 60
  132. sf.parser.Min().Set(iMin)
  133. val -= iMin * 60
  134. sf.parser.Sec().Set(val)
  135. return nil
  136. }
  137. sf.parser.Hour().Set(val / 3600)
  138. val -= sf.parser.Hour().Get() * 3600
  139. sf.parser.Min().Set(val / 60)
  140. val -= sf.parser.Min().Get() * 60
  141. sf.parser.Sec().Set(val)
  142. val = int(time.Now().UTC().Unix()) + sf.val.Get()
  143. sf.timeTarget.Set(val)
  144. }
  145. return nil
  146. }
  147. // String -- возвращает строковое представление оставшихся сек
  148. func (sf *CountTime) String() string {
  149. sf.block.RLock()
  150. defer sf.block.RUnlock()
  151. return sf.parser.String()
  152. }
  153. // ChanSig -- возвращает канал чтения тиков
  154. func (sf *CountTime) ChanSig() <-chan int {
  155. return sf.chCall
  156. }