Add simple client API, add airport type to API response
This commit is contained in:
parent
54e312dccc
commit
ff64014f5c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
data
|
data
|
||||||
locationcode
|
/locationcode
|
||||||
|
47
airports.go
47
airports.go
@ -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))
|
||||||
|
85
client/locationcode/locationcodeclient.go
Normal file
85
client/locationcode/locationcodeclient.go
Normal 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
2
go.mod
@ -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
57
types/airport_type.go
Normal 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
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user