1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04:00
Files
DankMaterialShell/core/internal/geolocation/client_ip.go
2026-02-28 00:07:04 -05:00

92 lines
2.0 KiB
Go

package geolocation
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type IpClient struct {
currLocation *Location
}
type ipLocationResult struct {
Location
City string
}
type ipAPIResponse struct {
Status string `json:"status"`
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
City string `json:"city"`
}
func newIpClient() *IpClient {
return &IpClient{
currLocation: &Location{},
}
}
func (c *IpClient) Subscribe(id string) chan Location {
ch := make(chan Location, 1)
if location, err := c.GetLocation(); err == nil {
ch <- location
}
return ch
}
func (c *IpClient) Unsubscribe(id string) {}
func (c *IpClient) Close() {}
func (c *IpClient) GetLocation() (Location, error) {
if c.currLocation.Latitude != 0 || c.currLocation.Longitude != 0 {
return *c.currLocation, nil
}
result, err := fetchIPLocation()
if err != nil {
return Location{}, err
}
c.currLocation.Latitude = result.Latitude
c.currLocation.Longitude = result.Longitude
return *c.currLocation, nil
}
func fetchIPLocation() (ipLocationResult, error) {
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get("http://ip-api.com/json/")
if err != nil {
return ipLocationResult{}, fmt.Errorf("failed to fetch IP location: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return ipLocationResult{}, fmt.Errorf("ip-api.com returned status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return ipLocationResult{}, fmt.Errorf("failed to read response: %w", err)
}
var data ipAPIResponse
if err := json.Unmarshal(body, &data); err != nil {
return ipLocationResult{}, fmt.Errorf("failed to parse response: %w", err)
}
if data.Status == "fail" || (data.Lat == 0 && data.Lon == 0) {
return ipLocationResult{}, fmt.Errorf("ip-api.com returned no location data")
}
return ipLocationResult{
Location: Location{Latitude: data.Lat, Longitude: data.Lon},
City: data.City,
}, nil
}