counttime.go 3.9 KB

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