package util import ( "encoding/json" "log" "net" "net/http" "strings" ) type LocationResult struct { Country string `json:"country"` Region string `json:"regionName"` City string `json:"city"` } func GetLocation(ip string) (LocationResult, error) { var loc LocationResult // Example using ipinfo.io free API resp, err := http.Get("http://ip-api.com/json/" + ip + "?fields=25") if err != nil { return loc, err } defer resp.Body.Close() json.NewDecoder(resp.Body).Decode(&loc) return loc, nil } func GetClientIP(r *http.Request) string { // This header will be set by ngrok to the original client IP if xff := r.Header.Get("X-Forwarded-For"); xff != "" { log.Printf("DEBUG: Getting IP from X-Forwarded-For: %s\n", xff) // X-Forwarded-For: client, proxy1, proxy2, ... ips := strings.Split(xff, ",") if len(ips) > 0 { return strings.TrimSpace(ips[0]) } } // Fallback to RemoteAddr (not the real client IP, but just in case) host, _, err := net.SplitHostPort(r.RemoteAddr) log.Printf("DEBUG: Falling to request remote addr: %s (%s)\n", host, r.RemoteAddr) if err != nil { return r.RemoteAddr } return host }