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  }