servicehost_windows.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. //go:build windows
  2. // +build windows
  3. package servicehost
  4. import (
  5. log "github.com/sirupsen/logrus"
  6. "fmt"
  7. "golang.org/x/sys/windows/svc"
  8. "golang.org/x/sys/windows/svc/debug"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "time"
  13. )
  14. type otWindowsService struct{}
  15. //gocyclo:ignore
  16. func (m *otWindowsService) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (svcSpecificExitCode bool, exitCode uint32) {
  17. const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
  18. tick := time.Tick(1 * time.Minute)
  19. status <- svc.Status{State: svc.StartPending}
  20. status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
  21. log.Info("Servicehost started")
  22. for {
  23. select {
  24. case <-tick:
  25. log.Debug("servicehost Tick")
  26. case c := <-r:
  27. switch c.Cmd {
  28. case svc.Interrogate:
  29. status <- c.CurrentStatus
  30. case svc.Stop, svc.Shutdown:
  31. log.Info("Stopping service")
  32. return false, 0
  33. case svc.Pause:
  34. status <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
  35. case svc.Continue:
  36. status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
  37. default:
  38. log.Infof("Unexpected control request: %d", c.Cmd)
  39. }
  40. }
  41. }
  42. }
  43. func setupLogging(serviceLogDirectory string) {
  44. logsDir, err := configuredServiceLogDirectory(serviceLogDirectory)
  45. if err != nil {
  46. log.Warnf("Failed to resolve serviceLogs.directory relative to executable: %v", err)
  47. }
  48. if logsDir == "" {
  49. logsDir = path.Join(GetConfigFilePath(), "logs")
  50. }
  51. openServiceLogFile(logsDir)
  52. }
  53. func openServiceLogFile(logsDir string) {
  54. if err := os.MkdirAll(logsDir, 0755); err != nil {
  55. log.Errorf("Failed to create logs directory %v: %v", logsDir, err)
  56. return
  57. }
  58. timestamp := time.Now().Format("2006-01-02_15-04-05")
  59. filename := path.Join(logsDir, fmt.Sprintf("OliveTin-service-%v.log", timestamp))
  60. log.Infof("Setting up logging to file: %v", filename)
  61. f, err := os.Create(filename)
  62. if err != nil {
  63. log.Errorf("Failed to open log file: %v", err)
  64. return
  65. }
  66. log.Infof("Switching to log file: %v", f.Name())
  67. log.SetOutput(f)
  68. log.Infof("Opened log file: %v", f.Name())
  69. }
  70. func GetConfigFilePath() string {
  71. programDataDir := path.Join(os.Getenv("ProgramData"), "OliveTin")
  72. _, err := os.Stat(programDataDir)
  73. if os.IsNotExist(err) {
  74. os.MkdirAll(programDataDir, 0755)
  75. }
  76. return programDataDir
  77. }
  78. func cdToExecutableDir() {
  79. ex, err := os.Executable()
  80. if err != nil {
  81. panic(fmt.Sprintf("Failed to get executable path: %s", err))
  82. }
  83. exPath := filepath.Dir(ex)
  84. err = os.Chdir(exPath)
  85. if err != nil {
  86. panic(fmt.Sprintf("Failed to change directory to executable path: %s", err))
  87. }
  88. }
  89. //gocyclo:ignore
  90. func startServiceHandler(mode string) {
  91. cdToExecutableDir()
  92. const serviceName = "OliveTin"
  93. var err error
  94. switch mode {
  95. case "winsvc-debug":
  96. log.Infof("Running Windows service in debug mode")
  97. err = debug.Run(serviceName, &otWindowsService{})
  98. case "winsvc-standard":
  99. log.Infof("Running Windows service in standard mode")
  100. err = svc.Run(serviceName, &otWindowsService{})
  101. case "":
  102. return
  103. default:
  104. log.Fatalf("Unknown servicehost service mode: %s", mode)
  105. }
  106. if err != nil {
  107. log.Fatalf("Failed to run service: %v", err)
  108. }
  109. log.Infof("Servicehost handler completed")
  110. os.Exit(0)
  111. }
  112. func Start(mode string, serviceLogDirectory string) {
  113. setupLogging(serviceLogDirectory)
  114. go startServiceHandler(mode)
  115. }