Files
tasJS/Player.js
2018-07-13 19:31:07 -04:00

158 lines
4.7 KiB
JavaScript

import WebSocket from 'ws';
import { LOG_TYPES } from './constants';
export default class Player {
constructor({
accessToken,
userId,
username,
}) {
this.accessToken = accessToken;
this.userId = userId;
this.username = username;
this.logger = null;
this.broadcast = null;
this.socket = null;
this.controller = null;
this.lastAnswerId = null;
this.playerPingTimeout = null;
this.playerPingInterval = null;
this.hasExtraLife = false;
this.canSendAnswer = false;
this.usedExtraLifeThisQuestion = false;
}
async connect(controller, broadcast) {
const { broadcastId, socketUrl } = broadcast;
this.broadcast = broadcast;
this.controller = controller;
const options = {
headers: {
Authorization: `Bearer ${this.accessToken}`,
},
};
this.socket = new WebSocket(socketUrl, options);
this.socket.on('error', err => this.logger.log(`An error occurred: ${err}`, LOG_TYPES.ERROR));
this.socket.on('pong', this.pong.bind(this));
this.socket.on('open', this.handleOpen.bind(this));
this.socket.on('close', this.handleClose.bind(this));
this.socket.on('message', this.handleMessage.bind(this));
}
ping() {
if (!this.socket) return;
try {
this.socket.ping();
this.playerPingTimeout = setTimeout(() => {
this.socket.terminate();
this.logger.log(`Player ${this.username} connection closed. Attempting to reconnect...`, LOG_TYPES.ERROR);
this.connect(this.broadcast);
}, 2000);
} catch (error) {
this.logger.log(`Player ${this.username} connection closed. Attempting to reconnect...`, LOG_TYPES.ERROR);
}
}
pong() {
clearTimeout(this.playerPingTimeout);
}
async handleOpen() {
this.playerPingInterval = setInterval(this.ping.bind(this), 10000);
this.logger.log(`Player ${this.username} has connected to websocket!`, LOG_TYPES.SUCCESS);
const { broadcastId } = this.broadcast;
this.socket.send(JSON.stringify({ type: 'subscribe', broadcastId }), () => {
this.logger.log(`Player ${this.username} has subscribed to the game!`, LOG_TYPES.INFO);
});
}
handleClose() {
this.socket = null;
clearInterval(this.playerPingInterval);
clearTimeout(this.playerPingTimeout);
}
removePlayer() {
if (this.socket) {
this.socket.terminate();
this.socket.close();
}
this.handleClose();
}
async handleMessage(data) {
const parsed = JSON.parse(data);
switch (parsed.type) {
case 'gameStatus':
const { extraLivesRemaining = 0 } = parsed;
this.hasExtraLife = extraLivesRemaining > 0;
this.logger.logSilent(`Player ${this.username}'s game status: ${data}`);
break;
case 'question':
this.canSendAnswer = true;
break;
case 'questionClosed':
this.canSendAnswer = false;
break;
case 'questionSummary':
const { question, youGotItRight, savedByExtraLife } = parsed;
if (!youGotItRight) {
this.logger.logSilent(`Player ${this.username} got ${question} wrong.`);
}
if (!savedByExtraLife && this.usedExtraLifeThisQuestion) {
this.logger.logSilent(`Player ${this.username} used extra life but was not saved on question: ${question}.`);
this.usedExtraLifeThisQuestion = false;
}
break;
case 'questionFinished':
break;
}
}
sendAnswer(questionId, answer, answerNumber) {
const { answerId } = answer;
const answerPackage = {
type: 'answer',
broadcastId: this.broadcast.broadcastId,
questionId,
answerId,
};
this.lastAnswerId = answerId;
try {
if (!this.canSendAnswer) {
this.logger.logSilent(`Player ${this.username} tried to send answer for ${questionId}: ${answer.text} but time expired!`);
} else {
this.socket.send(JSON.stringify(answerPackage));
this.logger.log(`Player ${this.username} sent answer ${answerNumber}) ${answer.text}`);
}
} catch (error) {
this.logger.log(`WebSocket error: ${this.username} can\'t send answer.`, LOG_TYPES.ERROR);
this.logger.logSilent(error);
this.lastAnswerId = null;
}
}
sendExtraLife(questionId) {
const extraLifePackage = {
type: 'useExtraLife',
broadcastId: this.broadcast.broadcastId,
questionId,
};
try {
this.socket.send(JSON.stringify(extraLifePackage));
this.hasExtraLife = false;
this.usedExtraLifeThisQuestion = true;
this.logger.log(`Player ${this.username} has been saved by an extra life!`);
} catch (error) {
this.logger.log(`WebSocket error: ${this.username} can\'t send extra life.`, LOG_TYPES.ERROR);
}
}
}