mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-10-28 07:41:27 +00:00
Two tracks from the Beszel/Domain-Locker merge plan in ROADMAP.md: - Importers: POST /api/import/external sniffs Homepage services.yml, Homarr JSON, and Dashy conf.yml into sections/items; SettingsDialog import now accepts all four formats. - Monitors (M1): monitors + heartbeats schema, pure checkers for http/tcp/ping/dns/keyword/json-query/push, scheduler on app ctx, CRUD + check-now + push ingest API, /monitors + /monitors/:id pages (wouter), monitor board widget, ServiceDialog monitor opt-in. Authored By: TDvorak <[email protected]> Generated with Devin (https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
76 lines
2.2 KiB
Go
76 lines
2.2 KiB
Go
package widget
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// AdGuard Home REST API: GET /control/stats with HTTP basic auth.
|
|
type adguard struct{}
|
|
|
|
func init() { Register(adguard{}) }
|
|
|
|
func (adguard) Meta() Type {
|
|
return Type{
|
|
Type: "adguard",
|
|
Name: "AdGuard Home",
|
|
Description: "Queries and block rate",
|
|
Fields: []Field{
|
|
{Key: "endpoint", Label: "Endpoint", Placeholder: "http://adguard.local", Required: true},
|
|
{Key: "user", Label: "Username", Required: true},
|
|
{Key: "pass", Label: "Password", Secret: true, Required: true},
|
|
},
|
|
}
|
|
}
|
|
|
|
type adguardData struct {
|
|
QueriesToday int `json:"queriesToday"`
|
|
BlockedToday int `json:"blockedToday"`
|
|
BlockedPercent float64 `json:"blockedPercent"`
|
|
AvgProcessMs float64 `json:"avgProcessMs"`
|
|
}
|
|
|
|
func (adguard) Fetch(ctx context.Context, cfg json.RawMessage) (any, error) {
|
|
endpoint := strings.TrimRight(cfgStr(cfg, "endpoint"), "/")
|
|
user, pass := cfgStr(cfg, "user"), cfgStr(cfg, "pass")
|
|
if endpoint == "" || user == "" {
|
|
return nil, fmt.Errorf("endpoint and user required")
|
|
}
|
|
var raw struct {
|
|
NumDNSQueries int `json:"num_dns_queries"`
|
|
NumBlockedFiltering int `json:"num_blocked_filtering"`
|
|
AvgProcessingTimeSec float64 `json:"avg_processing_time_sec"`
|
|
}
|
|
// AdGuard uses basic auth; encode via the URL userinfo so the helper
|
|
// stays header-free — and the secret never touches a log line.
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint+"/control/stats", nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.SetBasicAuth(user, pass)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("upstream unreachable")
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("upstream returned %d", resp.StatusCode)
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(&raw); err != nil {
|
|
return nil, err
|
|
}
|
|
var pct float64
|
|
if raw.NumDNSQueries > 0 {
|
|
pct = float64(raw.NumBlockedFiltering) / float64(raw.NumDNSQueries) * 100
|
|
}
|
|
return adguardData{
|
|
QueriesToday: raw.NumDNSQueries,
|
|
BlockedToday: raw.NumBlockedFiltering,
|
|
BlockedPercent: pct,
|
|
AvgProcessMs: raw.AvgProcessingTimeSec * 1000,
|
|
}, nil
|
|
}
|