Files
elmprodvpn/selective-vpn-api/app/watchers_state_files.go

110 lines
2.2 KiB
Go

package app
import (
"context"
"crypto/sha256"
"encoding/json"
"os"
"time"
)
// ---------------------------------------------------------------------
// status file watcher
// ---------------------------------------------------------------------
func watchStatusFile(ctx context.Context, every time.Duration) {
var last [32]byte
have := false
for {
select {
case <-ctx.Done():
return
case <-time.After(every):
}
data, err := os.ReadFile(statusFilePath)
if err != nil {
continue
}
h := sha256.Sum256(data)
if have && h == last {
continue
}
last = h
have = true
var st Status
if err := json.Unmarshal(data, &st); err != nil {
events.push("status_error", map[string]any{"error": err.Error()})
continue
}
events.push("status_changed", st)
}
}
// ---------------------------------------------------------------------
// login file watcher
// ---------------------------------------------------------------------
func watchLoginFile(ctx context.Context, every time.Duration) {
var last [32]byte
have := false
for {
select {
case <-ctx.Done():
return
case <-time.After(every):
}
data, err := os.ReadFile(loginStatePath)
if err != nil {
continue
}
h := sha256.Sum256(data)
if have && h == last {
continue
}
last = h
have = true
var st VPNLoginState
if err := json.Unmarshal(data, &st); err != nil {
events.push("login_state_error", map[string]any{"error": err.Error()})
continue
}
events.push("login_state_changed", st)
}
}
// ---------------------------------------------------------------------
// generic file watcher
// ---------------------------------------------------------------------
func watchFileChange(ctx context.Context, path string, kind string, mode string, every time.Duration) {
var lastMod time.Time
var lastSize int64 = -1
for {
select {
case <-ctx.Done():
return
case <-time.After(every):
}
info, err := os.Stat(path)
if err != nil {
continue
}
if info.ModTime() == lastMod && info.Size() == lastSize {
continue
}
lastMod = info.ModTime()
lastSize = info.Size()
events.push(kind, map[string]any{
"path": path,
"mode": mode,
"size": info.Size(),
"mtime": info.ModTime().UTC().Format(time.RFC3339Nano),
})
}
}