feat: initial commit
This commit is contained in:
1 parent
353f62e257
commit
c6852c6f1b
62 files changed
+5911
-2
No files matched your search
@@ -0,0 +1,76 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/x-grk/longpolling-remote-access/internal/proto"
|
||||
)
|
||||
|
||||
// doUpdate downloads the latest agent binary for this platform, atomically
|
||||
// replaces the running executable, and schedules a service restart. It never
|
||||
// uninstalls — only updates.
|
||||
func (a *Agent) doUpdate() proto.TaskResult {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return proto.TaskResult{Error: "не удалось определить путь бинарника: " + err.Error()}
|
||||
}
|
||||
exe, _ = filepath.EvalSymlinks(exe)
|
||||
|
||||
url := fmt.Sprintf("%s/download/agent-%s-%s", a.cfg.Host, runtime.GOOS, runtime.GOARCH)
|
||||
req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
|
||||
resp, err := a.http.Do(req)
|
||||
if err != nil {
|
||||
return proto.TaskResult{Error: "скачивание: " + err.Error()}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return proto.TaskResult{Error: "скачивание: сервер вернул " + resp.Status}
|
||||
}
|
||||
|
||||
tmp := exe + ".new"
|
||||
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o755)
|
||||
if err != nil {
|
||||
return proto.TaskResult{Error: "создание файла: " + err.Error()}
|
||||
}
|
||||
if _, err := io.Copy(f, resp.Body); err != nil {
|
||||
f.Close()
|
||||
os.Remove(tmp)
|
||||
return proto.TaskResult{Error: "запись: " + err.Error()}
|
||||
}
|
||||
f.Close()
|
||||
|
||||
// Atomic replace: renaming over a running executable is allowed on Linux;
|
||||
// the live process keeps the old inode until it restarts.
|
||||
if err := os.Rename(tmp, exe); err != nil {
|
||||
os.Remove(tmp)
|
||||
return proto.TaskResult{Error: "замена бинарника: " + err.Error()}
|
||||
}
|
||||
|
||||
// Restart shortly, after the result has been reported.
|
||||
go func() {
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
restartSelf()
|
||||
}()
|
||||
|
||||
data, _ := json.Marshal(map[string]string{"status": "обновлено, перезапуск"})
|
||||
return proto.TaskResult{OK: true, Data: data}
|
||||
}
|
||||
|
||||
// restartSelf restarts the agent so the new binary takes effect.
|
||||
func restartSelf() {
|
||||
if path, err := exec.LookPath("systemctl"); err == nil {
|
||||
_ = exec.Command(path, "restart", "lpagent").Start()
|
||||
return
|
||||
}
|
||||
// No systemd (e.g. launchd/manual run): exit so the supervisor restarts us.
|
||||
os.Exit(0)
|
||||
}
|
||||
Reference in new issue
Block a user