Compare commits
No commits in common. "main" and "v1.0.1" have entirely different histories.
@ -1,11 +1,10 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: kubernetes
|
type: kubernetes
|
||||||
name: default
|
name: default
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: test
|
- name: test
|
||||||
image: golang:1.24
|
image: golang:1.18
|
||||||
volumes:
|
volumes:
|
||||||
- name: deps
|
- name: deps
|
||||||
path: /go
|
path: /go
|
||||||
@ -29,8 +28,3 @@ steps:
|
|||||||
from_secret: harbor_library_username
|
from_secret: harbor_library_username
|
||||||
password:
|
password:
|
||||||
from_secret: harbor_library_password
|
from_secret: harbor_library_password
|
||||||
---
|
|
||||||
kind: signature
|
|
||||||
hmac: d2fe2afd7d16e5530e00f268db9e381b980cddbc1bc11287c223fb1a9a6fa894
|
|
||||||
|
|
||||||
...
|
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
data
|
data
|
||||||
/locationcode
|
locationcode
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.24-alpine3.21 AS build
|
FROM golang:1.18-alpine3.15 AS build
|
||||||
RUN apk --no-cache add git
|
RUN apk --no-cache add git
|
||||||
|
|
||||||
WORKDIR /go/src/
|
WORKDIR /go/src/
|
||||||
@ -6,10 +6,9 @@ ADD . /go/src/
|
|||||||
RUN go install -v ./...
|
RUN go install -v ./...
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.21
|
FROM alpine:3.15
|
||||||
USER root
|
USER root
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates
|
||||||
RUN apk --no-cache upgrade
|
|
||||||
|
|
||||||
RUN addgroup lc && adduser -D -G lc lc
|
RUN addgroup lc && adduser -D -G lc lc
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
217
airports.go
217
airports.go
@ -1,52 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path"
|
"path"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang/geo/s2"
|
"github.com/golang/geo/s2"
|
||||||
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
|
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
slogecho "github.com/samber/slog-echo"
|
"github.com/labstack/echo/v4/middleware"
|
||||||
"go.ntppool.org/common/logger"
|
|
||||||
"go.ntppool.org/common/tracing"
|
|
||||||
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
|
|
||||||
"go.askask.com/locationcode/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Finder struct {
|
type Airport struct {
|
||||||
f *alphafoxtrot.AirportFinder
|
Name string
|
||||||
|
Code string
|
||||||
|
Distance float64
|
||||||
|
data *alphafoxtrot.Airport
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log := logger.Setup()
|
|
||||||
|
|
||||||
dataDir := flag.String("data-dir", "./data", "Data cache directory")
|
var dataDir = flag.String("data-dir", "./data", "Data cache directory")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
err := validateData(*dataDir)
|
validateData(*dataDir)
|
||||||
if err != nil {
|
|
||||||
log.Error("data error", "err", err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
finder := &Finder{
|
finder := alphafoxtrot.NewAirportFinder()
|
||||||
f: alphafoxtrot.NewAirportFinder(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOptions come with preset filepaths
|
// LoadOptions come with preset filepaths
|
||||||
options := alphafoxtrot.PresetLoadOptions(*dataDir)
|
options := alphafoxtrot.PresetLoadOptions(*dataDir)
|
||||||
@ -55,95 +41,35 @@ func main() {
|
|||||||
filter := alphafoxtrot.AirportTypeRunways
|
filter := alphafoxtrot.AirportTypeRunways
|
||||||
|
|
||||||
// Load the data into memory
|
// Load the data into memory
|
||||||
if err := finder.f.Load(options, filter); len(err) > 0 {
|
if err := finder.Load(options, filter); len(err) > 0 {
|
||||||
log.Error("finder load error", "err", err)
|
log.Println("errors:", err)
|
||||||
}
|
|
||||||
|
|
||||||
if args := flag.Args(); len(args) > 0 {
|
|
||||||
if len(args) != 4 {
|
|
||||||
fmt.Printf("[cc] [lat] [lng] [radius]\n")
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
cc := strings.ToUpper(args[0])
|
|
||||||
|
|
||||||
latitude, err := strconv.ParseFloat(args[1], 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("could not parse %s as latitude: %s", args[1], err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
longitude, err := strconv.ParseFloat(args[2], 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("could not parse %s as longitude: %s", args[2], err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
radiusKM, err := strconv.ParseFloat(args[3], 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("could not parse %s as radius: %s", args[3], err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
airports, err := finder.GetAirports(context.Background(), cc, radiusKM, latitude, longitude)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("GetAirports error: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, a := range airports {
|
|
||||||
fmt.Printf("%s\t%s (%0f)\n", a.Code, a.Name, a.Distance)
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
tpShutdown, err := tracing.InitTracer(ctx, &tracing.TracerConfig{
|
|
||||||
ServiceName: "locationcode",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Error("could not initialize tracer", "err", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
e.Use(otelecho.Middleware("locationcode"))
|
|
||||||
|
|
||||||
e.Use(slogecho.NewWithConfig(log,
|
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||||
slogecho.Config{
|
Skipper: func(c echo.Context) bool {
|
||||||
WithTraceID: false, // done by logger already
|
return c.Request().URL.Path == "/" || c.Request().URL.Path == "/__healthz"
|
||||||
DefaultLevel: slog.LevelInfo,
|
|
||||||
ClientErrorLevel: slog.LevelWarn,
|
|
||||||
ServerErrorLevel: slog.LevelError,
|
|
||||||
// WithRequestHeader: true,
|
|
||||||
|
|
||||||
Filters: []slogecho.Filter{
|
|
||||||
func(c echo.Context) bool {
|
|
||||||
return !(c.Request().URL.Path == "/" || c.Request().URL.Path == "/__healthz")
|
|
||||||
},
|
},
|
||||||
},
|
}))
|
||||||
},
|
|
||||||
))
|
|
||||||
|
|
||||||
e.GET("/", func(c echo.Context) error {
|
e.GET("/", func(c echo.Context) error {
|
||||||
return c.String(http.StatusOK, "location code service")
|
return c.String(http.StatusOK, "location code service")
|
||||||
})
|
})
|
||||||
e.GET("/v1/code", func(c echo.Context) error {
|
e.GET("/v1/code", func(c echo.Context) error {
|
||||||
ctx := c.Request().Context()
|
|
||||||
countryISOCode := c.QueryParam("cc")
|
countryISOCode := c.QueryParam("cc")
|
||||||
countryISOCode = strings.ToUpper(countryISOCode)
|
countryISOCode = strings.ToUpper(countryISOCode)
|
||||||
|
|
||||||
radiusString := c.QueryParam("radius")
|
radiusString := c.QueryParam("radius")
|
||||||
|
|
||||||
var radiusKM float64
|
var radiusKM int
|
||||||
if len(radiusString) > 0 {
|
if len(radiusString) > 0 {
|
||||||
radiusKM, _ = strconv.ParseFloat(radiusString, 64)
|
radiusKM, _ = strconv.Atoi(radiusString)
|
||||||
}
|
}
|
||||||
|
|
||||||
if radiusKM < 150 {
|
if radiusKM < 10 {
|
||||||
radiusKM = 150
|
radiusKM = 100
|
||||||
} else {
|
|
||||||
radiusKM = radiusKM * 1.5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
latitude, longitude, err := getLatLng(c)
|
latitude, longitude, err := getLatLng(c)
|
||||||
@ -151,55 +77,11 @@ func main() {
|
|||||||
return c.String(http.StatusBadRequest, fmt.Sprintf("invalid lat or lng: %s", err))
|
return c.String(http.StatusBadRequest, fmt.Sprintf("invalid lat or lng: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
airports, err := finder.GetAirports(ctx, countryISOCode, radiusKM, latitude, longitude)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, airports)
|
|
||||||
})
|
|
||||||
|
|
||||||
errg, ctx := errgroup.WithContext(ctx)
|
|
||||||
|
|
||||||
errg.Go(func() error {
|
|
||||||
return e.Start(":8520")
|
|
||||||
})
|
|
||||||
|
|
||||||
errg.Go(func() error {
|
|
||||||
<-ctx.Done()
|
|
||||||
log.InfoContext(ctx, "shutting down server")
|
|
||||||
return e.Shutdown(ctx)
|
|
||||||
})
|
|
||||||
|
|
||||||
err = errg.Wait()
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
log.ErrorContext(ctx, "server error", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shutdownCtx, shCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer shCancel()
|
|
||||||
if err := tpShutdown(shutdownCtx); err != nil {
|
|
||||||
log.ErrorContext(shutdownCtx, "failed to shutdown tracer", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude, longitude float64) ([]*types.Airport, error) {
|
|
||||||
log := logger.FromContext(ctx)
|
|
||||||
log.InfoContext(ctx, fmt.Sprintf("GetAirports(%s %.2f %.4f %.4f)", cc, radiusKM, latitude, longitude))
|
|
||||||
|
|
||||||
ipLocation := s2.LatLngFromDegrees(latitude, longitude)
|
ipLocation := s2.LatLngFromDegrees(latitude, longitude)
|
||||||
|
|
||||||
maxResults := 500 // some countries have a lot of airports without local codes
|
maxResults := 100
|
||||||
radiusInMeters := radiusKM * 1000
|
radiusInMeters := float64(radiusKM) * 1000
|
||||||
airportsRaw := f.f.FindNearestAirportsByCountry(
|
airportsRaw := finder.FindNearestAirportsByCountry(countryISOCode, latitude, longitude, radiusInMeters, maxResults, filter)
|
||||||
cc,
|
|
||||||
latitude, longitude,
|
|
||||||
radiusInMeters,
|
|
||||||
maxResults,
|
|
||||||
alphafoxtrot.AirportTypeAll, // filtered at load time
|
|
||||||
)
|
|
||||||
|
|
||||||
airports := []*alphafoxtrot.Airport{}
|
airports := []*alphafoxtrot.Airport{}
|
||||||
for _, ap := range airportsRaw {
|
for _, ap := range airportsRaw {
|
||||||
@ -209,32 +91,51 @@ func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude,
|
|||||||
airports = append(airports, ap)
|
airports = append(airports, ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
r := []*types.Airport{}
|
llCache := map[int]s2.LatLng{}
|
||||||
|
for i, ap := range airports {
|
||||||
|
ll := s2.LatLngFromDegrees(ap.LatitudeDeg, ap.LongitudeDeg)
|
||||||
|
llCache[i] = ll
|
||||||
|
}
|
||||||
|
|
||||||
for _, airport := range airports {
|
r := []*Airport{}
|
||||||
|
|
||||||
|
for i, airport := range airports {
|
||||||
// fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
|
// fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
|
||||||
|
|
||||||
a := types.NewAirport(airport)
|
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
|
||||||
|
|
||||||
ll := s2.LatLngFromDegrees(airport.LatitudeDeg, airport.LongitudeDeg)
|
distance := float64(ipLocation.Distance(llCache[i])) * 6371.01
|
||||||
a.Distance = float64(ipLocation.Distance(ll)) * 6371.01
|
|
||||||
|
|
||||||
|
a := &Airport{
|
||||||
|
Name: airport.Name,
|
||||||
|
Code: code,
|
||||||
|
Distance: distance,
|
||||||
|
data: airport,
|
||||||
|
}
|
||||||
r = append(r, a)
|
r = append(r, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
types.SortAirports(r)
|
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 airports[i].Type < airports[j].Type
|
||||||
|
})
|
||||||
|
|
||||||
maxReturns := 20
|
if len(r) > 10 {
|
||||||
if len(r) > maxReturns {
|
r = r[0:10]
|
||||||
r = r[0:maxReturns]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.InfoContext(ctx, "got airports", "count", len(airportsRaw), "filtered", len(airports), "returning", len(r))
|
fmt.Printf("got %d airports, filtered to %d, returning %d\n", len(airportsRaw), len(airports), len(r))
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
e.Logger.Fatal(e.Start(":8000"))
|
||||||
|
|
||||||
return r, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateData(dataDir string) error {
|
func validateData(dataDir string) {
|
||||||
downloadFiles := false
|
downloadFiles := false
|
||||||
for _, filename := range alphafoxtrot.OurAirportsFiles {
|
for _, filename := range alphafoxtrot.OurAirportsFiles {
|
||||||
filepath := path.Join(dataDir, filename)
|
filepath := path.Join(dataDir, filename)
|
||||||
@ -245,12 +146,8 @@ func validateData(dataDir string) error {
|
|||||||
}
|
}
|
||||||
if downloadFiles {
|
if downloadFiles {
|
||||||
fmt.Println("Downloading CSV files from OurAirports.com...")
|
fmt.Println("Downloading CSV files from OurAirports.com...")
|
||||||
err := DownloadDatabase(dataDir)
|
alphafoxtrot.DownloadDatabase(dataDir)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLatLng(c echo.Context) (float64, float64, error) {
|
func getLatLng(c echo.Context) (float64, float64, error) {
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
|
|
||||||
"github.com/grumpypixel/go-webget"
|
|
||||||
)
|
|
||||||
|
|
||||||
// const downloadBaseURL = alphafoxtrot.OurAirportsBaseURL
|
|
||||||
// const downloadBaseURL = "https://tmp.askask.com/os/ourairports/"
|
|
||||||
|
|
||||||
// https://github.com/davidmegginson/ourairports-data
|
|
||||||
const downloadBaseURL = "https://davidmegginson.github.io/ourairports-data/"
|
|
||||||
|
|
||||||
// Download csv files from OurAirports.com
|
|
||||||
func DownloadDatabase(targetDir string) error {
|
|
||||||
files := make([]string, 0)
|
|
||||||
for _, filename := range alphafoxtrot.OurAirportsFiles {
|
|
||||||
files = append(files, downloadBaseURL+filename)
|
|
||||||
}
|
|
||||||
var errs []error
|
|
||||||
for _, url := range files {
|
|
||||||
options := webget.Options{
|
|
||||||
ProgressHandler: MyProgress{},
|
|
||||||
Timeout: time.Second * 60,
|
|
||||||
CreateTargetDir: true,
|
|
||||||
}
|
|
||||||
err := webget.DownloadToFile(url, targetDir, "", &options)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MyProgress struct{}
|
|
||||||
|
|
||||||
func (p MyProgress) Start(sourceURL string) {
|
|
||||||
// fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p MyProgress) Update(sourceURL string, percentage float64, bytesRead, contentLength int64) {
|
|
||||||
if percentage > 0 {
|
|
||||||
fmt.Printf("\rDownloading %s: %v bytes [%.2f%%]", path.Base(sourceURL), bytesRead, percentage)
|
|
||||||
}
|
|
||||||
fmt.Printf("\rDownloading %s: %v bytes [done]", path.Base(sourceURL), bytesRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p MyProgress) Done(sourceURL string) {
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
77
go.mod
77
go.mod
@ -1,73 +1,24 @@
|
|||||||
module go.askask.com/locationcode
|
module go.askask.com/locationcode
|
||||||
|
|
||||||
go 1.24
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551
|
||||||
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b
|
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b
|
||||||
github.com/grumpypixel/go-webget v0.0.1
|
github.com/labstack/echo/v4 v4.7.2
|
||||||
github.com/labstack/echo/v4 v4.13.3
|
|
||||||
github.com/samber/slog-echo v1.16.1
|
|
||||||
go.ntppool.org/common v0.3.1
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0
|
|
||||||
go.opentelemetry.io/otel v1.35.0
|
|
||||||
golang.org/x/sync v0.13.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/grumpypixel/go-webget v0.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/labstack/gommon v0.3.1 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
|
||||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
|
||||||
github.com/prometheus/common v0.63.0 // indirect
|
|
||||||
github.com/prometheus/procfs v0.16.0 // indirect
|
|
||||||
github.com/remychantenay/slog-otel v1.3.3 // indirect
|
|
||||||
github.com/samber/lo v1.49.1 // indirect
|
|
||||||
github.com/samber/slog-multi v1.4.0 // indirect
|
|
||||||
github.com/spf13/cobra v1.9.1 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0 // indirect
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0 // indirect
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 // indirect
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.57.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/log v0.11.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/sdk/log v0.11.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
|
||||||
golang.org/x/crypto v0.37.0 // indirect
|
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
|
||||||
golang.org/x/net v0.39.0 // indirect
|
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
|
||||||
golang.org/x/text v0.24.0 // indirect
|
|
||||||
golang.org/x/time v0.11.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
|
|
||||||
google.golang.org/grpc v1.71.1 // indirect
|
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
|
||||||
)
|
)
|
||||||
|
183
go.sum
183
go.sum
@ -1,153 +1,52 @@
|
|||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
|
||||||
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7 h1:HNykSFq2QowNxC/zZc1IEbRuj30sMiY4aCSLb4EK/zA=
|
|
||||||
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7/go.mod h1:J+F9/3Ofc8ysEOY2/cNjxTMl2eB1gvPIywEHUplPgDA=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
|
||||||
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b h1:CAT7j8NnDTijm+Mqc49PowzRwffiQwoNTdacBtAaPac=
|
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b h1:CAT7j8NnDTijm+Mqc49PowzRwffiQwoNTdacBtAaPac=
|
||||||
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b/go.mod h1:VSzLdQ8TugVDF/ZqngnVa/4budj2JLbC3spdz4eKEd4=
|
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b/go.mod h1:VSzLdQ8TugVDF/ZqngnVa/4budj2JLbC3spdz4eKEd4=
|
||||||
github.com/grumpypixel/go-webget v0.0.1 h1:JByEaxRKMK3ACvARJCMva1Tb+mKmZPpIDF9gcgf42OU=
|
github.com/grumpypixel/go-webget v0.0.1 h1:JByEaxRKMK3ACvARJCMva1Tb+mKmZPpIDF9gcgf42OU=
|
||||||
github.com/grumpypixel/go-webget v0.0.1/go.mod h1:TZ3kzdKP644McT9EqfvX6vRcnoKxAGNJVbUGfDCgbpA=
|
github.com/grumpypixel/go-webget v0.0.1/go.mod h1:TZ3kzdKP644McT9EqfvX6vRcnoKxAGNJVbUGfDCgbpA=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
|
||||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
|
||||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
|
||||||
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
|
||||||
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
|
||||||
github.com/remychantenay/slog-otel v1.3.3 h1:Atk1p630QPgYFW4/YEyBuObNmwrYpx5Tglnl1sdhSVA=
|
|
||||||
github.com/remychantenay/slog-otel v1.3.3/go.mod h1:OMdQAB/S2341nbz2Ramh3+RH2yYGLJLspTaghiCToTU=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
|
||||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
|
||||||
github.com/samber/slog-echo v1.16.1 h1:5Q5IUROkFqKcu/qJM/13AP1d3gd1RS+Q/4EvKQU1fuo=
|
|
||||||
github.com/samber/slog-echo v1.16.1/go.mod h1:f+B3WR06saRXcaGRZ/I/UPCECDPqTUqadRIf7TmyRhI=
|
|
||||||
github.com/samber/slog-multi v1.4.0 h1:pwlPMIE7PrbTHQyKWDU+RIoxP1+HKTNOujk3/kdkbdg=
|
|
||||||
github.com/samber/slog-multi v1.4.0/go.mod h1:FsQ4Uv2L+E/8TZt+/BVgYZ1LoDWCbfCU21wVIoMMrO8=
|
|
||||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
|
||||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
go.ntppool.org/common v0.3.1 h1:JaJpS3m8oAc9jH0yhHYJnjOC+RUzxx/F+EDe0QON4eQ=
|
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||||
go.ntppool.org/common v0.3.1/go.mod h1:1SKjFBH9AL7Fj2S0zy41isHzV6dTC+6yIKD5QDtX8aY=
|
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0 h1:lRKWBp9nWoBe1HKXzc3ovkro7YZSb72X2+3zYNxfXiU=
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0/go.mod h1:D+iyUv/Wxbw5LUDO5oh7x744ypftIryiWjoj42I6EKs=
|
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0 h1:x7sPooQCwSg27SjtQee8GyIIRTQcF4s7eSkac6F2+VA=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0/go.mod h1:4K5UXgiHxV484efGs42ejD7E2J/sIlepYgdGoPXe7hE=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 h1:GuQXpvSXNjpswpweIem84U9BNauqHHi2w1GtNAalvpM=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0/go.mod h1:CkmxekdHco4d7thFJNPQ7Mby4jMBgZUclnrxT4e+ryk=
|
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0 h1:vmDg6SXfGUXSkivp53zPNWbmqFBz5P+DBHlf3PROB9E=
|
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0/go.mod h1:ZluigSzu/knqjPvUvb3B9LZSAYxus3my2d0kyaiJuxA=
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ=
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 h1:HMUytBT3uGhPKYY/u/G5MR9itrlSO2SMOsSD3Tk3k7A=
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0/go.mod h1:hdDXsiNLmdW/9BF2jQpnHHlhFajpWCEYfM6e5m2OAZg=
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0 h1:C/Wi2F8wEmbxJ9Kuzw/nhP+Z9XaHYMkyDmXy6yR2cjw=
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0/go.mod h1:0Lr9vmGKzadCTgsiBydxr6GEZ8SsZ7Ks53LzjWG5Ar4=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 h1:0NIXxOCFx+SKbhCVxwl3ETG8ClLPAa0KuKV6p3yhxP8=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0/go.mod h1:ChZSJbbfbl/DcRZNc9Gqh6DYGlfjw4PvO1pEOZH1ZsE=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.57.0 h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
|
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0 h1:k6KdfZk72tVW/QVZf60xlDziDvYAePj5QHwoQvrB2m8=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0/go.mod h1:5Y3ZJLqzi/x/kYtrSrPSx7TFI/SGsL7q2kME027tH6I=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 h1:T0Ec2E+3YZf5bgTNQVet8iTDW7oIk03tXHq+wkwIDnE=
|
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0/go.mod h1:30v2gqH+vYGJsesLWFov8u47EpYTcIQcBjKpI6pJThg=
|
|
||||||
go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y=
|
|
||||||
go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc=
|
|
||||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
|
||||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
|
||||||
go.opentelemetry.io/otel/sdk/log v0.11.0 h1:7bAOpjpGglWhdEzP8z0VXc4jObOiDEwr3IYbhBnjk2c=
|
|
||||||
go.opentelemetry.io/otel/sdk/log v0.11.0/go.mod h1:dndLTxZbwBstZoqsJB3kGsRPkpAgaJrWfQg3lhlHFFY=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
|
||||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
|
||||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
|
||||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
|
||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
|
||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
|
||||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
|
||||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a h1:OQ7sHVzkx6L57dQpzUS4ckfWJ51KDH74XHTDe23xWAs=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a/go.mod h1:2R6XrVC8Oc08GlNh8ujEpc7HkLiEZ16QeY7FxIs20ac=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a h1:GIqLhp/cYUkuGuiT+vJk8vhOP86L4+SP5j8yXgeVpvI=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
|
||||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
|
||||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Airport struct {
|
|
||||||
Name string
|
|
||||||
Code string
|
|
||||||
Distance float64
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAirport(airport *alphafoxtrot.Airport) *Airport {
|
|
||||||
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
|
|
||||||
|
|
||||||
a := &Airport{
|
|
||||||
Name: airport.Name,
|
|
||||||
Code: code,
|
|
||||||
Type: airport.Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
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].Type == r[j].Type {
|
|
||||||
return r[i].Distance < r[j].Distance
|
|
||||||
}
|
|
||||||
return r[i].Type < r[j].Type
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user