package geo import ( "errors" "fmt" "strings" ) // ErrInvalidIP is returned when an IP cannot be parsed. var ErrInvalidIP = errors.New("invalid ip address") // ErrNotFound is returned when a backend cannot resolve the IP. var ErrNotFound = errors.New("location not found") type Backend string const ( BackendMMDB Backend = "mmdb" BackendPostgres Backend = "postgres" ) type Config struct { Backend Backend MMDBPath string DatabaseURL string LookupQuery string } type Resolver interface { Lookup(string) (Location, error) Close() error } type Location struct { IP string Country string Region string City string Address string Latitude float64 Longitude float64 } func NewResolver(cfg Config) (Resolver, error) { switch cfg.Backend { case "", BackendMMDB: return newMMDBResolver(cfg.MMDBPath) case BackendPostgres: return newPostgresResolver(cfg.DatabaseURL, cfg.LookupQuery) default: return nil, fmt.Errorf("unsupported backend %q", cfg.Backend) } } func buildAddress(parts ...string) string { addressParts := make([]string, 0, len(parts)) for _, part := range parts { if part != "" { addressParts = append(addressParts, part) } } return strings.Join(addressParts, ", ") }