117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
package glance
|
|
|
|
import (
|
|
"context"
|
|
"html/template"
|
|
"log/slog"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/glanceapp/glance/pkg/sysinfo"
|
|
)
|
|
|
|
var serverStatsWidgetTemplate = mustParseTemplate("server-stats.html", "widget-base.html")
|
|
|
|
type serverStatsWidget struct {
|
|
widgetBase `yaml:",inline"`
|
|
Servers []serverStatsRequest `yaml:"servers"`
|
|
}
|
|
|
|
func (widget *serverStatsWidget) initialize() error {
|
|
widget.withTitle("Server Stats").withCacheDuration(15 * time.Second)
|
|
widget.widgetBase.WIP = true
|
|
|
|
if len(widget.Servers) == 0 {
|
|
widget.Servers = []serverStatsRequest{{Type: "local"}}
|
|
}
|
|
|
|
for i := range widget.Servers {
|
|
widget.Servers[i].URL = strings.TrimRight(widget.Servers[i].URL, "/")
|
|
|
|
if widget.Servers[i].Timeout == 0 {
|
|
widget.Servers[i].Timeout = durationField(3 * time.Second)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (widget *serverStatsWidget) update(context.Context) {
|
|
// Refactor later, most of it may change depending on feedback
|
|
var wg sync.WaitGroup
|
|
|
|
for i := range widget.Servers {
|
|
serv := &widget.Servers[i]
|
|
|
|
if serv.Type == "local" {
|
|
info, errs := sysinfo.Collect(serv.SystemInfoRequest)
|
|
|
|
if len(errs) > 0 {
|
|
for i := range errs {
|
|
slog.Warn("Getting system info: " + errs[i].Error())
|
|
}
|
|
}
|
|
|
|
serv.IsReachable = true
|
|
serv.Info = info
|
|
} else {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
info, err := fetchRemoteServerInfo(serv)
|
|
if err != nil {
|
|
slog.Warn("Getting remote system info: " + err.Error())
|
|
serv.IsReachable = false
|
|
serv.Info = &sysinfo.SystemInfo{
|
|
Hostname: "Unnamed server #" + strconv.Itoa(i+1),
|
|
}
|
|
} else {
|
|
serv.IsReachable = true
|
|
serv.Info = info
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
widget.withError(nil).scheduleNextUpdate()
|
|
}
|
|
|
|
func (widget *serverStatsWidget) Render() template.HTML {
|
|
return widget.renderTemplate(widget, serverStatsWidgetTemplate)
|
|
}
|
|
|
|
type serverStatsRequest struct {
|
|
*sysinfo.SystemInfoRequest `yaml:",inline"`
|
|
Info *sysinfo.SystemInfo `yaml:"-"`
|
|
IsReachable bool `yaml:"-"`
|
|
StatusText string `yaml:"-"`
|
|
Name string `yaml:"name"`
|
|
HideSwap bool `yaml:"hide-swap"`
|
|
Type string `yaml:"type"`
|
|
URL string `yaml:"url"`
|
|
Token string `yaml:"token"`
|
|
Timeout durationField `yaml:"timeout"`
|
|
// Support for other agents
|
|
// Provider string `yaml:"provider"`
|
|
}
|
|
|
|
func fetchRemoteServerInfo(infoReq *serverStatsRequest) (*sysinfo.SystemInfo, error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(infoReq.Timeout))
|
|
defer cancel()
|
|
|
|
request, _ := http.NewRequestWithContext(ctx, "GET", infoReq.URL+"/api/sysinfo/all", nil)
|
|
if infoReq.Token != "" {
|
|
request.Header.Set("Authorization", "Bearer "+infoReq.Token)
|
|
}
|
|
|
|
info, err := decodeJsonFromRequest[*sysinfo.SystemInfo](defaultHTTPClient, request)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return info, nil
|
|
}
|