mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-01-18 16:17:26 +01:00
101 lines
2.6 KiB
Go
101 lines
2.6 KiB
Go
//go:build windows && !noserver
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"golang.org/x/sys/windows/svc"
|
|
"heckel.io/ntfy/v2/log"
|
|
"heckel.io/ntfy/v2/server"
|
|
)
|
|
|
|
const serviceName = "ntfy"
|
|
|
|
// sigHandlerConfigReload is a no-op on Windows since SIGHUP is not available.
|
|
// Windows users can restart the service to reload configuration.
|
|
func sigHandlerConfigReload(config string) {
|
|
log.Debug("Config hot-reload via SIGHUP is not supported on Windows")
|
|
}
|
|
|
|
// runAsWindowsService runs the ntfy server as a Windows service
|
|
func runAsWindowsService(conf *server.Config) error {
|
|
return svc.Run(serviceName, &windowsService{conf: conf})
|
|
}
|
|
|
|
// windowsService implements the svc.Handler interface
|
|
type windowsService struct {
|
|
conf *server.Config
|
|
server *server.Server
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// Execute is the main entry point for the Windows service
|
|
func (s *windowsService) Execute(args []string, requests <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
|
|
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
|
|
status <- svc.Status{State: svc.StartPending}
|
|
|
|
// Create and start the server
|
|
var err error
|
|
s.mu.Lock()
|
|
s.server, err = server.New(s.conf)
|
|
s.mu.Unlock()
|
|
if err != nil {
|
|
log.Error("Failed to create server: %s", err.Error())
|
|
return true, 1
|
|
}
|
|
|
|
// Start server in a goroutine
|
|
serverErrChan := make(chan error, 1)
|
|
go func() {
|
|
serverErrChan <- s.server.Run()
|
|
}()
|
|
|
|
status <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
|
log.Info("Windows service started")
|
|
|
|
for {
|
|
select {
|
|
case err := <-serverErrChan:
|
|
if err != nil {
|
|
log.Error("Server error: %s", err.Error())
|
|
return true, 1
|
|
}
|
|
return false, 0
|
|
case req := <-requests:
|
|
switch req.Cmd {
|
|
case svc.Interrogate:
|
|
status <- req.CurrentStatus
|
|
case svc.Stop, svc.Shutdown:
|
|
log.Info("Windows service stopping...")
|
|
status <- svc.Status{State: svc.StopPending}
|
|
s.mu.Lock()
|
|
if s.server != nil {
|
|
s.server.Stop()
|
|
}
|
|
s.mu.Unlock()
|
|
return false, 0
|
|
default:
|
|
log.Warn("Unexpected service control request: %d", req.Cmd)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// maybeRunAsService checks if the process is running as a Windows service,
|
|
// and if so, runs the server as a service. Returns true if it ran as a service.
|
|
func maybeRunAsService(conf *server.Config) (bool, error) {
|
|
isService, err := svc.IsWindowsService()
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to detect Windows service mode: %w", err)
|
|
} else if !isService {
|
|
return false, nil
|
|
}
|
|
log.Info("Running as Windows service")
|
|
if err := runAsWindowsService(conf); err != nil {
|
|
return true, fmt.Errorf("failed to run as Windows service: %w", err)
|
|
}
|
|
return true, nil
|
|
}
|