github.com/derat/nup@v0.0.0-20230418113745-15592ba7c620/cmd/nup/update/json.go (about) 1 // Copyright 2020 Daniel Erat. 2 // All rights reserved. 3 4 package update 5 6 import ( 7 "encoding/json" 8 "io" 9 "os" 10 11 "github.com/derat/nup/server/db" 12 ) 13 14 // readSongsFromJSONFile JSON-unmarshals db.Song objects from path and 15 // asynchronously sends them to ch. The total number of songs is returned. 16 func readSongsFromJSONFile(path string, ch chan songOrErr) (int, error) { 17 f, err := os.Open(path) 18 if err != nil { 19 return 0, err 20 } 21 defer f.Close() 22 23 // This interface is dumb. We need to return the total number of songs, 24 // but we also need to send the songs to the channel asynchronously to 25 // avoid blocking. Reading all the songs into memory seems like the 26 // best way to handle this. This function previously started a goroutine 27 // for each song, but that results in songs getting sent in an arbitrary 28 // order instead of the order in the file. 29 var songs []db.Song 30 d := json.NewDecoder(f) 31 for { 32 var s db.Song 33 if err = d.Decode(&s); err == io.EOF { 34 break 35 } else if err != nil { 36 return 0, err 37 } 38 songs = append(songs, s) 39 } 40 41 go func() { 42 for i := range songs { 43 ch <- songOrErr{&songs[i], nil} 44 } 45 }() 46 return len(songs), nil 47 }