servicehost_windows.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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() {
  44. logsDir := path.Join(GetConfigFilePath(), "logs")
  45. os.MkdirAll(logsDir, 0755)
  46. timestamp := time.Now().Format("2006-01-02_15-04-05")
  47. filename := path.Join(logsDir, fmt.Sprintf("OliveTin-service-%v.log", timestamp))
  48. log.Infof("Setting up logging to file: %v", filename)
  49. f, err := os.Create(filename)
  50. if err != nil {
  51. log.Infof("Failed to open log file: %v", err)
  52. } else {
  53. log.Infof("Switching to log file: %v", f.Name())
  54. log.SetOutput(f)
  55. log.Infof("Opened log file: %v", f.Name())
  56. }
  57. }
  58. func GetConfigFilePath() string {
  59. programDataDir := path.Join(os.Getenv("ProgramData"), "OliveTin")
  60. _, err := os.Stat(programDataDir)
  61. if os.IsNotExist(err) {
  62. os.MkdirAll(programDataDir, 0755)
  63. }
  64. return programDataDir
  65. }
  66. func cdToExecutableDir() {
  67. ex, err := os.Executable()
  68. if err != nil {
  69. panic(fmt.Sprintf("Failed to get executable path: %s", err))
  70. }
  71. exPath := filepath.Dir(ex)
  72. err = os.Chdir(exPath)
  73. if err != nil {
  74. panic(fmt.Sprintf("Failed to change directory to executable path: %s", err))
  75. }
  76. }
  77. //gocyclo:ignore
  78. func startServiceHandler(mode string) {
  79. cdToExecutableDir()
  80. const serviceName = "OliveTin"
  81. var err error
  82. switch mode {
  83. case "winsvc-debug":
  84. log.Infof("Running Windows service in debug mode")
  85. err = debug.Run(serviceName, &otWindowsService{})
  86. case "winsvc-standard":
  87. log.Infof("Running Windows service in standard mode")
  88. err = svc.Run(serviceName, &otWindowsService{})
  89. case "":
  90. return
  91. default:
  92. log.Fatalf("Unknown servicehost service mode: %s", mode)
  93. }
  94. if err != nil {
  95. log.Fatalf("Failed to run service: %v", err)
  96. }
  97. log.Infof("Servicehost handler completed")
  98. os.Exit(0)
  99. }
  100. func Start(mode string) {
  101. setupLogging()
  102. go startServiceHandler(mode)
  103. }