diff --git a/.gitignore b/.gitignore index 2a3d09c..12593f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -geoipapi +./geoipapi *~ \ No newline at end of file diff --git a/client/geoipapi/geoipclient.go b/client/geoipapi/geoipclient.go new file mode 100644 index 0000000..6531575 --- /dev/null +++ b/client/geoipapi/geoipclient.go @@ -0,0 +1,77 @@ +package geoipapi + +import ( + "context" + "encoding/json" + "fmt" + "net" + "net/http" + "net/netip" + "net/url" + "os" + "time" + + "github.com/oschwald/geoip2-golang" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" +) + +var client http.Client + +func init() { + netTransport := &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 5 * time.Second, + }).Dial, + TLSHandshakeTimeout: 5 * time.Second, + } + client = http.Client{ + Timeout: time.Second * 10, + Transport: netTransport, + } +} + +func GetCity(ctx context.Context, ip netip.Addr) (*geoip2.City, error) { + ctx, span := otel.Tracer("geoipapi").Start(ctx, "geoip.GetCity") + defer span.End() + + baseURL := os.Getenv("geoip_service") + if len(baseURL) == 0 { + return nil, fmt.Errorf("geoip_service not configured") + } + + q := url.Values{} + q.Set("ip", ip.String()) + + span.SetAttributes(attribute.String("ip", ip.String())) + + reqURL, err := url.Parse(fmt.Sprintf("http://%s/api/json?%s", baseURL, q.Encode())) + if err != nil { + span.RecordError(err) + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil) + if err != nil { + span.RecordError(err) + return nil, err + } + + resp, err := client.Do(req) + if err != nil { + span.RecordError(err) + return nil, err + } + defer resp.Body.Close() + + dec := json.NewDecoder(resp.Body) + + city := geoip2.City{} + err = dec.Decode(&city) + if err != nil { + span.RecordError(err) + return nil, err + } + + return &city, nil +}