service.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package ntp
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/metacubex/mihomo/component/dialer"
  7. "github.com/metacubex/mihomo/component/proxydialer"
  8. "github.com/metacubex/mihomo/log"
  9. M "github.com/sagernet/sing/common/metadata"
  10. "github.com/sagernet/sing/common/ntp"
  11. )
  12. var offset time.Duration
  13. var service *Service
  14. type Service struct {
  15. server M.Socksaddr
  16. dialer proxydialer.SingDialer
  17. ticker *time.Ticker
  18. ctx context.Context
  19. cancel context.CancelFunc
  20. mu sync.Mutex
  21. syncSystemTime bool
  22. running bool
  23. }
  24. func ReCreateNTPService(server string, interval time.Duration, dialerProxy string, syncSystemTime bool) {
  25. if service != nil {
  26. service.Stop()
  27. }
  28. ctx, cancel := context.WithCancel(context.Background())
  29. service = &Service{
  30. server: M.ParseSocksaddr(server),
  31. dialer: proxydialer.NewByNameSingDialer(dialerProxy, dialer.NewDialer()),
  32. ticker: time.NewTicker(interval * time.Minute),
  33. ctx: ctx,
  34. cancel: cancel,
  35. syncSystemTime: syncSystemTime,
  36. }
  37. service.Start()
  38. }
  39. func (srv *Service) Start() {
  40. srv.mu.Lock()
  41. defer srv.mu.Unlock()
  42. log.Infoln("NTP service start, sync system time is %t", srv.syncSystemTime)
  43. err := srv.update()
  44. if err != nil {
  45. log.Errorln("Initialize NTP time failed: %s", err)
  46. return
  47. }
  48. service.running = true
  49. go srv.loopUpdate()
  50. }
  51. func (srv *Service) Stop() {
  52. srv.mu.Lock()
  53. defer srv.mu.Unlock()
  54. if service.running {
  55. srv.ticker.Stop()
  56. srv.cancel()
  57. service.running = false
  58. }
  59. }
  60. func (srv *Service) Running() bool {
  61. if srv == nil {
  62. return false
  63. }
  64. srv.mu.Lock()
  65. defer srv.mu.Unlock()
  66. return srv.running
  67. }
  68. func (srv *Service) update() error {
  69. var response *ntp.Response
  70. var err error
  71. for i := 0; i < 3; i++ {
  72. if response, err = ntp.Exchange(context.Background(), srv.dialer, srv.server); err == nil {
  73. break
  74. }
  75. if i == 2 {
  76. return err
  77. }
  78. }
  79. offset = response.ClockOffset
  80. if offset > time.Duration(0) {
  81. log.Infoln("System clock is ahead of NTP time by %s", offset)
  82. } else if offset < time.Duration(0) {
  83. log.Infoln("System clock is behind NTP time by %s", -offset)
  84. }
  85. if srv.syncSystemTime {
  86. timeNow := response.Time
  87. syncErr := setSystemTime(timeNow)
  88. if syncErr == nil {
  89. log.Infoln("Sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout))
  90. } else {
  91. log.Errorln("Write time to system: %s", syncErr)
  92. srv.syncSystemTime = false
  93. }
  94. }
  95. return nil
  96. }
  97. func (srv *Service) loopUpdate() {
  98. for {
  99. select {
  100. case <-srv.ctx.Done():
  101. return
  102. case <-srv.ticker.C:
  103. }
  104. err := srv.update()
  105. if err != nil {
  106. log.Warnln("Sync time failed: %s", err)
  107. }
  108. }
  109. }
  110. func Now() time.Time {
  111. now := time.Now()
  112. if service.Running() && offset.Abs() > 0 {
  113. now = now.Add(offset)
  114. }
  115. return now
  116. }