main.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "flag"
  6. "fmt"
  7. "net/http"
  8. "os"
  9. "rtu_linux_services/servicelib"
  10. "sync/atomic"
  11. "time"
  12. "github.com/kardianos/service"
  13. "hnyfkj.com.cn/rtu/linux/baseapp"
  14. "hnyfkj.com.cn/rtu/linux/netmgrd"
  15. "hnyfkj.com.cn/rtu/linux/utils/jsonrpc2"
  16. )
  17. var (
  18. Version = "0.0.0.1"
  19. BuildTime = ""
  20. )
  21. const (
  22. network = "tcp" // http -> tcp
  23. listenAddr = "127.0.0.1:7001"
  24. )
  25. type program struct {
  26. name string
  27. core_server *jsonrpc2.RPCServer
  28. http_server *http.Server
  29. timeSyncOK atomic.Bool
  30. syncSource atomic.Value
  31. stopTimeSync chan struct{}
  32. }
  33. // Start should not block. Do the actual work async.
  34. func (p *program) Start(s service.Service) error {
  35. logCfgFile, err := servicelib.EnsureDefaultLogConfig()
  36. if err != nil {
  37. return err
  38. }
  39. baseapp.InitLogger(logCfgFile)
  40. baseapp.Logger.Infof("App Version: %s, Build Time: %s", Version, BuildTime)
  41. p.core_server, err = jsonrpc2.NewRPCServer(p.name, baseapp.Logger)
  42. if err != nil {
  43. return err
  44. }
  45. methods := make(jsonrpc2.MethodMap)
  46. //////////////////////////////////////////////////////////
  47. _getBuildVer := servicelib.MakeGetBuildVer(
  48. Version, BuildTime)
  49. methods["basic.getBuildVer"] = _getBuildVer // 获取软件版本
  50. _getLogLevel := servicelib.GetLogLevel
  51. methods["basic.getLogLevel"] = _getLogLevel // 获取日志级别
  52. _setLogLevel := servicelib.SetLogLevel
  53. methods["basic.setLogLevel"] = _setLogLevel // 设置日志级别
  54. _saveLogConf := servicelib.SaveLogConf
  55. methods["basic.saveLogConf"] = _saveLogConf // 保存日志设置
  56. //////////////////////////////////////////////////////////
  57. methods["core.getTimeSyncStatus"] = p.getTimeSyncStatus
  58. err = p.core_server.RegisterMethods(methods)
  59. if err != nil {
  60. return err
  61. }
  62. mux := http.NewServeMux()
  63. mux.Handle("/rpc", p.core_server)
  64. p.http_server = &http.Server{
  65. Addr: listenAddr,
  66. Handler: mux,
  67. }
  68. p.stopTimeSync = make(chan struct{})
  69. p.syncSource.Store("")
  70. go p.run()
  71. return nil
  72. }
  73. // Do work here
  74. func (p *program) run() {
  75. go p.maintainSystemTime()
  76. baseapp.Logger.Infof(
  77. "[%s] Http server starting on %s...",
  78. p.name,
  79. p.http_server.Addr,
  80. )
  81. err := p.http_server.ListenAndServe() // 同步阻塞
  82. if err != nil && !errors.Is(err, http.ErrServerClosed) {
  83. baseapp.Logger.Errorf("[%s] Start http server error: %v!!", p.name, err)
  84. return
  85. }
  86. }
  87. // Stop should not block. Return with a few seconds.
  88. func (p *program) Stop(s service.Service) error {
  89. if p.stopTimeSync != nil {
  90. close(p.stopTimeSync)
  91. }
  92. if p.core_server != nil {
  93. p.core_server.Stop()
  94. }
  95. if p.http_server != nil {
  96. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  97. defer cancel()
  98. _ = p.http_server.Shutdown(ctx)
  99. }
  100. baseapp.ExitLogger()
  101. return nil
  102. }
  103. func (p *program) syncSysTime() error {
  104. _, _, tcpOK, httpOK, httpTime := netmgrd.CheckNetwork()
  105. if !(tcpOK || httpOK) {
  106. return errors.New("network not available")
  107. }
  108. if !httpTime.IsZero() && netmgrd.SetSystemTime(httpTime) == nil {
  109. p.syncSource.Store("http")
  110. return nil
  111. }
  112. err := netmgrd.SyncNTPTime()
  113. if err == nil {
  114. p.syncSource.Store("ntp")
  115. return nil
  116. } else {
  117. return err
  118. }
  119. }
  120. func (p *program) maintainSystemTime() {
  121. timer := time.NewTimer(0) // ->立即触发
  122. defer timer.Stop()
  123. for {
  124. select {
  125. case <-timer.C:
  126. if err := p.syncSysTime(); err != nil {
  127. p.timeSyncOK.Store(false)
  128. baseapp.Logger.Errorf("[%s] Failed to synchronize system time: %v!!", p.name, err)
  129. timer.Reset(time.Second)
  130. continue
  131. }
  132. p.timeSyncOK.Store(true)
  133. baseapp.Logger.Infof("[%s] ✅ System time synchronized successfully: %s", p.name, time.Now().Format("2006-01-02 15:04:05"))
  134. timer.Reset(time.Hour)
  135. case <-p.stopTimeSync:
  136. return
  137. }
  138. } // for end
  139. }
  140. func main() {
  141. baseapp.SetOptDirs(true, false, false, false)
  142. baseapp.InitPath()
  143. svcFlag := flag.String("service", "", "Control the system service.")
  144. flag.Parse()
  145. svcConfig := &service.Config{
  146. Name: "yfkj-timesyncd",
  147. DisplayName: "yfkj-timesyncd",
  148. Description: "System time synchronization",
  149. Option: map[string]any{
  150. "Restart": "always", // 无条件重启
  151. },
  152. }
  153. servicelib.WriteVersionFile(baseapp.EXEC_DIR, Version) //-> for 升级
  154. prg := &program{
  155. name: "TimeSync",
  156. }
  157. svc, err := service.New(prg, svcConfig)
  158. if err != nil {
  159. fmt.Printf("%s.service creation failed: %v\n",
  160. svcConfig.Name, err)
  161. os.Exit(1)
  162. }
  163. if len(*svcFlag) != 0 {
  164. err := service.Control(svc, *svcFlag)
  165. if err != nil {
  166. fmt.Printf("%v\n Valid actions: %q\n", err, service.ControlAction)
  167. }
  168. os.Exit(0)
  169. }
  170. if servicelib.IsAddrInUse(network, listenAddr) { // 查询端口占用,避免运行多份实例
  171. fmt.Printf(
  172. "%s.service start failed: listen addr %s already in use\n",
  173. svcConfig.Name, listenAddr,
  174. )
  175. os.Exit(1)
  176. }
  177. if err := svc.Run(); err != nil {
  178. fmt.Printf("%s.service run failed: %v\n",
  179. svcConfig.Name, err)
  180. os.Exit(1)
  181. }
  182. }