quality / commitlint (push) Skipped
quality / changes (push) Successful in 9s
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 46s
quality / web (push) Successful in 1m16s
quality / go (push) Successful in 2m42s
quality / bird2 (push) Successful in 16s
CD / quality (push) Successful in 5m19s
CD / publish (push) Successful in 7m19s
- Deleted unused components: `DashboardActivityTimeline`, `DashboardFramePanel`, `DashboardModulesGrid`, `DashboardRecentJobsGrid`, and `DashboardRecentRevisionsGrid` to streamline the dashboard. - Updated `DashboardKpiGrid` to improve KPI display logic, including progress indicators and enhanced badge functionality. - Refactored `DashboardNetworkHealth` to provide better status representation based on loading states and network conditions. - Introduced new properties for KPI cards to support progress tracking and improved visual feedback. This cleanup aims to enhance performance and maintainability of the dashboard while providing a better user experience.
124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
package store
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ComputeModuleInputHash fingerprints module config and child entries so snapshots
|
|
// invalidate on CRUD without re-reading every child at render time.
|
|
func ComputeModuleInputHash(st Backend, tenantID string, mod *Module) (string, error) {
|
|
if st == nil || mod == nil {
|
|
return "", fmt.Errorf("store: module hash: missing store or module")
|
|
}
|
|
h := sha256.New()
|
|
_, _ = fmt.Fprintf(h, "type=%s\n", strings.TrimSpace(mod.Type))
|
|
_, _ = fmt.Fprintf(h, "enabled=%t\n", mod.Enabled)
|
|
if mod.DefaultCommunityID != nil {
|
|
_, _ = fmt.Fprintf(h, "default_community=%s\n", strings.TrimSpace(*mod.DefaultCommunityID))
|
|
}
|
|
_, _ = fmt.Fprintf(h, "doh_policy=%s\n", NormalizeDohResolverPolicy(mod.DohResolverPolicy))
|
|
for _, pid := range mod.EffectiveDohProfileIDs() {
|
|
_, _ = fmt.Fprintf(h, "doh_profile=%s\n", pid)
|
|
if prof, err := st.GetDohProfile(tenantID, pid); err == nil && prof != nil {
|
|
_, _ = fmt.Fprintf(h, "doh_url=%s\n", strings.TrimSpace(prof.URL))
|
|
if prof.TimeoutMs != nil {
|
|
_, _ = fmt.Fprintf(h, "doh_timeout=%d\n", *prof.TimeoutMs)
|
|
}
|
|
}
|
|
}
|
|
|
|
switch mod.Type {
|
|
case "IP_RANGES":
|
|
list, err := st.ListIPRangeEntries(tenantID, mod.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sort.Slice(list, func(i, j int) bool { return list[i].Prefix < list[j].Prefix })
|
|
for _, e := range list {
|
|
comm := ""
|
|
if e.CommunityID != nil {
|
|
comm = *e.CommunityID
|
|
}
|
|
_, _ = fmt.Fprintf(h, "ip=%s|c=%s\n", e.Prefix, comm)
|
|
}
|
|
case "AS_PREFIXES":
|
|
list, err := st.ListASEntries(tenantID, mod.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sort.Slice(list, func(i, j int) bool { return list[i].ASN < list[j].ASN })
|
|
for _, e := range list {
|
|
comm := ""
|
|
if e.CommunityID != nil {
|
|
comm = *e.CommunityID
|
|
}
|
|
_, _ = fmt.Fprintf(h, "as=%d|c=%s\n", e.ASN, comm)
|
|
}
|
|
case "CDN_CIDRS":
|
|
list, err := st.ListCDNSources(tenantID, mod.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sort.Slice(list, func(i, j int) bool { return list[i].ID < list[j].ID })
|
|
for _, s := range list {
|
|
comm := ""
|
|
if s.CommunityID != nil {
|
|
comm = *s.CommunityID
|
|
}
|
|
interval := 0
|
|
if s.RefreshIntervalSec != nil {
|
|
interval = *s.RefreshIntervalSec
|
|
}
|
|
_, _ = fmt.Fprintf(h, "cdn=%s|url=%s|kind=%s|path=%s|c=%s|etag=%s|interval=%d\n",
|
|
s.ID, strings.TrimSpace(s.URL), s.SourceKind, strings.TrimSpace(s.PrefixPath), comm,
|
|
strings.TrimSpace(s.Etag), interval)
|
|
}
|
|
case "DOMAINS":
|
|
list, err := st.ListDomainEntries(tenantID, mod.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sort.Slice(list, func(i, j int) bool { return list[i].FQDN < list[j].FQDN })
|
|
for _, e := range list {
|
|
comm := ""
|
|
if e.CommunityID != nil {
|
|
comm = *e.CommunityID
|
|
}
|
|
_, _ = fmt.Fprintf(h, "dom=%s|c=%s\n", strings.TrimSpace(e.FQDN), comm)
|
|
}
|
|
default:
|
|
_, _ = fmt.Fprintf(h, "unknown_type=%s\n", mod.Type)
|
|
}
|
|
return hex.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
// TouchModuleInputHash recomputes and stores module.input_hash (ARCH-01: hash lives in store).
|
|
func TouchModuleInputHash(st Backend, tenantID, moduleID string) {
|
|
if st == nil {
|
|
return
|
|
}
|
|
mod, err := st.GetModule(tenantID, moduleID)
|
|
if err != nil || mod == nil {
|
|
return
|
|
}
|
|
h, err := ComputeModuleInputHash(st, tenantID, mod)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_ = st.SetModuleInputHash(tenantID, moduleID, h)
|
|
}
|
|
|
|
// CDNPatchAffectsInputHash reports whether a CDN source patch changes ingest fingerprint
|
|
// fields (URL/kind/path/community/interval). ETag and last_refreshed_at do not.
|
|
func CDNPatchAffectsInputHash(patch *CDNSourcePatch) bool {
|
|
if patch == nil {
|
|
return false
|
|
}
|
|
return patch.SourceKind != nil || patch.URL != nil || patch.PrefixPath != nil ||
|
|
patch.CommunityID != nil || patch.RefreshIntervalSec != nil
|
|
}
|