zlh-agent/internal/minecraft/readiness.go
2026-04-19 21:51:00 +00:00

89 lines
2.2 KiB
Go

package minecraft
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"zlh-agent/internal/provision"
"zlh-agent/internal/state"
)
func WaitUntilReady(cfg state.Config, timeout, interval time.Duration) error {
start := time.Now()
ports := CandidatePorts(cfg)
protocols := CandidateProtocols(cfg.Version)
attempt := 0
deadline := start.Add(timeout)
var lastErr error
for {
attempt++
for _, port := range ports {
for _, protocol := range protocols {
if _, err := QueryStatus("127.0.0.1", port, protocol); err == nil {
elapsed := time.Since(start).Milliseconds()
log.Printf("[lifecycle] vmid=%d phase=probe result=ready attempt=%d elapsed_ms=%d port=%d protocol=%d", cfg.VMID, attempt, elapsed, port, protocol)
return nil
} else {
lastErr = err
}
}
}
elapsed := time.Since(start).Milliseconds()
log.Printf("[lifecycle] vmid=%d phase=probe result=not_ready attempt=%d elapsed_ms=%d err=%v", cfg.VMID, attempt, elapsed, lastErr)
if time.Now().After(deadline) {
if lastErr != nil {
return fmt.Errorf("minecraft readiness probe timeout after %s: %w", timeout, lastErr)
}
return fmt.Errorf("minecraft readiness probe timeout after %s", timeout)
}
time.Sleep(interval)
}
}
func CandidatePorts(cfg state.Config) []int {
ports := make([]int, 0, 3)
propsPath := filepath.Join(provision.ServerDir(cfg), "server.properties")
if b, err := os.ReadFile(propsPath); err == nil {
lines := strings.SplitSeq(string(b), "\n")
for l := range lines {
if after, ok := strings.CutPrefix(l, "server-port="); ok {
if p, err := strconv.Atoi(after); err == nil && p > 0 {
ports = append(ports, p)
}
break
}
}
}
if len(cfg.Ports) > 0 && cfg.Ports[0] > 0 {
ports = append(ports, cfg.Ports[0])
}
ports = append(ports, 25565)
return dedupeInts(ports)
}
func CandidateProtocols(version string) []int {
return dedupeInts([]int{ProtocolForVersion(version), 767, 765, 763, 762, 754})
}
func dedupeInts(in []int) []int {
seen := make(map[int]struct{}, len(in))
out := make([]int, 0, len(in))
for _, v := range in {
if _, ok := seen[v]; ok {
continue
}
seen[v] = struct{}{}
out = append(out, v)
}
return out
}