mirror of
https://github.com/therootcompany/golib.git
synced 2026-04-24 20:58:00 +00:00
refactor(geoip,check-ip): lift download/refresh out of geoip into cmd
geoip.Open now just opens files; download/refresh/polling logic lives at the cmd layer using dataset.Group with a combined httpcache.Cacher fetcher (or PollFiles when no GeoIP.conf is available). Removes geoip.OpenDatabases — the library is no longer concerned with refresh.
This commit is contained in:
parent
d8b6638d97
commit
9b92136f91
@ -37,7 +37,7 @@ type IPCheck struct {
|
||||
|
||||
inbound *dataset.View[ipcohort.Cohort]
|
||||
outbound *dataset.View[ipcohort.Cohort]
|
||||
geo *geoip.Databases
|
||||
geo *dataset.View[geoip.Databases]
|
||||
}
|
||||
|
||||
func printVersion(w *os.File) {
|
||||
@ -103,16 +103,16 @@ func main() {
|
||||
}
|
||||
|
||||
maxmind := filepath.Join(cfg.CacheDir, "maxmind")
|
||||
geo, err := geoip.OpenDatabases(
|
||||
cfg.ConfPath,
|
||||
filepath.Join(maxmind, geoip.CityEdition+".mmdb"),
|
||||
filepath.Join(maxmind, geoip.ASNEdition+".mmdb"),
|
||||
)
|
||||
if err != nil {
|
||||
cityPath := filepath.Join(maxmind, geoip.CityEdition+".mmdb")
|
||||
asnPath := filepath.Join(maxmind, geoip.ASNEdition+".mmdb")
|
||||
geoGroup := dataset.NewGroup(geoFetcher(cfg.ConfPath, cityPath, asnPath))
|
||||
cfg.geo = dataset.Add(geoGroup, func() (*geoip.Databases, error) {
|
||||
return geoip.Open(cityPath, asnPath)
|
||||
})
|
||||
if err := geoGroup.Load(context.Background()); err != nil {
|
||||
log.Fatalf("geoip: %v", err)
|
||||
}
|
||||
defer func() { _ = geo.Close() }()
|
||||
cfg.geo = geo
|
||||
defer func() { _ = cfg.geo.Value().Close() }()
|
||||
|
||||
if cfg.Bind == "" {
|
||||
return
|
||||
@ -121,9 +121,48 @@ func main() {
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
go group.Tick(ctx, refreshInterval, func(err error) {
|
||||
log.Printf("refresh: %v", err)
|
||||
log.Printf("blocklists refresh: %v", err)
|
||||
})
|
||||
go geoGroup.Tick(ctx, refreshInterval, func(err error) {
|
||||
log.Printf("geoip refresh: %v", err)
|
||||
})
|
||||
if err := cfg.serve(ctx); err != nil {
|
||||
log.Fatalf("serve: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// geoFetcher returns a Fetcher for the GeoLite2 City + ASN .mmdb files.
|
||||
// With a GeoIP.conf (explicit path or auto-discovered) both files are
|
||||
// downloaded via httpcache conditional GETs; otherwise the files are
|
||||
// expected to exist on disk and are polled for out-of-band changes.
|
||||
func geoFetcher(confPath, cityPath, asnPath string) dataset.Fetcher {
|
||||
if confPath == "" {
|
||||
for _, p := range geoip.DefaultConfPaths() {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
confPath = p
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if confPath == "" {
|
||||
return dataset.PollFiles(cityPath, asnPath)
|
||||
}
|
||||
conf, err := geoip.ParseConf(confPath)
|
||||
if err != nil {
|
||||
log.Fatalf("geoip-conf: %v", err)
|
||||
}
|
||||
dl := geoip.New(conf.AccountID, conf.LicenseKey)
|
||||
city := dl.NewCacher(geoip.CityEdition, cityPath)
|
||||
asn := dl.NewCacher(geoip.ASNEdition, asnPath)
|
||||
return dataset.FetcherFunc(func() (bool, error) {
|
||||
cityUpdated, err := city.Fetch()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("fetch %s: %w", geoip.CityEdition, err)
|
||||
}
|
||||
asnUpdated, err := asn.Fetch()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("fetch %s: %w", geoip.ASNEdition, err)
|
||||
}
|
||||
return cityUpdated || asnUpdated, nil
|
||||
})
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ func (c *IPCheck) handle(w http.ResponseWriter, r *http.Request) {
|
||||
Blocked: in || out,
|
||||
BlockedInbound: in,
|
||||
BlockedOutbound: out,
|
||||
Geo: c.geo.Lookup(ip),
|
||||
Geo: c.geo.Value().Lookup(ip),
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("format") == "json" ||
|
||||
|
||||
@ -4,8 +4,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
)
|
||||
@ -16,41 +14,6 @@ type Databases struct {
|
||||
ASN *geoip2.Reader
|
||||
}
|
||||
|
||||
// OpenDatabases resolves configuration, downloads stale .mmdb files (when a
|
||||
// GeoIP.conf with credentials is available), and opens the readers.
|
||||
//
|
||||
// - confPath="" → auto-discover from DefaultConfPaths
|
||||
// - conf found → auto-download to cityPath/asnPath
|
||||
// - no conf → cityPath and asnPath must point to existing .mmdb files
|
||||
func OpenDatabases(confPath, cityPath, asnPath string) (*Databases, error) {
|
||||
if confPath == "" {
|
||||
for _, p := range DefaultConfPaths() {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
confPath = p
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if confPath != "" {
|
||||
cfg, err := ParseConf(confPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("geoip-conf: %w", err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(cityPath), 0o755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl := New(cfg.AccountID, cfg.LicenseKey)
|
||||
if _, err := dl.NewCacher(CityEdition, cityPath).Fetch(); err != nil {
|
||||
return nil, fmt.Errorf("fetch %s: %w", CityEdition, err)
|
||||
}
|
||||
if _, err := dl.NewCacher(ASNEdition, asnPath).Fetch(); err != nil {
|
||||
return nil, fmt.Errorf("fetch %s: %w", ASNEdition, err)
|
||||
}
|
||||
}
|
||||
return Open(cityPath, asnPath)
|
||||
}
|
||||
|
||||
// Open opens city and ASN .mmdb files from the given paths.
|
||||
func Open(cityPath, asnPath string) (*Databases, error) {
|
||||
city, err := geoip2.Open(cityPath)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user