Scert/backend/internal/servicehost/windows.go

85 lines
1.8 KiB
Go

//go:build windows
package servicehost
import (
"context"
"os/exec"
"strconv"
)
func Install(ctx context.Context, options Options) error {
o, err := options.normalized()
if err != nil {
return err
}
binPath := strconv.Quote(o.Executable) + " --config " + strconv.Quote(o.ConfigPath) + " serve"
if err := runSC(ctx, "create", o.Name, "binPath=", binPath, "start=", "auto", "DisplayName=", o.DisplayName); err != nil {
return commandError("安装", err)
}
if err := runSC(ctx, "description", o.Name, o.Description); err != nil {
return commandError("写入描述", err)
}
return nil
}
func Uninstall(ctx context.Context, name string) error {
name, err := normalizeName(name)
if err != nil {
return err
}
if err := runSC(ctx, "stop", name); err != nil {
// 服务未运行时允许继续删除。
_ = err
}
if err := runSC(ctx, "delete", name); err != nil {
return commandError("卸载", err)
}
return nil
}
func Start(ctx context.Context, name string) error {
name, err := normalizeName(name)
if err != nil {
return err
}
if err := runSC(ctx, "start", name); err != nil {
return commandError("启动", err)
}
return nil
}
func Stop(ctx context.Context, name string) error {
name, err := normalizeName(name)
if err != nil {
return err
}
if err := runSC(ctx, "stop", name); err != nil {
return commandError("停止", err)
}
return nil
}
func runSC(ctx context.Context, args ...string) error {
command := exec.CommandContext(ctx, "sc.exe", args...)
output, err := command.CombinedOutput()
if err != nil {
return &commandFailure{output: string(output), err: err}
}
return nil
}
type commandFailure struct {
output string
err error
}
func (e *commandFailure) Error() string {
if e.err != nil {
return e.output + ": " + e.err.Error()
}
return e.output
}
func (e *commandFailure) Unwrap() error { return e.err }