func main() { flag.Parse() file, err := ioutil.ReadFile(*file) checkErr(err) var songs []Song checkErr(json.Unmarshal(file, &songs)) // Specifically don't set grpc.WithTimeout(), // as it messes with the QueueSong() streams. conn, err := grpc.Dial( fmt.Sprintf("%v:%v", *host, *port), grpc.WithInsecure(), ) checkErr(err) defer conn.Close() c := playsource.NewPlaySourceClient(conn) stream, err := c.QueueSong(context.Background()) checkErr(err) // Try to play all the songs listed in the queue file using // the proper protocol. Note: doesn't handle retries. var inFlight int for i := 0; i < len(songs); { for inFlight < *queueSize { log.Println("Queueing song:", songs[i]) err := stream.Send(&playsource.QueueSongRequest{ Song: &playsource.Song{ SongId: int32(i), Name: songs[i].Name, Artists: songs[i].Artists, }, }) checkErr(err) i++ inFlight++ } resp, err := stream.Recv() checkErr(err) inFlight-- if inFlight < 0 { log.Fatalf("Negative in flight requests") } if resp.Finished { log.Println("Finished:", songs[resp.SongId]) } else if !resp.Found { log.Println("Not Found:", songs[resp.SongId]) } else if !resp.Queued { log.Println("Not Queued (possible overqueue?):", songs[resp.SongId]) } } }
func TestQueueLoop(t *testing.T) { lis, err := net.Listen("tcp", "localhost:0") assert.NoError(t, err) grpcServer := grpc.NewServer() playsource.RegisterPlaySourceServer( grpcServer, NewTestServer(10, 0.8, 3*time.Second), ) go grpcServer.Serve(lis) defer grpcServer.Stop() conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) assert.NoError(t, err) defer conn.Close() c := playsource.NewPlaySourceClient(conn) // The general approach here is that we can keep queueing up to // a certain amount of songs (bounded by service). However, as a // client, we want to perform a local bound of how many songs we // queue, or have 'in-flight'. That is, we must track queue acks // and finished acks to determine when to send queue requests. // This is very similar to the networks algorithm. Funny how things // actually work. stream, err := c.QueueSong(context.Background()) assert.NoError(t, err) var inFlight int for i := 0; i < 100; { for inFlight < 3 { log.Println("Sending request: ", i) err := stream.Send(&playsource.QueueSongRequest{ Song: &playsource.Song{ SongId: int32(i), Name: strconv.Itoa(i), Artists: []string{"a", "b", "c"}, }, }) require.NoError(t, err) i++ inFlight++ } resp, err := stream.Recv() require.NoError(t, err) inFlight-- if resp.Finished { log.Printf("Song %v finished playing", resp.SongId) } else if !resp.Found { log.Println("could not find song:", resp.SongId) } } }