72 lines
1.9 KiB
Go
72 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
type TrafficMapCity struct {
|
|
TrafficCityLocation
|
|
Country string `json:"country"`
|
|
Requests int64 `json:"requests"`
|
|
UniqueIPs int64 `json:"uniqueIps"`
|
|
Alerts int64 `json:"alerts"`
|
|
Decisions int64 `json:"decisions"`
|
|
LastSeen int64 `json:"lastSeen"`
|
|
}
|
|
|
|
func (s *Store) trafficMapCities(where string, args []any) ([]TrafficMapCity, bool, error) {
|
|
rows, err := s.db.Query(`SELECT ip,country,SUM(kind='request'),SUM(kind='alert'),SUM(kind='decision'),MAX(ts) FROM traffic_events`+where+` GROUP BY ip,country`, args...)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
defer rows.Close()
|
|
groups := map[string]*TrafficMapCity{}
|
|
for rows.Next() {
|
|
var ip, country string
|
|
var requests, alerts, decisions, last int64
|
|
if err = rows.Scan(&ip, &country, &requests, &alerts, &decisions, &last); err != nil {
|
|
return nil, false, err
|
|
}
|
|
g := lookupTrafficCityLocation(ip)
|
|
if !g.Located {
|
|
continue
|
|
}
|
|
key := fmt.Sprintf("%s/%s/%s/%.5f/%.5f", country, g.Region, g.City, g.Latitude, g.Longitude)
|
|
c := groups[key]
|
|
if c == nil {
|
|
c = &TrafficMapCity{TrafficCityLocation: g, Country: country}
|
|
groups[key] = c
|
|
}
|
|
c.Requests += requests
|
|
c.Alerts += alerts
|
|
c.Decisions += decisions
|
|
if requests > 0 {
|
|
c.UniqueIPs++
|
|
}
|
|
if last > c.LastSeen {
|
|
c.LastSeen = last
|
|
}
|
|
}
|
|
if err = rows.Err(); err != nil {
|
|
return nil, false, err
|
|
}
|
|
result := make([]TrafficMapCity, 0, len(groups))
|
|
for _, c := range groups {
|
|
result = append(result, *c)
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
a, b := result[i], result[j]
|
|
x, y := a.Requests+a.Alerts+a.Decisions, b.Requests+b.Alerts+b.Decisions
|
|
if x != y {
|
|
return x > y
|
|
}
|
|
return fmt.Sprint(a.Country, a.Region, a.City, a.Latitude, a.Longitude) < fmt.Sprint(b.Country, b.Region, b.City, b.Latitude, b.Longitude)
|
|
})
|
|
limited := len(result) > 500
|
|
if limited {
|
|
result = result[:500]
|
|
}
|
|
return result, limited, nil
|
|
}
|