Files
explorer-monorepo/backend/api/track1/ccip_health.go
defiQUG bdae5a9f6e feat: explorer API, wallet, CCIP scripts, and config refresh
- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
2026-04-07 23:22:12 -07:00

183 lines
4.6 KiB
Go

package track1
import (
"context"
"encoding/json"
"io"
"net/http"
"os"
"sort"
"strconv"
"strings"
"time"
)
type relayHealthTarget struct {
Name string
URL string
}
func fetchRelayHealthURL(ctx context.Context, u string) map[string]interface{} {
out := make(map[string]interface{})
c := &http.Client{Timeout: 4 * time.Second}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
out["url_probe"] = map[string]interface{}{"ok": false, "error": err.Error()}
} else {
resp, err := c.Do(req)
if err != nil {
out["url_probe"] = map[string]interface{}{"ok": false, "error": err.Error()}
} else {
func() {
defer resp.Body.Close()
b, _ := io.ReadAll(io.LimitReader(resp.Body, 256*1024))
ok := resp.StatusCode >= 200 && resp.StatusCode < 300
var j interface{}
if json.Unmarshal(b, &j) == nil {
out["url_probe"] = map[string]interface{}{"ok": ok, "status": resp.StatusCode, "body": j}
} else {
out["url_probe"] = map[string]interface{}{"ok": ok, "status": resp.StatusCode, "raw": string(b)}
}
}()
}
}
return out
}
func fetchRelayHealthFileSnapshot(p string) map[string]interface{} {
out := make(map[string]interface{})
if p != "" {
b, err := os.ReadFile(p)
if err != nil {
out["file_snapshot_error"] = err.Error()
} else if len(b) > 512*1024 {
out["file_snapshot_error"] = "file too large"
} else {
var j interface{}
if err := json.Unmarshal(b, &j); err != nil {
out["file_snapshot_error"] = err.Error()
} else {
out["file_snapshot"] = j
}
}
}
return out
}
func buildRelayHealthSignal(ctx context.Context, url, filePath string) map[string]interface{} {
out := make(map[string]interface{})
if strings.TrimSpace(url) != "" {
for key, value := range fetchRelayHealthURL(ctx, url) {
out[key] = value
}
}
if strings.TrimSpace(filePath) != "" {
for key, value := range fetchRelayHealthFileSnapshot(filePath) {
out[key] = value
}
}
if len(out) == 0 {
return nil
}
return out
}
func normalizeRelayHealthName(raw string, index int) string {
name := strings.TrimSpace(strings.ToLower(raw))
if name == "" {
return "relay_" + strconv.Itoa(index)
}
replacer := strings.NewReplacer(" ", "_", "-", "_", "/", "_")
name = replacer.Replace(name)
return name
}
func parseRelayHealthTargets() []relayHealthTarget {
raw := strings.TrimSpace(os.Getenv("CCIP_RELAY_HEALTH_URLS"))
if raw == "" {
return nil
}
normalized := strings.NewReplacer("\n", ",", ";", ",").Replace(raw)
parts := strings.Split(normalized, ",")
targets := make([]relayHealthTarget, 0, len(parts))
for idx, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
name := ""
url := part
if strings.Contains(part, "=") {
chunks := strings.SplitN(part, "=", 2)
name = normalizeRelayHealthName(chunks[0], idx+1)
url = strings.TrimSpace(chunks[1])
} else {
name = normalizeRelayHealthName("", idx+1)
}
if url == "" {
continue
}
targets = append(targets, relayHealthTarget{Name: name, URL: url})
}
return targets
}
// FetchCCIPRelayHealths returns optional named CCIP / relay signals from URL probes and/or operator JSON files.
// Safe defaults: short timeouts, small body cap. Omit from payload when nothing is configured.
func FetchCCIPRelayHealths(ctx context.Context) map[string]interface{} {
relays := make(map[string]interface{})
if legacy := buildRelayHealthSignal(
ctx,
strings.TrimSpace(os.Getenv("CCIP_RELAY_HEALTH_URL")),
strings.TrimSpace(os.Getenv("MISSION_CONTROL_CCIP_JSON")),
); legacy != nil {
relays["mainnet"] = legacy
}
for _, target := range parseRelayHealthTargets() {
if _, exists := relays[target.Name]; exists {
continue
}
if relay := buildRelayHealthSignal(ctx, target.URL, ""); relay != nil {
relays[target.Name] = relay
}
}
if len(relays) == 0 {
return nil
}
return relays
}
func primaryRelayHealth(relays map[string]interface{}) map[string]interface{} {
if len(relays) == 0 {
return nil
}
preferred := []string{"mainnet_cw", "mainnet_weth", "mainnet"}
for _, key := range preferred {
if relay, ok := relays[key].(map[string]interface{}); ok {
return relay
}
}
keys := make([]string, 0, len(relays))
for key := range relays {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
if relay, ok := relays[key].(map[string]interface{}); ok {
return relay
}
}
return nil
}
// FetchCCIPRelayHealth returns the primary relay signal for legacy callers.
func FetchCCIPRelayHealth(ctx context.Context) map[string]interface{} {
return primaryRelayHealth(FetchCCIPRelayHealths(ctx))
}