mirror of
https://github.com/dcarrillo/whatismyip.git
synced 2025-01-15 20:36:49 +00:00
133 lines
2.6 KiB
Go
133 lines
2.6 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
|
|
"github.com/oschwald/maxminddb-golang"
|
|
)
|
|
|
|
type GeoRecord struct {
|
|
Country struct {
|
|
ISOCode string `maxminddb:"iso_code"`
|
|
Names map[string]string `maxminddb:"names"`
|
|
} `maxminddb:"country"`
|
|
City struct {
|
|
Names map[string]string `maxminddb:"names"`
|
|
} `maxminddb:"city"`
|
|
Location struct {
|
|
Latitude float64 `maxminddb:"latitude"`
|
|
Longitude float64 `maxminddb:"longitude"`
|
|
TimeZone string `maxminddb:"time_zone"`
|
|
} `maxminddb:"location"`
|
|
Postal struct {
|
|
Code string `maxminddb:"code"`
|
|
} `maxminddb:"postal"`
|
|
}
|
|
|
|
type ASNRecord struct {
|
|
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
|
|
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
|
|
}
|
|
|
|
type GeoDB struct {
|
|
cityPath string
|
|
asnPath string
|
|
City *maxminddb.Reader
|
|
ASN *maxminddb.Reader
|
|
}
|
|
|
|
func Setup(cityPath string, asnPath string) (*GeoDB, error) {
|
|
city, asn, err := openDatabases(cityPath, asnPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &GeoDB{
|
|
cityPath: cityPath,
|
|
asnPath: asnPath,
|
|
City: city,
|
|
ASN: asn,
|
|
}, nil
|
|
}
|
|
|
|
func (db *GeoDB) CloseDBs() error {
|
|
var errs []error
|
|
|
|
if db.City != nil {
|
|
if err := db.City.Close(); err != nil {
|
|
errs = append(errs, fmt.Errorf("closing city db: %w", err))
|
|
}
|
|
}
|
|
|
|
if db.ASN != nil {
|
|
if err := db.ASN.Close(); err != nil {
|
|
errs = append(errs, fmt.Errorf("closing ASN db: %w", err))
|
|
}
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
return fmt.Errorf("errors closing databases: %s", errs)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (db *GeoDB) Reload() error {
|
|
if err := db.CloseDBs(); err != nil {
|
|
return fmt.Errorf("closing existing connections: %w", err)
|
|
}
|
|
|
|
city, asn, err := openDatabases(db.cityPath, db.asnPath)
|
|
if err != nil {
|
|
return fmt.Errorf("opening new connections: %w", err)
|
|
}
|
|
|
|
db.City = city
|
|
db.ASN = asn
|
|
return nil
|
|
}
|
|
|
|
func (db *GeoDB) LookupCity(ip net.IP) (*GeoRecord, error) {
|
|
record := &GeoRecord{}
|
|
err := db.City.Lookup(ip, record)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return record, nil
|
|
}
|
|
|
|
func (db *GeoDB) LookupASN(ip net.IP) (*ASNRecord, error) {
|
|
record := &ASNRecord{}
|
|
err := db.ASN.Lookup(ip, record)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return record, nil
|
|
}
|
|
|
|
func openDatabases(cityPath, asnPath string) (*maxminddb.Reader, *maxminddb.Reader, error) {
|
|
city, err := openMMDB(cityPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
asn, err := openMMDB(asnPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return city, asn, nil
|
|
}
|
|
|
|
func openMMDB(path string) (*maxminddb.Reader, error) {
|
|
db, err := maxminddb.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
log.Printf("Database %s has been loaded\n", path)
|
|
|
|
return db, nil
|
|
}
|