Files
past-go/past-go/cmd/server/service_windows.go
T
2026-10-07 09:28:43 +08:00

121 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build windows
package main
import (
"fmt"
"os"
"path/filepath"
"time"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/mgr"
)
const svcName = "past-server"
// runAsServiceIfNeeded 在被 Windows 服务管理器启动时接管生命周期;返回 true 表示已作为服务运行完毕。
func runAsServiceIfNeeded(run func(stop <-chan struct{})) bool {
isSvc, err := svc.IsWindowsService()
if err != nil || !isSvc {
return false
}
_ = svc.Run(svcName, &svcHandler{run: run})
return true
}
type svcHandler struct{ run func(stop <-chan struct{}) }
func (h *svcHandler) Execute(_ []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (bool, uint32) {
s <- svc.Status{State: svc.StartPending}
stop := make(chan struct{})
done := make(chan struct{})
go func() { h.run(stop); close(done) }()
s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}
for {
select {
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
s <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
s <- svc.Status{State: svc.StopPending}
close(stop)
select {
case <-done:
case <-time.After(15 * time.Second):
}
return false, 0
}
case <-done:
return false, 0
}
}
}
// serviceControl 处理 -service install|uninstall|start|stop(需要管理员权限)
func serviceControl(cmd, cfgPath string) error {
m, err := mgr.Connect()
if err != nil {
return fmt.Errorf("连接服务管理器失败(请用管理员身份运行): %w", err)
}
defer m.Disconnect()
switch cmd {
case "install":
exe, err := os.Executable()
if err != nil {
return err
}
abs, _ := filepath.Abs(cfgPath)
if s, err := m.OpenService(svcName); err == nil {
s.Close()
return fmt.Errorf("服务 %s 已存在(先执行 -service uninstall)", svcName)
}
s, err := m.CreateService(svcName, exe, mgr.Config{
DisplayName: "我们past Go 服务 (past-server)",
Description: "past.sundynix.cn 后端 API 与管理后台",
StartType: mgr.StartAutomatic,
}, "-config", abs)
if err != nil {
return err
}
defer s.Close()
// 异常退出自动重启
_ = s.SetRecoveryActions([]mgr.RecoveryAction{
{Type: mgr.ServiceRestart, Delay: 3 * time.Second},
{Type: mgr.ServiceRestart, Delay: 3 * time.Second},
{Type: mgr.ServiceRestart, Delay: 10 * time.Second},
}, 86400)
if err := s.Start(); err != nil {
return fmt.Errorf("已安装但启动失败: %w", err)
}
fmt.Println("服务已安装并启动:", svcName, "配置:", abs)
case "uninstall":
s, err := m.OpenService(svcName)
if err != nil {
return fmt.Errorf("服务不存在: %w", err)
}
defer s.Close()
_, _ = s.Control(svc.Stop)
time.Sleep(2 * time.Second)
if err := s.Delete(); err != nil {
return err
}
fmt.Println("服务已卸载:", svcName)
case "start", "stop":
s, err := m.OpenService(svcName)
if err != nil {
return fmt.Errorf("服务不存在: %w", err)
}
defer s.Close()
if cmd == "start" {
return s.Start()
}
_, err = s.Control(svc.Stop)
return err
default:
return fmt.Errorf("未知 -service 命令: %s(install|uninstall|start|stop)", cmd)
}
return nil
}