1
0
Fork 0
timelinize/internal/airports/airports.go
2025-06-19 15:05:18 -06:00

98 lines
2.2 KiB
Go

// This file handles pulling information from the CC 4.0 BY-SA licenced airport location database available at:
// https://github.com/lxndrblz/Airports
package airports
import (
"bytes"
_ "embed"
"encoding/csv"
"fmt"
"io"
"strconv"
"github.com/timelinize/timelinize/timeline"
)
//go:generate curl -L -o airports.csv https://raw.githubusercontent.com/lxndrblz/Airports/master/airports.csv
//go:embed airports.csv
var airportData []byte
type Info struct {
IATA string
Name string
Location timeline.Location
Timezone string
URL string
}
type DB map[string]Info
// Parses the embedded Airport CSV file into a map addressable by the airport IATA code.
// Remember to remove all references to it when you're done, so the Garbage Collector
// can remove it from memory.
func BuildDB() (DB, error) {
db := make(DB)
r := csv.NewReader(bytes.NewReader(airportData))
headers, err := r.Read()
if err != nil {
return db, fmt.Errorf("unable to parse airport db CSV headers: %w", err)
}
headerMap := make(map[string]int)
for i, h := range headers {
headerMap[h] = i
}
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return db, fmt.Errorf("unable to parse airport db CSV: %w", err)
}
if len(record) < len(headers) {
continue
}
lat, latErr := strconv.ParseFloat(record[headerMap[latHeader]], 64)
lng, lngErr := strconv.ParseFloat(record[headerMap[lngHeader]], 64)
if latErr != nil || lngErr != nil {
continue
}
loc := timeline.Location{Latitude: &lat, Longitude: &lng}
if alt, err := strconv.ParseFloat(record[headerMap[altHeader]], 64); err == nil {
loc.Altitude = &alt
}
iata := record[headerMap[iataHeader]]
db[iata] = Info{
IATA: iata,
Name: record[headerMap[nameHeader]],
Location: loc,
Timezone: record[headerMap[tzHeader]],
URL: record[headerMap[urlHeader]],
}
}
return db, nil
}
// Looks up airport information by the provided IATA code.
func (db DB) LookupIATA(iata string) (Info, bool) {
info, ok := db[iata]
return info, ok
}
const (
iataHeader = "code"
nameHeader = "name"
latHeader = "latitude"
lngHeader = "longitude"
altHeader = "elevation"
tzHeader = "time_zone"
urlHeader = "url"
)