Files
explorer-monorepo/backend/api/track1/bridge_status_data.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

147 lines
3.7 KiB
Go

package track1
import (
"context"
"os"
"strings"
"time"
)
func relaySnapshotStatus(relay map[string]interface{}) string {
if relay == nil {
return ""
}
if probe, ok := relay["url_probe"].(map[string]interface{}); ok {
if okValue, exists := probe["ok"].(bool); exists && !okValue {
return "down"
}
if body, ok := probe["body"].(map[string]interface{}); ok {
if status, ok := body["status"].(string); ok {
return strings.ToLower(strings.TrimSpace(status))
}
}
}
if _, ok := relay["file_snapshot_error"].(string); ok {
return "down"
}
if snapshot, ok := relay["file_snapshot"].(map[string]interface{}); ok {
if status, ok := snapshot["status"].(string); ok {
return strings.ToLower(strings.TrimSpace(status))
}
}
return ""
}
func relayNeedsAttention(relay map[string]interface{}) bool {
status := relaySnapshotStatus(relay)
switch status {
case "degraded", "stale", "stopped", "down":
return true
default:
return false
}
}
// BuildBridgeStatusData builds the inner `data` object for bridge/status and SSE payloads.
func (s *Server) BuildBridgeStatusData(ctx context.Context) map[string]interface{} {
rpc138 := strings.TrimSpace(os.Getenv("RPC_URL"))
if rpc138 == "" {
rpc138 = "http://localhost:8545"
}
var probes []RPCProbeResult
p138 := ProbeEVMJSONRPC(ctx, "chain-138", "138", rpc138)
probes = append(probes, p138)
if eth := strings.TrimSpace(os.Getenv("ETH_MAINNET_RPC_URL")); eth != "" {
probes = append(probes, ProbeEVMJSONRPC(ctx, "ethereum-mainnet", "1", eth))
}
for _, row := range ParseExtraRPCProbes() {
name, u, ck := row[0], row[1], row[2]
probes = append(probes, ProbeEVMJSONRPC(ctx, name, ck, u))
}
overall := "operational"
if !p138.OK {
overall = "degraded"
} else {
for _, p := range probes {
if !p.OK {
overall = "degraded"
break
}
}
}
now := time.Now().UTC().Format(time.RFC3339)
chains := map[string]interface{}{
"138": map[string]interface{}{
"name": "Defi Oracle Meta Mainnet",
"status": chainStatusFromProbe(p138),
"last_sync": now,
"latency_ms": p138.LatencyMs,
"head_age_sec": p138.HeadAgeSeconds,
"block_number": p138.BlockNumberDec,
"endpoint": p138.Endpoint,
"probe_error": p138.Error,
},
}
for _, p := range probes {
if p.ChainKey != "1" && p.Name != "ethereum-mainnet" {
continue
}
chains["1"] = map[string]interface{}{
"name": "Ethereum Mainnet",
"status": chainStatusFromProbe(p),
"last_sync": now,
"latency_ms": p.LatencyMs,
"head_age_sec": p.HeadAgeSeconds,
"block_number": p.BlockNumberDec,
"endpoint": p.Endpoint,
"probe_error": p.Error,
}
break
}
probeJSON := make([]map[string]interface{}, 0, len(probes))
for _, p := range probes {
probeJSON = append(probeJSON, map[string]interface{}{
"name": p.Name,
"chainKey": p.ChainKey,
"endpoint": p.Endpoint,
"ok": p.OK,
"latencyMs": p.LatencyMs,
"blockNumber": p.BlockNumber,
"blockNumberDec": p.BlockNumberDec,
"headAgeSeconds": p.HeadAgeSeconds,
"error": p.Error,
})
}
data := map[string]interface{}{
"status": overall,
"chains": chains,
"rpc_probe": probeJSON,
"checked_at": now,
}
if ov := readOptionalVerifyJSON(); ov != nil {
data["operator_verify"] = ov
}
if relays := FetchCCIPRelayHealths(ctx); relays != nil {
data["ccip_relays"] = relays
if ccip := primaryRelayHealth(relays); ccip != nil {
data["ccip_relay"] = ccip
}
for _, value := range relays {
relay, ok := value.(map[string]interface{})
if ok && relayNeedsAttention(relay) {
data["status"] = "degraded"
break
}
}
}
return data
}