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()
|
stats.FileSizeBytes = fileInfo.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get live routes count
|
// Get live routes count from both tables
|
||||||
err = d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM live_routes").Scan(&stats.LiveRoutes)
|
var v4Count, v6Count int
|
||||||
|
err = d.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM live_routes_v4").Scan(&v4Count)
|
||||||
if err != nil {
|
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
|
// Get prefix distribution
|
||||||
stats.IPv4PrefixDistribution, stats.IPv6PrefixDistribution, err = d.GetPrefixDistributionContext(ctx)
|
stats.IPv4PrefixDistribution, stats.IPv6PrefixDistribution, err = d.GetPrefixDistributionContext(ctx)
|
||||||
@ -868,19 +874,38 @@ func (d *Database) UpsertLiveRoute(route *LiveRoute) error {
|
|||||||
d.lock("UpsertLiveRoute")
|
d.lock("UpsertLiveRoute")
|
||||||
defer d.unlock()
|
defer d.unlock()
|
||||||
|
|
||||||
query := `
|
// Choose table based on IP version
|
||||||
INSERT INTO live_routes (id, prefix, mask_length, ip_version, origin_asn, peer_ip, as_path, next_hop,
|
tableName := "live_routes_v4"
|
||||||
last_updated, v4_ip_start, v4_ip_end)
|
if route.IPVersion == ipVersionV6 {
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
tableName = "live_routes_v6"
|
||||||
ON CONFLICT(prefix, origin_asn, peer_ip) DO UPDATE SET
|
}
|
||||||
mask_length = excluded.mask_length,
|
|
||||||
ip_version = excluded.ip_version,
|
var query string
|
||||||
as_path = excluded.as_path,
|
if route.IPVersion == ipVersionV4 {
|
||||||
next_hop = excluded.next_hop,
|
query = fmt.Sprintf(`
|
||||||
last_updated = excluded.last_updated,
|
INSERT INTO %s (id, prefix, mask_length, origin_asn, peer_ip, as_path, next_hop,
|
||||||
v4_ip_start = excluded.v4_ip_start,
|
last_updated, ip_start, ip_end)
|
||||||
v4_ip_end = excluded.v4_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
|
// Encode AS path as JSON
|
||||||
pathJSON, err := json.Marshal(route.ASPath)
|
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)
|
return fmt.Errorf("failed to encode AS path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert v4_ip_start and v4_ip_end to interface{} for SQL NULL handling
|
if route.IPVersion == ipVersionV4 {
|
||||||
var v4Start, v4End interface{}
|
// Convert v4_ip_start and v4_ip_end to interface{} for SQL NULL handling
|
||||||
if route.V4IPStart != nil {
|
var v4Start, v4End interface{}
|
||||||
v4Start = *route.V4IPStart
|
if route.V4IPStart != nil {
|
||||||
}
|
v4Start = *route.V4IPStart
|
||||||
if route.V4IPEnd != nil {
|
}
|
||||||
v4End = *route.V4IPEnd
|
if route.V4IPEnd != nil {
|
||||||
}
|
v4End = *route.V4IPEnd
|
||||||
|
}
|
||||||
|
|
||||||
_, err = d.db.Exec(query,
|
_, err = d.db.Exec(query,
|
||||||
route.ID.String(),
|
route.ID.String(),
|
||||||
route.Prefix,
|
route.Prefix,
|
||||||
route.MaskLength,
|
route.MaskLength,
|
||||||
route.IPVersion,
|
route.OriginASN,
|
||||||
route.OriginASN,
|
route.PeerIP,
|
||||||
route.PeerIP,
|
string(pathJSON),
|
||||||
string(pathJSON),
|
route.NextHop,
|
||||||
route.NextHop,
|
route.LastUpdated,
|
||||||
route.LastUpdated,
|
v4Start,
|
||||||
v4Start,
|
v4End,
|
||||||
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
|
return err
|
||||||
}
|
}
|
||||||
@ -920,16 +957,25 @@ func (d *Database) DeleteLiveRoute(prefix string, originASN int, peerIP string)
|
|||||||
d.lock("DeleteLiveRoute")
|
d.lock("DeleteLiveRoute")
|
||||||
defer d.unlock()
|
defer d.unlock()
|
||||||
|
|
||||||
var query string
|
// Determine table based on prefix IP version
|
||||||
var err error
|
_, 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 {
|
if originASN == 0 {
|
||||||
// Delete all routes for this prefix from this peer
|
// 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)
|
_, err = d.db.Exec(query, prefix, peerIP)
|
||||||
} else {
|
} else {
|
||||||
// Delete specific route
|
// 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)
|
_, err = d.db.Exec(query, prefix, originASN, peerIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ func (s *Server) handleStats() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
s.logger.Error("Failed to get database stats", "error", err)
|
s.logger.Error("Failed to get database stats", "error", err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
writeJSONError(w, http.StatusInternalServerError, err.Error())
|
||||||
|
|
||||||
return
|
return
|
||||||
case dbStats = <-statsChan:
|
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() {
|
function updateStatus() {
|
||||||
fetch('/api/v1/stats')
|
fetch('/api/v1/stats')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
@ -294,6 +327,7 @@
|
|||||||
if (response.status === 'error') {
|
if (response.status === 'error') {
|
||||||
document.getElementById('error').textContent = 'Error: ' + response.error.msg;
|
document.getElementById('error').textContent = 'Error: ' + response.error.msg;
|
||||||
document.getElementById('error').style.display = 'block';
|
document.getElementById('error').style.display = 'block';
|
||||||
|
resetAllFields();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +374,7 @@
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
document.getElementById('error').textContent = 'Error fetching status: ' + error;
|
document.getElementById('error').textContent = 'Error fetching status: ' + error;
|
||||||
document.getElementById('error').style.display = 'block';
|
document.getElementById('error').style.display = 'block';
|
||||||
|
resetAllFields();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user