96 lines
2.4 KiB
Go
96 lines
2.4 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/x-grk/longpolling-remote-access/internal/proto"
|
|
)
|
|
|
|
// Auto-update, the agent's part: the server tells (with every poll, on its
|
|
// config and on the WebSocket) its own version and how often to compare -
|
|
// in minutes, 0 for never. When the server's version is newer, the agent
|
|
// takes the new one from it, as the panel's «Обновить» does.
|
|
|
|
// autoUpdate is what the agent was told, and when it last looked.
|
|
type autoUpdate struct {
|
|
mu sync.Mutex
|
|
minutes int
|
|
serverVer string
|
|
last time.Time
|
|
}
|
|
|
|
func (a *Agent) applyUpdateInfo(minutes int, serverVersion string) {
|
|
a.auto.mu.Lock()
|
|
defer a.auto.mu.Unlock()
|
|
if minutes < 0 {
|
|
minutes = 0
|
|
}
|
|
a.auto.minutes = minutes
|
|
if serverVersion != "" {
|
|
a.auto.serverVer = serverVersion
|
|
}
|
|
}
|
|
|
|
// applyUpdateHeaders takes the settings from the headers of an answer; an
|
|
// answer without them (an older server) changes nothing.
|
|
func (a *Agent) applyUpdateHeaders(h http.Header) {
|
|
v := h.Get(proto.AutoUpdateHeader)
|
|
if v == "" {
|
|
return
|
|
}
|
|
m, err := strconv.Atoi(v)
|
|
if err != nil {
|
|
m = 0
|
|
}
|
|
a.applyUpdateInfo(m, h.Get(proto.ServerVersionHeader))
|
|
}
|
|
|
|
func (a *Agent) updateInfo() (int, string) {
|
|
a.auto.mu.Lock()
|
|
defer a.auto.mu.Unlock()
|
|
return a.auto.minutes, a.auto.serverVer
|
|
}
|
|
|
|
func (a *Agent) autoUpdateOn() bool { m, _ := a.updateInfo(); return m > 0 }
|
|
|
|
// autoUpdateTick: one look at the clock. Out of the interval since the last
|
|
// look, it looks; the server's version newer than its own, it updates.
|
|
// Reports whether it did.
|
|
func (a *Agent) autoUpdateTick(now time.Time, update func() proto.TaskResult) bool {
|
|
a.auto.mu.Lock()
|
|
if a.auto.minutes <= 0 || (!a.auto.last.IsZero() && now.Sub(a.auto.last) < time.Duration(a.auto.minutes)*time.Minute) {
|
|
a.auto.mu.Unlock()
|
|
return false
|
|
}
|
|
a.auto.last = now
|
|
server := a.auto.serverVer
|
|
a.auto.mu.Unlock()
|
|
if !proto.VersionNewer(server, Version) {
|
|
return false
|
|
}
|
|
log.Printf("auto-update: server has %s, this is %s - updating", server, Version)
|
|
if res := update(); !res.OK {
|
|
log.Printf("auto-update: %s", res.Error)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// autoUpdateLoop watches the clock until ctx ends.
|
|
func (a *Agent) autoUpdateLoop(ctx context.Context) {
|
|
t := time.NewTicker(30 * time.Second)
|
|
defer t.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case now := <-t.C:
|
|
a.autoUpdateTick(now, a.doUpdate)
|
|
}
|
|
}
|
|
}
|