91 lines
2.4 KiB
Go
91 lines
2.4 KiB
Go
// Package geoip provides IP address geolocation features.
|
|
package geoip
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"code.nonshy.com/nonshy/website/pkg/config"
|
|
"code.nonshy.com/nonshy/website/pkg/utility"
|
|
"github.com/oschwald/geoip2-golang"
|
|
)
|
|
|
|
// GetRequestCity returns the GeoIP City result for the current HTTP request.
|
|
func GetRequestCity(r *http.Request) (*geoip2.City, error) {
|
|
var (
|
|
addr = utility.IPAddress(r)
|
|
ip = net.ParseIP(addr)
|
|
)
|
|
return GetCity(ip)
|
|
}
|
|
|
|
// GetRequestCountryFlag returns the country flag based on the current HTTP request IP address.
|
|
func GetRequestCountryFlag(r *http.Request) (string, error) {
|
|
city, err := GetRequestCity(r)
|
|
if err != nil {
|
|
// If the remote addr is localhost (local dev testing), default to US flag.
|
|
if addr := utility.IPAddress(r); addr == "127.0.0.1" || addr == "::1" {
|
|
return CountryFlagEmoji("US")
|
|
}
|
|
|
|
return "", err
|
|
}
|
|
|
|
return CountryFlagEmoji(city.Country.IsoCode)
|
|
}
|
|
|
|
// GetRequestCountryFlagWithCode returns the flag joined with the country code by a space (like CountryFlagEmojiWithCode).
|
|
func GetRequestCountryFlagWithCode(r *http.Request) (string, error) {
|
|
city, err := GetRequestCity(r)
|
|
if err != nil {
|
|
// If the remote addr is localhost (local dev testing), default to US flag.
|
|
if addr := utility.IPAddress(r); addr == "127.0.0.1" || addr == "::1" {
|
|
return CountryFlagEmojiWithCode("US")
|
|
}
|
|
|
|
return "", err
|
|
}
|
|
|
|
return CountryFlagEmojiWithCode(city.Country.IsoCode)
|
|
}
|
|
|
|
// GetCity queries the GeoIP database for city information for an IP address.
|
|
func GetCity(ip net.IP) (*geoip2.City, error) {
|
|
db, err := geoip2.Open(config.GeoIPPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db.City(ip)
|
|
}
|
|
|
|
// CountryFlagEmoji returns the emoji sequence for a country flag based on
|
|
// the two-letter country code.
|
|
func CountryFlagEmoji(alpha2 string) (string, error) {
|
|
if len(alpha2) != 2 {
|
|
return "", errors.New("country code must be two letters long")
|
|
}
|
|
|
|
alpha2 = strings.ToLower(alpha2)
|
|
|
|
var (
|
|
flagBaseIndex = '\U0001F1E6' - 'a'
|
|
box = func(ch byte) string {
|
|
return string(rune(ch) + flagBaseIndex)
|
|
}
|
|
)
|
|
|
|
return string(box(alpha2[0]) + box(alpha2[1])), nil
|
|
}
|
|
|
|
// CountryFlagEmojiWithCode returns a string consisting of the country flag, a space, and the alpha2 code passed in.
|
|
func CountryFlagEmojiWithCode(alpha2 string) (string, error) {
|
|
if emoji, err := CountryFlagEmoji(alpha2); err != nil {
|
|
return emoji, err
|
|
} else {
|
|
return emoji + " " + alpha2, nil
|
|
}
|
|
}
|