Skip to content

Commit

Permalink
Implement live chat bidi stream endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
mschristensen committed Feb 7, 2020
1 parent d8f6b3a commit 6f0f3f8
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 158 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
dist
db.json
chat-*.txt
156 changes: 0 additions & 156 deletions db.json

This file was deleted.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"scripts": {
"lint": "yarn run eslint --fix --ext .ts src",
"prebuild": "yarn run lint",
"clean": "rm -rf ./src/proto && mkdir -p ./src/proto && rm -f chat-*.txt && rm -f db.json",
"build": "sh ./scripts/build-protos.sh ./songs.proto ./src/proto && yarn run tsc",
"start": "PORT=6789 node ./dist/index.js"
}
Expand Down
1 change: 0 additions & 1 deletion scripts/build-protos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ cd ${BASEDIR}/../

PROTO_DEST=./src/proto

rm -rf ${PROTO_DEST}
mkdir -p ${PROTO_DEST}

# JavaScript code generation
Expand Down
54 changes: 54 additions & 0 deletions src/client/live-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import fs from 'fs';
import inquirer from 'inquirer';
import client from './client';
import { Comment } from '../proto/songs_pb';

async function liveChat(): Promise<void> {
const { name, songId } = await inquirer.prompt([
{
name: 'name',
message: 'What is your name?',
},
{
name: 'songId',
message: 'Which song do you want to discuss?',
},
]);
const stream = client.liveChat();
return new Promise(async (resolve, reject) => {
stream.on('data', (comment: Comment) => {
fs.writeFileSync(
`chat-${name}-${comment.getSongId()}.txt`,
`(${comment.getUsername()}) ${comment.getBody()}\n`,
{
flag: 'a',
},
);
});
stream.on('end', resolve);
stream.on('error', reject);

while (true) {
const answer = await inquirer.prompt([
{
name: 'message',
message: 'Type message:',
},
]);
const comment = new Comment();
comment.setUsername(name);
comment.setBody(answer.message);
comment.setSongId(songId);
stream.write(comment);
}
});
}

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

yargs
.command(serve)
.command(getSong)
.command(addSongs)
.command(getChat)
.command(liveChat)
.help().argv;
7 changes: 6 additions & 1 deletion src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ISongsServer, SongsService } from '../proto/songs_grpc_pb';
import getSong from './get-song';
import addSong from './add-song';
import getChat from './get-chat';
import { addComment, registerListener } from './live-chat';

class SongsServer implements ISongsServer {
getSong(call: grpc.ServerUnaryCall<Empty>, callback: grpc.sendUnaryData<Song>): void {
Expand All @@ -25,7 +26,11 @@ class SongsServer implements ISongsServer {
call.end();
}
liveChat(call: grpc.ServerDuplexStream<Comment, Comment>): void {
console.log('liveChat', call);
registerListener(comment => call.write(comment));
call.on('data', (comment: Comment) => {
addComment(comment);
});
call.on('end', () => call.end());
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/server/live-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Comment } from '../proto/songs_pb';
import db from './db';

type ListenerFn = (c: Comment) => void;

const listeners: ListenerFn[] = [];

export function registerListener(fn: ListenerFn): void {
listeners.push(fn);
}

export function addComment(comment: Comment): void {
// Use of `any` required due to bug in @types/lowdb
// SEE: https://github.com/typicode/lowdb/issues/349
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dbComments = db.get('comments') as any;
dbComments.push(comment.toObject()).write();
listeners.map(listener => listener(comment));
}

0 comments on commit 6f0f3f8

Please sign in to comment.