zlh-agent/internal/minecraft/readiness.go
2026-03-07 20:59:27 +00:00

86 lines
2.1 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 := []int{ProtocolForVersion(cfg.Version), 767, 765, 763, 762, 754}
protocols = dedupeInts(protocols)
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.Split(string(b), "\n")
for _, l := range lines {
if strings.HasPrefix(l, "server-port=") {
if p, err := strconv.Atoi(strings.TrimPrefix(l, "server-port=")); 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 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
}