Files
Denozordec dc803bcb34
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
refactor(web): remove deprecated dashboard components and enhance KPI grid
- 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.
2026-08-31 10:15:59 +07:00

127 lines
3.5 KiB
Go

package pipeline
import (
"context"
"fmt"
"net/http"
"net/netip"
"os"
"strconv"
"strings"
"time"
"evobgp/internal/asnresolve"
"evobgp/internal/store"
)
func asnCacheTTL() time.Duration {
sec := 1800
if s := strings.TrimSpace(os.Getenv("EVOBGP_ASN_CACHE_TTL_SEC")); s != "" {
if v, err := strconv.Atoi(s); err == nil && v > 0 {
sec = v
}
}
return time.Duration(sec) * time.Second
}
// asnHolderTTL is how long a holder name stays authoritative between refreshes;
// holder text changes rarely, so it survives short prefix-cache TTLs.
func asnHolderTTL() time.Duration {
sec := 7 * 24 * 3600
if s := strings.TrimSpace(os.Getenv("EVOBGP_ASN_HOLDER_TTL_SEC")); s != "" {
if v, err := strconv.Atoi(s); err == nil && v > 0 {
sec = v
}
}
return time.Duration(sec) * time.Second
}
// resolveASNForEntry fetches prefixes and holder with shared TTL cache (asn_prefix_cache).
// The holder lookup starts concurrently with the prefix fetch (one RTT instead of two);
// a holder failure is non-fatal — the previously cached holder name is kept.
func resolveASNForEntry(ctx context.Context, st store.Backend, hc *http.Client, asn int64) ([]netip.Prefix, string, error) {
ttl := asnCacheTTL()
var prevHolder string
if st != nil {
if ent, ok, err := st.GetASNPrefixCache(asn); err == nil && ok && ent != nil {
prevHolder = ent.Holder
if time.Since(ent.FetchedAt) < ttl {
return parseASNCachePrefixes(ent.Prefixes), ent.Holder, nil
}
}
}
holderCh := startASNHolderFetch(ctx, hc, st, asn, prevHolder)
pfxs, err := asnresolve.AnnouncedPrefixes(ctx, hc, asn)
if err != nil {
holder := <-holderCh // drain to avoid leaking the goroutine's channel send
_ = holder
return nil, "", err
}
holder := <-holderCh
if st != nil {
strs := make([]string, len(pfxs))
for i, p := range pfxs {
strs[i] = p.String()
}
if err := st.SetASNPrefixCache(asn, holder, strs); err != nil {
return nil, "", fmt.Errorf("asn cache AS%d: %w", asn, err)
}
}
return pfxs, holder, nil
}
// startASNHolderFetch launches the holder lookup concurrently. The returned buffered
// channel always yields exactly one value, so callers may abandon it without leaking.
func startASNHolderFetch(ctx context.Context, hc *http.Client, st store.Backend, asn int64, prevHolder string) <-chan string {
ch := make(chan string, 1)
go func() {
if prevHolder != "" && holderStillFresh(st, asn, prevHolder) {
ch <- prevHolder
return
}
holder, err := asnresolve.ASHolderName(ctx, hc, asn)
if err != nil || strings.TrimSpace(holder) == "" {
ch <- prevHolder
return
}
ch <- strings.TrimSpace(holder)
}()
return ch
}
// holderStillFresh reports whether the cached holder name is within its own (long) TTL.
func holderStillFresh(st store.Backend, asn int64, prevHolder string) bool {
if st == nil {
return false
}
ent, ok, err := st.GetASNPrefixCache(asn)
return err == nil && ok && ent != nil && ent.Holder == prevHolder && time.Since(ent.FetchedAt) < asnHolderTTL()
}
func parseASNCachePrefixes(raw []string) []netip.Prefix {
out := make([]netip.Prefix, 0, len(raw))
for _, p := range raw {
pfx, perr := netip.ParsePrefix(strings.TrimSpace(p))
if perr != nil {
continue
}
out = append(out, pfx.Masked())
}
return out
}
func parseCachedASNCachedPrefixes(raw []string) []netip.Prefix {
out := make([]netip.Prefix, 0, len(raw))
for _, p := range raw {
pfx, perr := netip.ParsePrefix(strings.TrimSpace(p))
if perr != nil {
continue
}
out = append(out, pfx.Masked())
}
return out
}