Added Technitium as a valid service for dns-stats widget
This commit is contained in:
parent
d8a4d39849
commit
0c8358beaa
1 changed files with 149 additions and 3 deletions
|
@ -48,7 +48,11 @@ func (widget *dnsStatsWidget) initialize() error {
|
|||
withTitleURL(string(widget.URL)).
|
||||
withCacheDuration(10 * time.Minute)
|
||||
|
||||
if widget.Service != "adguard" && widget.Service != "pihole" {
|
||||
switch widget.Service {
|
||||
case "adguard":
|
||||
case "pihole":
|
||||
case "technitium":
|
||||
default:
|
||||
return errors.New("service must be either 'adguard' or 'pihole'")
|
||||
}
|
||||
|
||||
|
@ -59,10 +63,13 @@ func (widget *dnsStatsWidget) update(ctx context.Context) {
|
|||
var stats *dnsStats
|
||||
var err error
|
||||
|
||||
if widget.Service == "adguard" {
|
||||
switch widget.Service {
|
||||
case "adguard":
|
||||
stats, err = fetchAdguardStats(widget.URL, widget.AllowInsecure, widget.Username, widget.Password, widget.HideGraph)
|
||||
} else {
|
||||
case "pihole":
|
||||
stats, err = fetchPiholeStats(widget.URL, widget.AllowInsecure, widget.Token, widget.HideGraph)
|
||||
case "technitium":
|
||||
stats, err = fetchTechnitiumStats(widget.URL, widget.AllowInsecure, widget.Token, widget.HideGraph)
|
||||
}
|
||||
|
||||
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||
|
@ -379,3 +386,142 @@ func fetchPiholeStats(instanceURL string, allowInsecure bool, token string, noGr
|
|||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
type technitiumStatsResponse struct {
|
||||
Response struct {
|
||||
Stats struct {
|
||||
TotalQueries int `json:"totalQueries"`
|
||||
BlockedQueries int `json:"totalBlocked"`
|
||||
} `json:"stats"`
|
||||
MainChartData struct {
|
||||
Datasets []struct {
|
||||
Label string `json:"label"`
|
||||
Data []int `json:"data"`
|
||||
} `json:"datasets"`
|
||||
} `json:"mainChartData"`
|
||||
TopBlockedDomains []struct {
|
||||
Domain string `json:"name"`
|
||||
Count int `json:"hits"`
|
||||
}
|
||||
} `json:"response"`
|
||||
}
|
||||
|
||||
func fetchTechnitiumStats(instanceUrl string, allowInsecure bool, token string, noGraph bool) (*dnsStats, error) {
|
||||
|
||||
if token == "" {
|
||||
return nil, errors.New("missing API token")
|
||||
}
|
||||
|
||||
requestURL := strings.TrimRight(instanceUrl, "/") + "/api/dashboard/stats/get?token=" + token + "&type=LastDay"
|
||||
|
||||
request, err := http.NewRequest("GET", requestURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var client requestDoer
|
||||
if !allowInsecure {
|
||||
client = defaultHTTPClient
|
||||
} else {
|
||||
client = defaultInsecureHTTPClient
|
||||
}
|
||||
|
||||
responseJson, err := decodeJsonFromRequest[technitiumStatsResponse](client, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var topBlockedDomainsCount = min(len(responseJson.Response.TopBlockedDomains), 5)
|
||||
|
||||
stats := &dnsStats{
|
||||
TotalQueries: responseJson.Response.Stats.TotalQueries,
|
||||
BlockedQueries: responseJson.Response.Stats.BlockedQueries,
|
||||
TopBlockedDomains: make([]dnsStatsBlockedDomain, 0, topBlockedDomainsCount),
|
||||
}
|
||||
|
||||
if stats.TotalQueries <= 0 {
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
stats.BlockedPercent = int(float64(responseJson.Response.Stats.BlockedQueries) / float64(responseJson.Response.Stats.TotalQueries) * 100)
|
||||
|
||||
for i := 0; i < topBlockedDomainsCount; i++ {
|
||||
domain := responseJson.Response.TopBlockedDomains[i]
|
||||
firstDomain := domain.Domain
|
||||
|
||||
if firstDomain == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
stats.TopBlockedDomains = append(stats.TopBlockedDomains, dnsStatsBlockedDomain{
|
||||
Domain: firstDomain,
|
||||
})
|
||||
|
||||
if stats.BlockedQueries > 0 {
|
||||
stats.TopBlockedDomains[i].PercentBlocked = int(float64(domain.Count) / float64(responseJson.Response.Stats.BlockedQueries) * 100)
|
||||
}
|
||||
}
|
||||
|
||||
if noGraph {
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
var queriesSeries, blockedSeries []int
|
||||
|
||||
for _, label := range responseJson.Response.MainChartData.Datasets {
|
||||
switch label.Label {
|
||||
case "Total":
|
||||
queriesSeries = label.Data
|
||||
case "Blocked":
|
||||
blockedSeries = label.Data
|
||||
}
|
||||
}
|
||||
|
||||
const bars = 8
|
||||
const hoursSpan = 24
|
||||
const hoursPerBar int = hoursSpan / bars
|
||||
|
||||
if len(queriesSeries) > hoursSpan {
|
||||
queriesSeries = queriesSeries[len(queriesSeries)-hoursSpan:]
|
||||
} else if len(queriesSeries) < hoursSpan {
|
||||
queriesSeries = append(make([]int, hoursSpan-len(queriesSeries)), queriesSeries...)
|
||||
}
|
||||
|
||||
if len(blockedSeries) > hoursSpan {
|
||||
blockedSeries = blockedSeries[len(blockedSeries)-hoursSpan:]
|
||||
} else if len(blockedSeries) < hoursSpan {
|
||||
blockedSeries = append(make([]int, hoursSpan-len(blockedSeries)), blockedSeries...)
|
||||
}
|
||||
|
||||
maxQueriesInSeries := 0
|
||||
|
||||
for i := 0; i < bars; i++ {
|
||||
queries := 0
|
||||
blocked := 0
|
||||
|
||||
for j := 0; j < hoursPerBar; j++ {
|
||||
queries += queriesSeries[i*hoursPerBar+j]
|
||||
blocked += blockedSeries[i*hoursPerBar+j]
|
||||
}
|
||||
|
||||
stats.Series[i] = dnsStatsSeries{
|
||||
Queries: queries,
|
||||
Blocked: blocked,
|
||||
}
|
||||
|
||||
if queries > 0 {
|
||||
stats.Series[i].PercentBlocked = int(float64(blocked) / float64(queries) * 100)
|
||||
}
|
||||
|
||||
if queries > maxQueriesInSeries {
|
||||
maxQueriesInSeries = queries
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < bars; i++ {
|
||||
stats.Series[i].PercentTotal = int(float64(stats.Series[i].Queries) / float64(maxQueriesInSeries) * 100)
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue