Add restart endpoint

Former-commit-id: 734542c3ed
This commit is contained in:
Owen
2026-05-27 16:33:16 -07:00
parent e223a35a62
commit 7ff97eda51
3 changed files with 66 additions and 7 deletions

22
main.go
View File

@@ -1032,6 +1032,19 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey(
logger.Info("Tunnel destroyed, ready for reconnection")
})
client.RegisterHandler("newt/wg/restart", func(msg websocket.WSMessage) {
closeWgTunnel()
closeClients()
if healthMonitor != nil {
healthMonitor.Stop()
}
client.Close()
if err := reexec(); err != nil {
logger.Error("Failed to restart: %v", err)
os.Exit(1)
}
})
client.RegisterHandler("newt/wg/terminate", func(msg websocket.WSMessage) {
logger.Info("Received termination message")
if wgData.PublicKey != "" {
@@ -1968,13 +1981,8 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey(
healthMonitor.Stop()
}
client.Close()
exe, exeErr := os.Executable()
if exeErr != nil {
logger.Error("Failed to get executable path for restart: %v", exeErr)
os.Exit(0)
}
if err := syscall.Exec(exe, os.Args, os.Environ()); err != nil {
logger.Error("Failed to re-exec for restart: %v", err)
if err := reexec(); err != nil {
logger.Error("Failed to restart: %v", err)
os.Exit(1)
}
}

21
reexec_unix.go Normal file
View File

@@ -0,0 +1,21 @@
//go:build !windows
package main
import (
"fmt"
"os"
"syscall"
)
// reexec replaces the current process image with a fresh copy of itself,
// preserving all arguments and environment variables. On success it never
// returns (execve replaces the process in-place). On failure it returns an
// error describing why the exec could not be performed.
func reexec() error {
exe, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
return syscall.Exec(exe, os.Args, os.Environ())
}

30
reexec_windows.go Normal file
View File

@@ -0,0 +1,30 @@
//go:build windows
package main
import (
"fmt"
"os"
"os/exec"
)
// reexec spawns a new copy of the current process with the same arguments and
// environment, then exits the current process. On Windows, execve is not
// available, so we start a child process and exit. On success it never returns
// (os.Exit terminates the current process). On failure it returns an error.
func reexec() error {
exe, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
cmd := exec.Command(exe, os.Args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Env = os.Environ()
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to start new process: %w", err)
}
os.Exit(0)
return nil // unreachable
}