@@ -3,6 +3,7 @@ package ntp
33import (
44 "context"
55 "sync"
6+ "sync/atomic"
67 "time"
78
89 "github.com/metacubex/mihomo/component/dialer"
@@ -13,24 +14,29 @@ import (
1314 "github.com/metacubex/sing/common/ntp"
1415)
1516
16- var offset time. Duration
17- var service * Service
17+ var globalSrv atomic. Pointer [ Service ]
18+ var globalMu sync. Mutex
1819
1920type Service struct {
2021 server M.Socksaddr
2122 dialer proxydialer.SingDialer
2223 ticker * time.Ticker
2324 ctx context.Context
2425 cancel context.CancelFunc
25- mu sync. Mutex
26+ offset atomic. Int64 // [time.Duration]
2627 syncSystemTime bool
27- running bool
2828}
2929
3030func ReCreateNTPService (server string , interval time.Duration , dialerProxy string , syncSystemTime bool ) {
31+ globalMu .Lock ()
32+ defer globalMu .Unlock ()
33+ service := globalSrv .Swap (nil )
3134 if service != nil {
3235 service .Stop ()
3336 }
37+ if server == "" {
38+ return
39+ }
3440 ctx , cancel := context .WithCancel (context .Background ())
3541 service = & Service {
3642 server : M .ParseSocksaddr (server ),
@@ -41,87 +47,76 @@ func ReCreateNTPService(server string, interval time.Duration, dialerProxy strin
4147 syncSystemTime : syncSystemTime ,
4248 }
4349 service .Start ()
50+ globalSrv .Store (service )
4451}
4552
4653func (srv * Service ) Start () {
47- srv .mu .Lock ()
48- defer srv .mu .Unlock ()
4954 log .Infoln ("NTP service start, sync system time is %t" , srv .syncSystemTime )
50- err := srv .update ()
51- if err != nil {
52- log .Errorln ("Initialize NTP time failed: %s" , err )
53- return
54- }
55- service .running = true
5655 go srv .loopUpdate ()
5756}
5857
5958func (srv * Service ) Stop () {
60- srv .mu .Lock ()
61- defer srv .mu .Unlock ()
62- if service .running {
63- srv .ticker .Stop ()
64- srv .cancel ()
65- service .running = false
66- }
59+ srv .cancel ()
6760}
6861
69- func (srv * Service ) Running () bool {
62+ func (srv * Service ) Offset () time. Duration {
7063 if srv == nil {
71- return false
64+ return 0
7265 }
73- srv .mu .Lock ()
74- defer srv .mu .Unlock ()
75- return srv .running
66+ if srv .ctx .Err () != nil {
67+ return time .Duration (srv .offset .Load ())
68+ }
69+ return 0
7670}
7771
7872func (srv * Service ) update () error {
7973 var response * ntp.Response
8074 var err error
8175 for i := 0 ; i < 3 ; i ++ {
82- if response , err = ntp .Exchange (context .Background (), srv .dialer , srv .server ); err == nil {
83- break
76+ response , err = ntp .Exchange (srv .ctx , srv .dialer , srv .server )
77+ if err != nil {
78+ continue
8479 }
85- if i == 2 {
86- return err
80+ offset := response .ClockOffset
81+ if offset > time .Duration (0 ) {
82+ log .Infoln ("System clock is ahead of NTP time by %s" , offset )
83+ } else if offset < time .Duration (0 ) {
84+ log .Infoln ("System clock is behind NTP time by %s" , - offset )
8785 }
88- }
89- offset = response .ClockOffset
90- if offset > time .Duration (0 ) {
91- log .Infoln ("System clock is ahead of NTP time by %s" , offset )
92- } else if offset < time .Duration (0 ) {
93- log .Infoln ("System clock is behind NTP time by %s" , - offset )
94- }
95- if srv .syncSystemTime {
96- timeNow := response .Time
97- syncErr := setSystemTime (timeNow )
98- if syncErr == nil {
99- log .Infoln ("Sync system time success: %s" , timeNow .Local ().Format (ntp .TimeLayout ))
100- } else {
101- log .Errorln ("Write time to system: %s" , syncErr )
102- srv .syncSystemTime = false
86+ srv .offset .Store (int64 (offset ))
87+ if srv .syncSystemTime {
88+ timeNow := response .Time
89+ syncErr := setSystemTime (timeNow )
90+ if syncErr == nil {
91+ log .Infoln ("Sync system time success: %s" , timeNow .Local ().Format (ntp .TimeLayout ))
92+ } else {
93+ log .Errorln ("Write time to system: %s" , syncErr )
94+ srv .syncSystemTime = false
95+ }
10396 }
97+ return nil
10498 }
105- return nil
99+ return err
106100}
107101
108102func (srv * Service ) loopUpdate () {
103+ defer srv .ticker .Stop ()
109104 for {
105+ err := srv .update ()
106+ if err != nil {
107+ log .Warnln ("Sync time failed: %s" , err )
108+ }
110109 select {
111110 case <- srv .ctx .Done ():
112111 return
113112 case <- srv .ticker .C :
114113 }
115- err := srv .update ()
116- if err != nil {
117- log .Warnln ("Sync time failed: %s" , err )
118- }
119114 }
120115}
121116
122117func Now () time.Time {
123118 now := time .Now ()
124- if service . Running () && offset .Abs () > 0 {
119+ if offset := globalSrv . Load (). Offset (); offset .Abs () > 0 {
125120 now = now .Add (offset )
126121 }
127122 return now
0 commit comments