121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
//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
|
||
}
|