Plot city-level traffic activity from local GeoIP coordinates
This commit is contained in:
71
traffic_map_cities.go
Normal file
71
traffic_map_cities.go
Normal file
@@ -0,0 +1,71 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user