Fix JavaScript UI and complete database table migration
- Update status page JavaScript to reset all fields to '-' on error - Fix status page to not show 'Connected' when API returns error - Update remaining database methods to use new live_routes_v4/v6 tables - Fix GetStatsContext to count routes from both IPv4 and IPv6 tables - Fix UpsertLiveRoute to insert into correct table based on IP version - Fix DeleteLiveRoute to determine table from prefix IP version
This commit is contained in:
parent
3673264552
commit
fc32090483
@ -847,11 +847,17 @@ func (d *Database) GetStatsContext(ctx context.Context) (Stats, error) {
|
||||
stats.FileSizeBytes = fileInfo.Size()
|
||||
}
|
||||
|
||||
// Get live routes count
|
||||
err = d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM live_routes").Scan(&stats.LiveRoutes)
|
||||
// Get live routes count from both tables
|
||||
var v4Count, v6Count int
|
||||
err = d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM live_routes_v4").Scan(&v4Count)
|
||||
if err != nil {
|
||||
return stats, fmt.Errorf("failed to count live routes: %w", err)
|
||||
return stats, fmt.Errorf("failed to count IPv4 routes: %w", err)
|
||||
}
|
||||
err = d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM live_routes_v6").Scan(&v6Count)
|
||||
if err != nil {
|
||||
return stats, fmt.Errorf("failed to count IPv6 routes: %w", err)
|
||||
}
|
||||
stats.LiveRoutes = v4Count + v6Count
|
||||
|
||||
// Get prefix distribution
|
||||
stats.IPv4PrefixDistribution, stats.IPv6PrefixDistribution, err = d.GetPrefixDistributionContext(ctx)
|
||||
@ -868,19 +874,38 @@ func (d *Database) UpsertLiveRoute(route *LiveRoute) error {
|
||||
d.lock("UpsertLiveRoute")
|
||||
defer d.unlock()
|
||||
|
||||
query := `
|
||||
INSERT INTO live_routes (id, prefix, mask_length, ip_version, origin_asn, peer_ip, as_path, next_hop,
|
||||
last_updated, v4_ip_start, v4_ip_end)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(prefix, origin_asn, peer_ip) DO UPDATE SET
|
||||
mask_length = excluded.mask_length,
|
||||
ip_version = excluded.ip_version,
|
||||
as_path = excluded.as_path,
|
||||
next_hop = excluded.next_hop,
|
||||
last_updated = excluded.last_updated,
|
||||
v4_ip_start = excluded.v4_ip_start,
|
||||
v4_ip_end = excluded.v4_ip_end
|
||||
`
|
||||
// Choose table based on IP version
|
||||
tableName := "live_routes_v4"
|
||||
if route.IPVersion == ipVersionV6 {
|
||||
tableName = "live_routes_v6"
|
||||
}
|
||||
|
||||
var query string
|
||||
if route.IPVersion == ipVersionV4 {
|
||||
query = fmt.Sprintf(`
|
||||
INSERT INTO %s (id, prefix, mask_length, origin_asn, peer_ip, as_path, next_hop,
|
||||
last_updated, ip_start, ip_end)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(prefix, origin_asn, peer_ip) DO UPDATE SET
|
||||
mask_length = excluded.mask_length,
|
||||
as_path = excluded.as_path,
|
||||
next_hop = excluded.next_hop,
|
||||
last_updated = excluded.last_updated,
|
||||
ip_start = excluded.ip_start,
|
||||
ip_end = excluded.ip_end
|
||||
`, tableName)
|
||||
} else {
|
||||
query = fmt.Sprintf(`
|
||||
INSERT INTO %s (id, prefix, mask_length, origin_asn, peer_ip, as_path, next_hop,
|
||||
last_updated)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(prefix, origin_asn, peer_ip) DO UPDATE SET
|
||||
mask_length = excluded.mask_length,
|
||||
as_path = excluded.as_path,
|
||||
next_hop = excluded.next_hop,
|
||||
last_updated = excluded.last_updated
|
||||
`, tableName)
|
||||
}
|
||||
|
||||
// Encode AS path as JSON
|
||||
pathJSON, err := json.Marshal(route.ASPath)
|
||||
@ -888,28 +913,40 @@ func (d *Database) UpsertLiveRoute(route *LiveRoute) error {
|
||||
return fmt.Errorf("failed to encode AS path: %w", err)
|
||||
}
|
||||
|
||||
// Convert v4_ip_start and v4_ip_end to interface{} for SQL NULL handling
|
||||
var v4Start, v4End interface{}
|
||||
if route.V4IPStart != nil {
|
||||
v4Start = *route.V4IPStart
|
||||
}
|
||||
if route.V4IPEnd != nil {
|
||||
v4End = *route.V4IPEnd
|
||||
}
|
||||
if route.IPVersion == ipVersionV4 {
|
||||
// Convert v4_ip_start and v4_ip_end to interface{} for SQL NULL handling
|
||||
var v4Start, v4End interface{}
|
||||
if route.V4IPStart != nil {
|
||||
v4Start = *route.V4IPStart
|
||||
}
|
||||
if route.V4IPEnd != nil {
|
||||
v4End = *route.V4IPEnd
|
||||
}
|
||||
|
||||
_, err = d.db.Exec(query,
|
||||
route.ID.String(),
|
||||
route.Prefix,
|
||||
route.MaskLength,
|
||||
route.IPVersion,
|
||||
route.OriginASN,
|
||||
route.PeerIP,
|
||||
string(pathJSON),
|
||||
route.NextHop,
|
||||
route.LastUpdated,
|
||||
v4Start,
|
||||
v4End,
|
||||
)
|
||||
_, err = d.db.Exec(query,
|
||||
route.ID.String(),
|
||||
route.Prefix,
|
||||
route.MaskLength,
|
||||
route.OriginASN,
|
||||
route.PeerIP,
|
||||
string(pathJSON),
|
||||
route.NextHop,
|
||||
route.LastUpdated,
|
||||
v4Start,
|
||||
v4End,
|
||||
)
|
||||
} else {
|
||||
_, err = d.db.Exec(query,
|
||||
route.ID.String(),
|
||||
route.Prefix,
|
||||
route.MaskLength,
|
||||
route.OriginASN,
|
||||
route.PeerIP,
|
||||
string(pathJSON),
|
||||
route.NextHop,
|
||||
route.LastUpdated,
|
||||
)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@ -920,16 +957,25 @@ func (d *Database) DeleteLiveRoute(prefix string, originASN int, peerIP string)
|
||||
d.lock("DeleteLiveRoute")
|
||||
defer d.unlock()
|
||||
|
||||
var query string
|
||||
var err error
|
||||
// Determine table based on prefix IP version
|
||||
_, ipnet, err := net.ParseCIDR(prefix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid prefix format: %w", err)
|
||||
}
|
||||
|
||||
tableName := "live_routes_v4"
|
||||
if ipnet.IP.To4() == nil {
|
||||
tableName = "live_routes_v6"
|
||||
}
|
||||
|
||||
var query string
|
||||
if originASN == 0 {
|
||||
// Delete all routes for this prefix from this peer
|
||||
query = `DELETE FROM live_routes WHERE prefix = ? AND peer_ip = ?`
|
||||
query = fmt.Sprintf(`DELETE FROM %s WHERE prefix = ? AND peer_ip = ?`, tableName)
|
||||
_, err = d.db.Exec(query, prefix, peerIP)
|
||||
} else {
|
||||
// Delete specific route
|
||||
query = `DELETE FROM live_routes WHERE prefix = ? AND origin_asn = ? AND peer_ip = ?`
|
||||
query = fmt.Sprintf(`DELETE FROM %s WHERE prefix = ? AND origin_asn = ? AND peer_ip = ?`, tableName)
|
||||
_, err = d.db.Exec(query, prefix, originASN, peerIP)
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ func (s *Server) handleStats() http.HandlerFunc {
|
||||
return
|
||||
case err := <-errChan:
|
||||
s.logger.Error("Failed to get database stats", "error", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
writeJSONError(w, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
case dbStats = <-statsChan:
|
||||
|
@ -286,6 +286,39 @@
|
||||
});
|
||||
}
|
||||
|
||||
function resetAllFields() {
|
||||
// Reset all metric fields to '-'
|
||||
document.getElementById('connected').textContent = '-';
|
||||
document.getElementById('connected').className = 'metric-value';
|
||||
document.getElementById('uptime').textContent = '-';
|
||||
document.getElementById('go_version').textContent = '-';
|
||||
document.getElementById('goroutines').textContent = '-';
|
||||
document.getElementById('memory_usage').textContent = '-';
|
||||
document.getElementById('total_messages').textContent = '-';
|
||||
document.getElementById('messages_per_sec').textContent = '-';
|
||||
document.getElementById('total_bytes').textContent = '-';
|
||||
document.getElementById('mbits_per_sec').textContent = '-';
|
||||
document.getElementById('asns').textContent = '-';
|
||||
document.getElementById('prefixes').textContent = '-';
|
||||
document.getElementById('ipv4_prefixes').textContent = '-';
|
||||
document.getElementById('ipv6_prefixes').textContent = '-';
|
||||
document.getElementById('peerings').textContent = '-';
|
||||
document.getElementById('peers').textContent = '-';
|
||||
document.getElementById('database_size').textContent = '-';
|
||||
document.getElementById('live_routes').textContent = '-';
|
||||
document.getElementById('ipv4_routes').textContent = '-';
|
||||
document.getElementById('ipv6_routes').textContent = '-';
|
||||
document.getElementById('ipv4_updates_per_sec').textContent = '-';
|
||||
document.getElementById('ipv6_updates_per_sec').textContent = '-';
|
||||
|
||||
// Clear handler stats
|
||||
document.getElementById('handler-stats-container').innerHTML = '';
|
||||
|
||||
// Clear prefix distributions
|
||||
document.getElementById('ipv4-prefix-distribution').innerHTML = '<div class="metric"><span class="metric-label">No data</span></div>';
|
||||
document.getElementById('ipv6-prefix-distribution').innerHTML = '<div class="metric"><span class="metric-label">No data</span></div>';
|
||||
}
|
||||
|
||||
function updateStatus() {
|
||||
fetch('/api/v1/stats')
|
||||
.then(response => response.json())
|
||||
@ -294,6 +327,7 @@
|
||||
if (response.status === 'error') {
|
||||
document.getElementById('error').textContent = 'Error: ' + response.error.msg;
|
||||
document.getElementById('error').style.display = 'block';
|
||||
resetAllFields();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -340,6 +374,7 @@
|
||||
.catch(error => {
|
||||
document.getElementById('error').textContent = 'Error fetching status: ' + error;
|
||||
document.getElementById('error').style.display = 'block';
|
||||
resetAllFields();
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user