//go:build windows package winsvc import ( "fmt" "log" "time" "github.com/fleetforge/forge-agent/internal/agent" "github.com/fleetforge/forge-agent/internal/config" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/eventlog" ) const ServiceName = "FleetForgeAgent" const ServiceDisplayName = "Fleet Forge Agent" const ServiceDescription = "Fleet Forge endpoint management agent." type agentService struct { cfg *config.Config } func (s *agentService) Execute(args []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) { status <- svc.Status{State: svc.StartPending, Accepts: svc.AcceptStop | svc.AcceptShutdown} elog, err := eventlog.Open(ServiceName) if err == nil { defer elog.Close() elog.Info(1, "Fleet Forge Agent service starting") } a := agent.New(s.cfg) done := make(chan error, 1) go func() { done <- a.Run() }() status <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown} for { select { case err := <-done: if err != nil { log.Printf("[service] Agent stopped with error: %v", err) if elog != nil { elog.Error(1, fmt.Sprintf("Agent stopped: %v", err)) } } return false, 0 case c := <-r: switch c.Cmd { case svc.Stop, svc.Shutdown: log.Println("[service] Stop/Shutdown received") status <- svc.Status{State: svc.StopPending} return false, 0 case svc.Interrogate: status <- c.CurrentStatus } case <-time.After(5 * time.Second): } } } func RunAsService() error { cfg, err := config.Load() if err != nil { return fmt.Errorf("failed to load config: %w", err) } svcInst := &agentService{cfg: cfg} return svc.Run(ServiceName, svcInst) }