Skip to content

Commit

Permalink
Implement getChat server streaming endpoint
Browse files Browse the repository at this point in the history
- Includes dummy data in the db
- CLI spec changed
  • Loading branch information
mschristensen committed Feb 6, 2020
1 parent a8d6ceb commit d8f6b3a
Show file tree
Hide file tree
Showing 13 changed files with 440 additions and 237 deletions.
154 changes: 148 additions & 6 deletions db.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,156 @@
{
"songs": [
{
"id": 0,
"title": "S1",
"artist": "A1"
"id": 1,
"title": "The Box",
"artist": "Roddy Ricch"
},
{
"id": 0,
"title": "S2",
"artist": "A2"
"id": 2,
"title": "Life Is Good",
"artist": "Future Featuring Drake"
},
{
"id": 3,
"title": "Circles",
"artist": "Post Malone"
},
{
"id": 4,
"title": "Memories",
"artist": "Maroon 5"
},
{
"id": 5,
"title": "Someone You Loved",
"artist": "Lewis Capaldi"
},
{
"id": 6,
"title": "10,000 Hours",
"artist": "Dan + Shay & Justin Bieber"
},
{
"id": 7,
"title": "Dance Monkey",
"artist": "Tones And I"
},
{
"id": 8,
"title": "Roxanne",
"artist": "Arizona Zervas"
},
{
"id": 9,
"title": "Don't Start Now",
"artist": "Dua Lipa"
},
{
"id": 10,
"title": "everything i wanted",
"artist": "Billie Eilish"
}
],
"comments": [
{
"songId": 12,
"username": "Emily Watson",
"body": "Behind the window was a reflection that only instilled fear."
},
{
"songId": 8,
"username": "Jeffery Vega",
"body": "I am out of paper for the printer."
},
{
"songId": 3,
"username": "Sandra Gibbs",
"body": "Don't piss in my garden and tell me you're trying to help my plants grow."
},
{
"songId": 16,
"username": "Sarah Webb",
"body": "I like going out to parties with friends or watching TV."
},
{
"songId": 6,
"username": "Amos Miles",
"body": "When motorists sped in and out of traffic, all she could think of was those in need of a transplant."
},
{
"songId": 12,
"username": "Andy Fowler",
"body": "The memory we used to share is no longer coherent."
},
{
"songId": 10,
"username": "Doug Stanley",
"body": "She works two jobs to make ends meet; at least, that was her reason for not having time to join us."
},
{
"songId": 2,
"username": "Keith Hogan",
"body": "Abstraction is often one floor above you."
},
{
"songId": 8,
"username": "Melissa Guzman",
"body": "We all agreed; it was a magnificent evening."
},
{
"songId": 18,
"username": "Olivia Washington",
"body": "The river stole the gods."
},
{
"songId": 11,
"username": "Tanya Murray",
"body": "She found his complete dullness interesting."
},
{
"songId": 0,
"username": "Lola Rodriquez",
"body": "The knives were out and she was sharpening hers."
},
{
"songId": 11,
"username": "Sheldon Campbell",
"body": "The random sentence generator generated a random sentence about a random sentence."
},
{
"songId": 18,
"username": "Michelle Wise",
"body": "Malls are great places to shop; I can find everything I need under one roof."
},
{
"songId": 4,
"username": "Clarence Cox",
"body": "We have a lot of rain in June."
},
{
"songId": 10,
"username": "Bobbie Berry",
"body": "He was disappointed when he found the beach to be so sandy and the sun so sunny."
},
{
"songId": 3,
"username": "Joan Rose",
"body": "Please tell me you don't work in a morgue."
},
{
"songId": 4,
"username": "Ebony Newman",
"body": "I love bacon, beer, birds, and baboons."
},
{
"songId": 4,
"username": "Manuel Newton",
"body": "The tortoise jumped into the lake with dreams of becoming a sea turtle."
},
{
"songId": 4,
"username": "Anne Wilkins",
"body": "So long and thanks for the fish."
}
]
}
11 changes: 5 additions & 6 deletions proto/songs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ message Song {
}

message Comment {
string username = 1;
string body = 2;
int32 song_id = 1;
string username = 2;
string body = 3;
}

message Reaction { bool like = 1; }

service Songs {
rpc GetSong(google.protobuf.Empty) returns (Song) {};
rpc AddSongs(stream Song) returns (google.protobuf.Empty) {};
rpc GetComments(Song) returns (stream Comment) {};
rpc LiveReactions(stream Reaction) returns (stream Reaction) {};
rpc GetChat(Song) returns (stream Comment) {};
rpc LiveChat(stream Comment) returns (stream Comment) {};
}
2 changes: 1 addition & 1 deletion src/client/add-songs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async function shouldAddMore(): Promise<boolean> {
}

export default {
command: 'add',
command: 'add-songs',
describe: 'Add songs',
builder: {},
handler: async (): Promise<void> => {
Expand Down
30 changes: 30 additions & 0 deletions src/client/get-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import client from './client';
import { Song, Comment } from '../proto/songs_pb';

function printChat(songId: number): Promise<void> {
console.log(`Getting chat for song ${songId}`);
const song = new Song();
song.setId(songId);
return new Promise<void>((resolve, reject) => {
const stream = client.getChat(song);
stream.on('data', (comment: Comment) => {
console.log(`(${comment.getUsername()}) ${comment.getBody()}`);
});
stream.on('end', resolve);
stream.on('error', reject);
});
}

export default {
command: 'get-chat',
describe: 'Get the chat comments on a song',
builder: {
songId: {
demand: true,
number: true,
},
},
handler: async (argv): Promise<void> => {
await printChat(argv.songId);
},
};
5 changes: 2 additions & 3 deletions src/client/get-song.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
import Table from 'cli-table';

function getSong(): Promise<Song> {
console.log('Getting a song...');
return new Promise<Song>((resolve, reject) => {
client.getSong(new Empty(), (err, song) => {
if (err) {
Expand All @@ -16,8 +15,8 @@ function getSong(): Promise<Song> {
}

export default {
command: 'get',
describe: 'Get songs',
command: 'get-song',
describe: 'Get a random song',
builder: {},
handler: async (): Promise<void> => {
const song = await getSong();
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import yargs from 'yargs';
import serve from './server/index';
import getSong from './client/get-song';
import addSongs from './client/add-songs';
import getChat from './client/get-chat';

yargs
.command(serve)
.command(getSong)
.command(addSongs)
.command(getChat)
.help().argv;
42 changes: 21 additions & 21 deletions src/proto/songs_grpc_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty
interface ISongsService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
getSong: ISongsService_IGetSong;
addSongs: ISongsService_IAddSongs;
getComments: ISongsService_IGetComments;
liveReactions: ISongsService_ILiveReactions;
getChat: ISongsService_IGetChat;
liveChat: ISongsService_ILiveChat;
}

interface ISongsService_IGetSong extends grpc.MethodDefinition<google_protobuf_empty_pb.Empty, songs_pb.Song> {
Expand All @@ -33,32 +33,32 @@ interface ISongsService_IAddSongs extends grpc.MethodDefinition<songs_pb.Song, g
responseSerialize: grpc.serialize<google_protobuf_empty_pb.Empty>;
responseDeserialize: grpc.deserialize<google_protobuf_empty_pb.Empty>;
}
interface ISongsService_IGetComments extends grpc.MethodDefinition<songs_pb.Song, songs_pb.Comment> {
path: string; // "/songs.Songs/GetComments"
interface ISongsService_IGetChat extends grpc.MethodDefinition<songs_pb.Song, songs_pb.Comment> {
path: string; // "/songs.Songs/GetChat"
requestStream: boolean; // false
responseStream: boolean; // true
requestSerialize: grpc.serialize<songs_pb.Song>;
requestDeserialize: grpc.deserialize<songs_pb.Song>;
responseSerialize: grpc.serialize<songs_pb.Comment>;
responseDeserialize: grpc.deserialize<songs_pb.Comment>;
}
interface ISongsService_ILiveReactions extends grpc.MethodDefinition<songs_pb.Reaction, songs_pb.Reaction> {
path: string; // "/songs.Songs/LiveReactions"
interface ISongsService_ILiveChat extends grpc.MethodDefinition<songs_pb.Comment, songs_pb.Comment> {
path: string; // "/songs.Songs/LiveChat"
requestStream: boolean; // true
responseStream: boolean; // true
requestSerialize: grpc.serialize<songs_pb.Reaction>;
requestDeserialize: grpc.deserialize<songs_pb.Reaction>;
responseSerialize: grpc.serialize<songs_pb.Reaction>;
responseDeserialize: grpc.deserialize<songs_pb.Reaction>;
requestSerialize: grpc.serialize<songs_pb.Comment>;
requestDeserialize: grpc.deserialize<songs_pb.Comment>;
responseSerialize: grpc.serialize<songs_pb.Comment>;
responseDeserialize: grpc.deserialize<songs_pb.Comment>;
}

export const SongsService: ISongsService;

export interface ISongsServer {
getSong: grpc.handleUnaryCall<google_protobuf_empty_pb.Empty, songs_pb.Song>;
addSongs: grpc.handleClientStreamingCall<songs_pb.Song, google_protobuf_empty_pb.Empty>;
getComments: grpc.handleServerStreamingCall<songs_pb.Song, songs_pb.Comment>;
liveReactions: grpc.handleBidiStreamingCall<songs_pb.Reaction, songs_pb.Reaction>;
getChat: grpc.handleServerStreamingCall<songs_pb.Song, songs_pb.Comment>;
liveChat: grpc.handleBidiStreamingCall<songs_pb.Comment, songs_pb.Comment>;
}

export interface ISongsClient {
Expand All @@ -69,11 +69,11 @@ export interface ISongsClient {
addSongs(metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
addSongs(options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
addSongs(metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
getComments(request: songs_pb.Song, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
getComments(request: songs_pb.Song, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
liveReactions(): grpc.ClientDuplexStream<songs_pb.Reaction, songs_pb.Reaction>;
liveReactions(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Reaction, songs_pb.Reaction>;
liveReactions(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Reaction, songs_pb.Reaction>;
getChat(request: songs_pb.Song, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
getChat(request: songs_pb.Song, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
liveChat(): grpc.ClientDuplexStream<songs_pb.Comment, songs_pb.Comment>;
liveChat(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Comment, songs_pb.Comment>;
liveChat(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Comment, songs_pb.Comment>;
}

export class SongsClient extends grpc.Client implements ISongsClient {
Expand All @@ -85,8 +85,8 @@ export class SongsClient extends grpc.Client implements ISongsClient {
public addSongs(metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
public addSongs(options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
public addSongs(metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: google_protobuf_empty_pb.Empty) => void): grpc.ClientWritableStream<songs_pb.Song>;
public getComments(request: songs_pb.Song, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
public getComments(request: songs_pb.Song, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
public liveReactions(options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Reaction, songs_pb.Reaction>;
public liveReactions(metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Reaction, songs_pb.Reaction>;
public getChat(request: songs_pb.Song, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
public getChat(request: songs_pb.Song, metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientReadableStream<songs_pb.Comment>;
public liveChat(options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Comment, songs_pb.Comment>;
public liveChat(metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<songs_pb.Comment, songs_pb.Comment>;
}
31 changes: 10 additions & 21 deletions src/proto/songs_grpc_pb.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,6 @@ function deserialize_songs_Comment(buffer_arg) {
return songs_pb.Comment.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_songs_Reaction(arg) {
if (!(arg instanceof songs_pb.Reaction)) {
throw new Error('Expected argument of type songs.Reaction');
}
return Buffer.from(arg.serializeBinary());
}

function deserialize_songs_Reaction(buffer_arg) {
return songs_pb.Reaction.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_songs_Song(arg) {
if (!(arg instanceof songs_pb.Song)) {
throw new Error('Expected argument of type songs.Song');
Expand Down Expand Up @@ -73,8 +62,8 @@ var SongsService = exports.SongsService = {
responseSerialize: serialize_google_protobuf_Empty,
responseDeserialize: deserialize_google_protobuf_Empty,
},
getComments: {
path: '/songs.Songs/GetComments',
getChat: {
path: '/songs.Songs/GetChat',
requestStream: false,
responseStream: true,
requestType: songs_pb.Song,
Expand All @@ -84,16 +73,16 @@ var SongsService = exports.SongsService = {
responseSerialize: serialize_songs_Comment,
responseDeserialize: deserialize_songs_Comment,
},
liveReactions: {
path: '/songs.Songs/LiveReactions',
liveChat: {
path: '/songs.Songs/LiveChat',
requestStream: true,
responseStream: true,
requestType: songs_pb.Reaction,
responseType: songs_pb.Reaction,
requestSerialize: serialize_songs_Reaction,
requestDeserialize: deserialize_songs_Reaction,
responseSerialize: serialize_songs_Reaction,
responseDeserialize: deserialize_songs_Reaction,
requestType: songs_pb.Comment,
responseType: songs_pb.Comment,
requestSerialize: serialize_songs_Comment,
requestDeserialize: deserialize_songs_Comment,
responseSerialize: serialize_songs_Comment,
responseDeserialize: deserialize_songs_Comment,
},
};

Expand Down
Loading

0 comments on commit d8f6b3a

Please sign in to comment.