Add simple client API, add airport type to API response
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

This commit is contained in:
Ask Bjørn Hansen 2025-01-12 01:12:39 -08:00
parent 54e312dccc
commit 15bc706d7a
5 changed files with 157 additions and 36 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
data data
locationcode /locationcode

View File

@ -10,7 +10,6 @@ import (
"os" "os"
"os/signal" "os/signal"
"path" "path"
"sort"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@ -24,14 +23,9 @@ import (
"go.ntppool.org/common/tracing" "go.ntppool.org/common/tracing"
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho" "go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
)
type Airport struct { "go.askask.com/locationcode/types"
Name string )
Code string
Distance float64
data *alphafoxtrot.Airport
}
type Finder struct { type Finder struct {
f *alphafoxtrot.AirportFinder f *alphafoxtrot.AirportFinder
@ -191,7 +185,7 @@ func main() {
} }
} }
func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude, longitude float64) ([]*Airport, error) { func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude, longitude float64) ([]*types.Airport, error) {
log := logger.FromContext(ctx) log := logger.FromContext(ctx)
log.InfoContext(ctx, fmt.Sprintf("GetAirports(%s %.2f %.4f %.4f)", cc, radiusKM, latitude, longitude)) log.InfoContext(ctx, fmt.Sprintf("GetAirports(%s %.2f %.4f %.4f)", cc, radiusKM, latitude, longitude))
@ -215,39 +209,24 @@ func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude,
airports = append(airports, ap) airports = append(airports, ap)
} }
llCache := map[int]s2.LatLng{} r := []*types.Airport{}
for i, ap := range airports {
ll := s2.LatLngFromDegrees(ap.LatitudeDeg, ap.LongitudeDeg)
llCache[i] = ll
}
r := []*Airport{} for _, airport := range airports {
// fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
for i, airport := range airports { a := types.NewAirport(airport)
fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode) ll := s2.LatLngFromDegrees(airport.LatitudeDeg, airport.LongitudeDeg)
a.Distance = float64(ipLocation.Distance(ll)) * 6371.01
distance := float64(ipLocation.Distance(llCache[i])) * 6371.01
a := &Airport{
Name: airport.Name,
Code: code,
Distance: distance,
data: airport,
}
r = append(r, a) r = append(r, a)
} }
sort.Slice(r, func(i, j int) bool { types.SortAirports(r)
if r[i].data.Type == r[j].data.Type {
return r[i].Distance < r[j].Distance
}
return airports[i].Type < airports[j].Type
})
if len(r) > 15 { maxReturns := 20
r = r[0:15] if len(r) > maxReturns {
r = r[0:maxReturns]
} }
log.InfoContext(ctx, "got airports", "count", len(airportsRaw), "filtered", len(airports), "returning", len(r)) log.InfoContext(ctx, "got airports", "count", len(airportsRaw), "filtered", len(airports), "returning", len(r))

View File

@ -0,0 +1,85 @@
package locationcode
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"os"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.askask.com/locationcode/types"
)
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 GetAirports(ctx context.Context, countryCode string, lat, lng float64, radiusKM float64) ([]*types.Airport, error) {
ctx, span := otel.Tracer("locationcode").Start(ctx, "locationcode.GetAirports")
defer span.End()
baseURL := os.Getenv("locationcode_service")
if len(baseURL) == 0 {
return nil, fmt.Errorf("locationcode_service not configured")
}
q := url.Values{}
q.Set("cc", countryCode)
if radiusKM > 0 {
q.Set("radius", fmt.Sprintf("%f", radiusKM))
}
q.Set("lat", fmt.Sprintf("%f", lat))
q.Set("lng", fmt.Sprintf("%f", lng))
reqURL, err := url.Parse(fmt.Sprintf("http://%s/v1/code?%s", baseURL, q.Encode()))
if err != nil {
span.RecordError(err)
return nil, err
}
span.SetAttributes(attribute.String("url", reqURL.String()))
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()
// io.Copy(os.Stdout, resp.Body)
// return nil, nil
dec := json.NewDecoder(resp.Body)
airports := []*types.Airport{}
err = dec.Decode(&airports)
if err != nil {
span.RecordError(err)
return nil, err
}
return airports, nil
}

2
go.mod
View File

@ -12,6 +12,7 @@ require (
github.com/samber/slog-echo v1.15.0 github.com/samber/slog-echo v1.15.0
go.ntppool.org/common v0.3.1 go.ntppool.org/common v0.3.1
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.58.0 go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.58.0
go.opentelemetry.io/otel v1.33.0
golang.org/x/sync v0.10.0 golang.org/x/sync v0.10.0
) )
@ -44,7 +45,6 @@ require (
go.opentelemetry.io/contrib/bridges/otelslog v0.8.0 // indirect go.opentelemetry.io/contrib/bridges/otelslog v0.8.0 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.58.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.58.0 // indirect
go.opentelemetry.io/contrib/exporters/autoexport v0.58.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.9.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.9.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.9.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.9.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.33.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.33.0 // indirect

57
types/airport_type.go Normal file
View File

@ -0,0 +1,57 @@
package types
import (
"sort"
"strings"
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
)
type Airport struct {
Name string
Code string
Distance float64
Type string
data *alphafoxtrot.Airport
}
func NewAirport(airport *alphafoxtrot.Airport) *Airport {
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
a := &Airport{
Name: airport.Name,
Code: code,
Type: airport.Type,
data: airport,
}
return a
}
func (a *Airport) String() string {
return a.Name
}
func UniqAirports(r []*Airport) []*Airport {
seen := make(map[string]struct{})
j := 0
for _, v := range r {
if _, ok := seen[v.Code]; ok {
continue
}
seen[v.Code] = struct{}{}
r[j] = v
j++
}
return r[:j]
}
func SortAirports(r []*Airport) {
sort.Slice(r, func(i, j int) bool {
if r[i].data.Type == r[j].data.Type {
return r[i].Distance < r[j].Distance
}
return r[i].data.Type < r[j].data.Type
})
}