Switch to using custom type for pihole's top blocked domains

This commit is contained in:
Svilen Markov 2024-09-30 00:24:44 +01:00
parent 28167403a4
commit 672547cd07

View File

@ -1,6 +1,7 @@
package feed
import (
"encoding/json"
"errors"
"log/slog"
"net/http"
@ -14,19 +15,28 @@ type piholeStatsResponse struct {
BlockedQueries int `json:"ads_blocked_today"`
BlockedSeries map[int64]int `json:"ads_over_time"`
BlockedPercentage float64 `json:"ads_percentage_today"`
TopBlockedDomains map[string]int `json:"top_ads"`
TopBlockedDomains piholeTopBlockedDomains `json:"top_ads"`
DomainsBlocked int `json:"domains_being_blocked"`
}
// If user has some level of privacy enabled on Pihole, `json:"top_ads"` is an empty array
// Use alternate struct without that field to avoid error when unmarshalling
type piholeStatsResponsePrivate struct {
TotalQueries int `json:"dns_queries_today"`
QueriesSeries map[int64]int `json:"domains_over_time"`
BlockedQueries int `json:"ads_blocked_today"`
BlockedSeries map[int64]int `json:"ads_over_time"`
BlockedPercentage float64 `json:"ads_percentage_today"`
DomainsBlocked int `json:"domains_being_blocked"`
// Use custom unmarshal behavior to avoid not getting the rest of the valid data when unmarshalling
type piholeTopBlockedDomains map[string]int
func (p *piholeTopBlockedDomains) UnmarshalJSON(data []byte) error {
// NOTE: do not change to piholeTopBlockedDomains type here or it will cause a stack overflow
// because of the UnmarshalJSON method getting called recursively
temp := make(map[string]int)
err := json.Unmarshal(data, &temp)
if err != nil {
*p = make(piholeTopBlockedDomains)
} else {
*p = temp
}
return nil
}
func FetchPiholeStats(instanceURL, token string) (*DNSStats, error) {
@ -45,24 +55,10 @@ func FetchPiholeStats(instanceURL, token string) (*DNSStats, error) {
responseJson, err := decodeJsonFromRequest[piholeStatsResponse](defaultClient, request)
if err != nil {
// Refer to piholeStatsResponsePrivate above
responseJsonPriv, err :=
decodeJsonFromRequest[piholeStatsResponsePrivate](defaultClient, request)
if err != nil {
return nil, err
}
// Copy the results back to responseJson, leaving the TopBlockedDomains field empty
responseJson.TotalQueries = responseJsonPriv.TotalQueries
responseJson.QueriesSeries = responseJsonPriv.QueriesSeries
responseJson.BlockedQueries = responseJsonPriv.BlockedQueries
responseJson.BlockedSeries = responseJsonPriv.BlockedSeries
responseJson.BlockedPercentage = responseJsonPriv.BlockedPercentage
responseJson.TopBlockedDomains = make(map[string]int)
responseJson.DomainsBlocked = responseJsonPriv.DomainsBlocked
}
stats := &DNSStats{
TotalQueries: responseJson.TotalQueries,
BlockedQueries: responseJson.BlockedQueries,