121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
package accept
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"git.asio.asia/nixevol/NixMsg/test/harness"
|
|
)
|
|
|
|
// ManagedServer 支持 Kill 后用同一 data_dir 再 Restart(崩溃续传验收)。
|
|
type ManagedServer struct {
|
|
BinPath string
|
|
ConfigPath string
|
|
DataDir string
|
|
Addr string
|
|
AdminPassword string
|
|
HTTPBase string
|
|
AdminHTTPBase string
|
|
|
|
cmd *exec.Cmd
|
|
}
|
|
|
|
// StartManaged 启动随机端口进程。
|
|
func StartManaged() (*ManagedServer, error) {
|
|
bin, err := harness.Binary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dataDir, err := os.MkdirTemp("", "nixmsg-q3-*")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cfgPath := filepath.Join(dataDir, "config.yaml")
|
|
cfg := fmt.Sprintf("listen: %q\ndata_dir: %q\n", "127.0.0.1:0", filepath.ToSlash(dataDir))
|
|
if err = os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil {
|
|
_ = os.RemoveAll(dataDir)
|
|
return nil, err
|
|
}
|
|
|
|
initCmd := exec.Command(bin, "admin", "init")
|
|
initCmd.Env = append(os.Environ(), "NIXMSG_CONFIG="+cfgPath)
|
|
initOut, initErr := initCmd.CombinedOutput()
|
|
if initErr != nil {
|
|
_ = os.RemoveAll(dataDir)
|
|
return nil, fmt.Errorf("admin init: %w\n%s", initErr, initOut)
|
|
}
|
|
password := parsePassword(string(initOut))
|
|
if password == "" {
|
|
_ = os.RemoveAll(dataDir)
|
|
return nil, fmt.Errorf("admin init password not found:\n%s", initOut)
|
|
}
|
|
|
|
s := &ManagedServer{
|
|
BinPath: bin,
|
|
ConfigPath: cfgPath,
|
|
DataDir: dataDir,
|
|
AdminPassword: password,
|
|
}
|
|
if err := s.startServe(); err != nil {
|
|
_ = os.RemoveAll(dataDir)
|
|
return nil, err
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func (s *ManagedServer) startServe() error {
|
|
_ = os.Remove(filepath.Join(s.DataDir, "listen.addr"))
|
|
cmd := exec.Command(s.BinPath, "serve")
|
|
cmd.Env = append(os.Environ(), "NIXMSG_CONFIG="+s.ConfigPath)
|
|
cmd.Stdout = os.Stderr
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
return fmt.Errorf("start serve: %w", err)
|
|
}
|
|
s.cmd = cmd
|
|
addr, err := waitListenAddr(filepath.Join(s.DataDir, "listen.addr"), 20*time.Second)
|
|
if err != nil {
|
|
_ = cmd.Process.Kill()
|
|
_, _ = cmd.Process.Wait()
|
|
return fmt.Errorf("wait listen.addr: %w", err)
|
|
}
|
|
s.Addr = addr
|
|
s.HTTPBase = "http://" + addr
|
|
s.AdminHTTPBase = s.HTTPBase
|
|
return nil
|
|
}
|
|
|
|
// Kill 杀掉进程,保留数据目录。
|
|
func (s *ManagedServer) Kill() error {
|
|
if s == nil || s.cmd == nil || s.cmd.Process == nil {
|
|
return nil
|
|
}
|
|
_ = s.cmd.Process.Kill()
|
|
_, _ = s.cmd.Process.Wait()
|
|
s.cmd = nil
|
|
return nil
|
|
}
|
|
|
|
// Restart 在同一配置与数据目录上重新 serve。
|
|
func (s *ManagedServer) Restart() error {
|
|
if err := s.Kill(); err != nil {
|
|
return err
|
|
}
|
|
return s.startServe()
|
|
}
|
|
|
|
// Cleanup 停进程并删除数据目录。
|
|
func (s *ManagedServer) Cleanup() error {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
_ = s.Kill()
|
|
if s.DataDir != "" {
|
|
return os.RemoveAll(s.DataDir)
|
|
}
|
|
return nil
|
|
}
|