Add AS peers display to AS detail page
- Added GetASPeers method to database to fetch all peering relationships - Updated AS detail handler to fetch and pass peers to template - Added peers section to AS detail page showing all peer ASNs with their info - Added peer count to the info cards at the top of the page - Shows handle, description, and first/last seen dates for each peer
This commit is contained in:
@@ -1435,6 +1435,65 @@ func (d *Database) GetASDetailsContext(ctx context.Context, asn int) (*ASN, []Li
|
||||
return &asnInfo, allPrefixes, nil
|
||||
}
|
||||
|
||||
// ASPeer represents a peering relationship with another AS
|
||||
type ASPeer struct {
|
||||
ASN int `json:"asn"`
|
||||
Handle string `json:"handle"`
|
||||
Description string `json:"description"`
|
||||
FirstSeen time.Time `json:"first_seen"`
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
}
|
||||
|
||||
// GetASPeers returns all ASes that peer with the given AS
|
||||
func (d *Database) GetASPeers(asn int) ([]ASPeer, error) {
|
||||
return d.GetASPeersContext(context.Background(), asn)
|
||||
}
|
||||
|
||||
// GetASPeersContext returns all ASes that peer with the given AS with context support
|
||||
func (d *Database) GetASPeersContext(ctx context.Context, asn int) ([]ASPeer, error) {
|
||||
query := `
|
||||
SELECT
|
||||
CASE
|
||||
WHEN p.as_a = ? THEN p.as_b
|
||||
ELSE p.as_a
|
||||
END as peer_asn,
|
||||
COALESCE(a.handle, '') as handle,
|
||||
COALESCE(a.description, '') as description,
|
||||
p.first_seen,
|
||||
p.last_seen
|
||||
FROM peerings p
|
||||
LEFT JOIN asns a ON a.asn = CASE
|
||||
WHEN p.as_a = ? THEN p.as_b
|
||||
ELSE p.as_a
|
||||
END
|
||||
WHERE p.as_a = ? OR p.as_b = ?
|
||||
ORDER BY peer_asn
|
||||
`
|
||||
|
||||
rows, err := d.db.QueryContext(ctx, query, asn, asn, asn, asn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query AS peers: %w", err)
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var peers []ASPeer
|
||||
for rows.Next() {
|
||||
var peer ASPeer
|
||||
err := rows.Scan(&peer.ASN, &peer.Handle, &peer.Description, &peer.FirstSeen, &peer.LastSeen)
|
||||
if err != nil {
|
||||
d.logger.Error("Failed to scan peer row", "error", err, "asn", asn)
|
||||
continue
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("error iterating AS peers: %w", err)
|
||||
}
|
||||
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
// GetPrefixDetails returns detailed information about a prefix
|
||||
func (d *Database) GetPrefixDetails(prefix string) ([]LiveRoute, error) {
|
||||
return d.GetPrefixDetailsContext(context.Background(), prefix)
|
||||
|
||||
@@ -60,6 +60,8 @@ type Store interface {
|
||||
// AS and prefix detail operations
|
||||
GetASDetails(asn int) (*ASN, []LiveRoute, error)
|
||||
GetASDetailsContext(ctx context.Context, asn int) (*ASN, []LiveRoute, error)
|
||||
GetASPeers(asn int) ([]ASPeer, error)
|
||||
GetASPeersContext(ctx context.Context, asn int) ([]ASPeer, error)
|
||||
GetPrefixDetails(prefix string) ([]LiveRoute, error)
|
||||
GetPrefixDetailsContext(ctx context.Context, prefix string) ([]LiveRoute, error)
|
||||
GetRandomPrefixesByLength(maskLength, ipVersion, limit int) ([]LiveRoute, error)
|
||||
|
||||
Reference in New Issue
Block a user