service.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package ntp
  2. import (
  3. "context"
  4. "os"
  5. "time"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/common/dialer"
  8. "github.com/sagernet/sing-box/common/settings"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/common"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. "github.com/sagernet/sing/common/logger"
  14. M "github.com/sagernet/sing/common/metadata"
  15. N "github.com/sagernet/sing/common/network"
  16. "github.com/sagernet/sing/common/ntp"
  17. )
  18. var _ ntp.TimeService = (*Service)(nil)
  19. type Service struct {
  20. ctx context.Context
  21. cancel common.ContextCancelCauseFunc
  22. server M.Socksaddr
  23. writeToSystem bool
  24. dialer N.Dialer
  25. logger logger.Logger
  26. ticker *time.Ticker
  27. clockOffset time.Duration
  28. }
  29. func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) (*Service, error) {
  30. ctx, cancel := common.ContextWithCancelCause(ctx)
  31. server := M.ParseSocksaddrHostPort(options.Server, options.ServerPort)
  32. if server.Port == 0 {
  33. server.Port = 123
  34. }
  35. var interval time.Duration
  36. if options.Interval > 0 {
  37. interval = time.Duration(options.Interval)
  38. } else {
  39. interval = 30 * time.Minute
  40. }
  41. outboundDialer, err := dialer.New(router, options.DialerOptions)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return &Service{
  46. ctx: ctx,
  47. cancel: cancel,
  48. server: server,
  49. writeToSystem: options.WriteToSystem,
  50. dialer: outboundDialer,
  51. logger: logger,
  52. ticker: time.NewTicker(interval),
  53. }, nil
  54. }
  55. func (s *Service) Start() error {
  56. err := s.update()
  57. if err != nil {
  58. return E.Cause(err, "initialize time")
  59. }
  60. s.logger.Info("updated time: ", s.TimeFunc()().Local().Format(C.TimeLayout))
  61. go s.loopUpdate()
  62. return nil
  63. }
  64. func (s *Service) Close() error {
  65. s.ticker.Stop()
  66. s.cancel(os.ErrClosed)
  67. return nil
  68. }
  69. func (s *Service) TimeFunc() func() time.Time {
  70. return func() time.Time {
  71. return time.Now().Add(s.clockOffset)
  72. }
  73. }
  74. func (s *Service) loopUpdate() {
  75. for {
  76. select {
  77. case <-s.ctx.Done():
  78. return
  79. case <-s.ticker.C:
  80. }
  81. err := s.update()
  82. if err == nil {
  83. s.logger.Debug("updated time: ", s.TimeFunc()().Local().Format(C.TimeLayout))
  84. } else {
  85. s.logger.Warn("update time: ", err)
  86. }
  87. }
  88. }
  89. func (s *Service) update() error {
  90. response, err := ntp.Exchange(s.ctx, s.dialer, s.server)
  91. if err != nil {
  92. return err
  93. }
  94. s.clockOffset = response.ClockOffset
  95. if s.writeToSystem {
  96. writeErr := settings.SetSystemTime(s.TimeFunc()())
  97. if writeErr != nil {
  98. s.logger.Warn("write time to system: ", writeErr)
  99. }
  100. }
  101. return nil
  102. }