package main import ( "encoding/json" "fmt" "io" "log/slog" "net" "net/http" "os" "text/template" "github.com/joho/godotenv" ) type ipResponse struct { IP string `json:"ip"` Asn string `json:"asn"` AsName string `json:"as_name"` AsDomain string `json:"as_domain"` CountryCode string `json:"country_code"` Country string `json:"country"` ContinentCode string `json:"continent_code"` Continent string `json:"continent"` } type IPInfo struct { Query string `json:"query"` Status string `json:"status"` Country string `json:"country"` CountryCode string `json:"countryCode"` Region string `json:"region"` RegionName string `json:"regionName"` City string `json:"city"` Zip string `json:"zip"` Lat float64 `json:"lat"` Lon float64 `json:"lon"` Timezone string `json:"timezone"` ISP string `json:"isp"` Org string `json:"org"` AS string `json:"as"` } type TemolateData struct { Ip ipResponse IP2 IPInfo } func main() { mux := http.NewServeMux() godotenv.Load() // routes mux.HandleFunc("/", handleRoot) mux.HandleFunc("/robots.txt", serveRobots) mux.HandleFunc("/*", handleRoot) mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) fmt.Println("listening on 8080") http.ListenAndServe(":8080", mux) } // Routes func handleRoot(w http.ResponseWriter, r *http.Request) { templ, err := template.ParseFiles("templates/home.html") if err != nil { http.Error(w, "template not found", http.StatusInternalServerError) return } host := r.Header.Get("CF-Connecting-IP") if host == "" { host = r.Header.Get("X-Real-IP") } if host == "" { host = r.Header.Get("X-Forwarded-For") } if host == "" { host, _, _ = net.SplitHostPort(r.RemoteAddr) } dox := callApi(host) dox2 := secondApi(host) templ.Execute(w, TemolateData{Ip: dox, IP2: *dox2}) } func serveRobots(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, ("templates/robots.txt")) } // utils func callApi(ip string) ipResponse { api := os.Getenv("IPAPI") slog.Info("client called", "ip", ip) var values ipResponse if api == " " { slog.Error("No api provided") return values } url := fmt.Sprintf("https://api.ipinfo.io/lite/%s?token=%s", ip, api) request, err := http.Get(url) if err != nil { slog.Error("callApi Error") return values } defer request.Body.Close() body, _ := io.ReadAll(request.Body) err = json.Unmarshal(body, &values) return values } func secondApi(ip string) *IPInfo { url := fmt.Sprintf("http://ip-api.com/json/%s", ip) var res IPInfo response, err := http.Get(url) if err != nil { slog.Error("secondApi err") return &res } defer response.Body.Close() body, _ := io.ReadAll(response.Body) json.Unmarshal(body, &res) slog.Debug("secondApi", "city", res.City, "lat", res.Lat, "lon", res.Lon, "status", res.Status) return &res }