+3
internal/api/handlers.go
+3
internal/api/handlers.go
+52
-39
internal/storage/postgres.go
+52
-39
internal/storage/postgres.go
···
93
93
CREATE INDEX IF NOT EXISTS idx_endpoints_type ON endpoints(endpoint_type);
94
94
CREATE INDEX IF NOT EXISTS idx_endpoints_ip ON endpoints(ip);
95
95
CREATE INDEX IF NOT EXISTS idx_endpoints_server_did ON endpoints(server_did);
96
+
CREATE INDEX IF NOT EXISTS idx_endpoints_server_did_type_discovered ON endpoints(server_did, endpoint_type, discovered_at);
96
97
97
98
-- IP infos table (IP as PRIMARY KEY)
98
99
CREATE TABLE IF NOT EXISTS ip_infos (
···
670
671
671
672
func (p *PostgresDB) GetPDSDetail(ctx context.Context, endpoint string) (*PDSDetail, error) {
672
673
query := `
674
+
WITH target_endpoint AS (
675
+
SELECT
676
+
e.id,
677
+
e.endpoint,
678
+
e.server_did,
679
+
e.discovered_at,
680
+
e.last_checked,
681
+
e.status,
682
+
e.ip
683
+
FROM endpoints e
684
+
WHERE e.endpoint = $1 AND e.endpoint_type = 'pds'
685
+
),
686
+
aliases_agg AS (
687
+
SELECT
688
+
te.server_did,
689
+
array_agg(e.endpoint ORDER BY e.discovered_at) FILTER (WHERE e.endpoint != te.endpoint) as aliases,
690
+
MIN(e.discovered_at) as first_discovered_at
691
+
FROM target_endpoint te
692
+
LEFT JOIN endpoints e ON te.server_did = e.server_did
693
+
AND e.endpoint_type = 'pds'
694
+
AND te.server_did IS NOT NULL
695
+
GROUP BY te.server_did
696
+
)
673
697
SELECT
674
-
e.id, e.endpoint, e.server_did, e.discovered_at, e.last_checked, e.status, e.ip,
698
+
te.id,
699
+
te.endpoint,
700
+
te.server_did,
701
+
te.discovered_at,
702
+
te.last_checked,
703
+
te.status,
704
+
te.ip,
675
705
latest.user_count,
676
706
latest.response_time,
677
707
latest.version,
···
679
709
latest.scanned_at,
680
710
i.city, i.country, i.country_code, i.asn, i.asn_org,
681
711
i.is_datacenter, i.is_vpn, i.latitude, i.longitude,
682
-
i.raw_data
683
-
FROM endpoints e
712
+
i.raw_data,
713
+
COALESCE(aa.aliases, ARRAY[]::text[]) as aliases,
714
+
aa.first_discovered_at
715
+
FROM target_endpoint te
716
+
LEFT JOIN aliases_agg aa ON te.server_did = aa.server_did
684
717
LEFT JOIN LATERAL (
685
718
SELECT scan_data, response_time, version, scanned_at, user_count
686
719
FROM endpoint_scans
687
-
WHERE endpoint_id = e.id
720
+
WHERE endpoint_id = te.id
688
721
ORDER BY scanned_at DESC
689
722
LIMIT 1
690
723
) latest ON true
691
-
LEFT JOIN ip_infos i ON e.ip = i.ip
692
-
WHERE e.endpoint = $1 AND e.endpoint_type = 'pds'
724
+
LEFT JOIN ip_infos i ON te.ip = i.ip
693
725
`
694
726
695
727
detail := &PDSDetail{}
···
703
735
var serverInfoJSON []byte
704
736
var scannedAt sql.NullTime
705
737
var rawDataJSON []byte
738
+
var aliases []string
739
+
var firstDiscoveredAt sql.NullTime
706
740
707
741
err := p.db.QueryRowContext(ctx, query, endpoint).Scan(
708
742
&detail.ID, &detail.Endpoint, &serverDID, &detail.DiscoveredAt, &detail.LastChecked, &detail.Status, &ip,
···
710
744
&city, &country, &countryCode, &asn, &asnOrg,
711
745
&isDatacenter, &isVPN, &lat, &lon,
712
746
&rawDataJSON,
747
+
pq.Array(&aliases),
748
+
&firstDiscoveredAt,
713
749
)
714
750
if err != nil {
715
751
return nil, err
···
719
755
detail.IP = ip.String
720
756
}
721
757
722
-
// NEW: Get aliases if this endpoint has a server_did
723
-
if serverDID.Valid && serverDID.String != "" {
724
-
aliasQuery := `
725
-
SELECT endpoint, discovered_at
726
-
FROM endpoints
727
-
WHERE server_did = $1
728
-
AND endpoint_type = 'pds'
729
-
AND endpoint != $2
730
-
ORDER BY discovered_at ASC
731
-
`
758
+
if serverDID.Valid {
759
+
detail.ServerDID = serverDID.String
760
+
}
732
761
733
-
rows, err := p.db.QueryContext(ctx, aliasQuery, serverDID.String, endpoint)
734
-
if err == nil {
735
-
defer rows.Close()
736
-
737
-
var aliases []string
738
-
var primaryDiscoveredAt time.Time
739
-
740
-
for rows.Next() {
741
-
var alias string
742
-
var discoveredAt time.Time
743
-
if err := rows.Scan(&alias, &discoveredAt); err == nil {
744
-
aliases = append(aliases, alias)
745
-
if primaryDiscoveredAt.IsZero() || discoveredAt.Before(detail.DiscoveredAt) {
746
-
primaryDiscoveredAt = discoveredAt
747
-
}
748
-
}
749
-
}
750
-
751
-
detail.Aliases = aliases
752
-
detail.IsPrimary = detail.DiscoveredAt.Equal(primaryDiscoveredAt) ||
753
-
detail.DiscoveredAt.Before(primaryDiscoveredAt)
754
-
}
762
+
// Set aliases and is_primary
763
+
detail.Aliases = aliases
764
+
if serverDID.Valid && serverDID.String != "" && firstDiscoveredAt.Valid {
765
+
// Has server_did - check if this is the first discovered
766
+
detail.IsPrimary = detail.DiscoveredAt.Equal(firstDiscoveredAt.Time) ||
767
+
detail.DiscoveredAt.Before(firstDiscoveredAt.Time)
755
768
} else {
756
-
// No server_did means it's a unique server
769
+
// No server_did means unique server
757
770
detail.IsPrimary = true
758
771
}
759
772