package yaml import ( "errors" "fmt" "io" "os" "strings" "sync" "time" "airlines/pkg/airports" "airlines/pkg/model" "github.com/schollz/progressbar/v3" "gopkg.in/yaml.v3" ) type FareInfo struct { Class string `yaml:"CLASS" json:"class"` Fare string `yaml:"FARE" json:"fare"` } type Flight struct { FF map[string]FareInfo `yaml:"FF" json:"ff"` From string `yaml:"FROM" json:"from"` Status string `yaml:"STATUS" json:"status"` To string `yaml:"TO" json:"to"` } type Schedule struct { data map[string]map[string]Flight } func ParseSchedule(r io.Reader) (*Schedule, error) { s := &Schedule{ data: make(map[string]map[string]Flight), } dec := yaml.NewDecoder(r) // dec.KnownFields(true) // strict field checking if err := dec.Decode(&s.data); err != nil { return nil, err } for date, flights := range s.data { if flights == nil { s.data[date] = map[string]Flight{} } } return s, nil } func UnmarshallYaml(path string) (*Schedule, error) { f, err := os.Open(path) if err != nil { return nil, err } sched, err := ParseSchedule(f) if err != nil { return nil, err } // for date, flights := range sched.data { // fmt.Printf("Date: %s (flights: %d)\n", date, len(flights)) // for flightNo, fl := range flights { // fmt.Printf(" %s: %s -> %s, %s\n", flightNo, fl.From, fl.To, fl.Status) // for ffKey, fi := range fl.FF { // fmt.Printf(" FF %s: class=%s fare=%s\n", ffKey, fi.Class, fi.Fare) // } // } // } // if b, err := json.MarshalIndent(sched, "", " "); err == nil { // fmt.Println("\nAs JSON:") // fmt.Println(string(b)) // } return sched, nil } func createFlight(num, from, to, date string, cardID uint64) (*model.Flight, error) { f := &model.Flight{ Number: num, From: from, To: to, } ap, _ := airports.LookupIATA(f.From) f.FromCoords.Lat = ap.Latitude f.FromCoords.Long = ap.Longitude d, err := time.Parse("2006-01-02", strings.TrimSpace(date)) if err != nil { return nil, fmt.Errorf("invalid Date %q: %w", date, err) } loc := model.TzFromAirportRecord(ap) departLocal := time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, loc) f.Date = departLocal.UTC() ap, _ = airports.LookupIATA(f.To) f.ToCoords.Lat = ap.Latitude f.ToCoords.Long = ap.Longitude return f, nil } func createCard(info string) (*model.Card, error) { prefix, number, _ := model.ParseCardLine(info) if prefix == "" && number == 0 { return nil, errors.New("bad card id") } return &model.Card{ Prefix: prefix, Number: number, }, nil } func (s *Schedule) DumpToDb(store model.Store) error { // var err error count := int64(0) for i := range s.data { count += int64(len(s.data[i])) } bar := progressbar.Default(count, "dumping yaml flights") for date := range s.data { for flightID, flightInfo := range s.data[date] { // fmt.Printf("%+v %+v %+v\n", date, flightID, flightInfo) var wg sync.WaitGroup sem := make(chan struct{}, 8) for cardID := range flightInfo.FF { wg.Add(1) sem <- struct{}{} go func() { defer func() { <-sem }() defer wg.Done() defer bar.Add(1) card, err := createCard(cardID) if err != nil { fmt.Println(err) // return } if card != nil { card, err = store.SaveCard(card) if err != nil { fmt.Println(err) // return } } f, err := createFlight(flightID, flightInfo.From, flightInfo.To, date, card.ID) if err != nil { fmt.Println(err) return } if card != nil { f.UserID = card.UserID } if f != nil { _, err = store.SaveFlight(f) if err != nil { fmt.Println(err) return } } }() } wg.Wait() } } return nil }