Initial Commit

Initial Commit
This commit is contained in:
eTronic
2018-06-24 18:13:38 -04:00
commit 7a74269c24
7 changed files with 572 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
import request from 'request';
import WebSocket from 'ws';
export default class Account {
constructor({
accessToken,
admin,
authToken,
avatarUrl,
guest,
loginToken,
userId,
username,
tester,
}) {
this.accessToken = accessToken;
this.admin = admin;
this.authToken = authToken;
this.avatarUrl = avatarUrl;
this.guest = guest;
this.loginToken = loginToken;
this.userId = userId;
this.username = username;
this.tester = tester;
this.broadcastId = null;
this.socket = null;
this.lastAnswerId = null;
}
activate(broadcastId, socket) {
this.broadcastId = broadcastId;
this.socket = socket;
}
sendAnswer(questionId, answerId) {
const answerPackage = {
type: 'answer',
broadcastId: this.broadcastId,
questionId,
answerId,
};
this.lastAnswerId = answerId;
this.socket.send(JSON.stringify(answerPackage));
}
}
+29
View File
@@ -0,0 +1,29 @@
export default class HQSchedule {
constructor({
active,
atCapacity,
showId,
showType,
startTime,
nextShowTime,
nextShowPrize,
upcoming,
prize,
broadcast,
gameKey,
broadcastFull,
}) {
this.active = active;
this.atCapacity = atCapacity;
this.showId = showId;
this.showType = showType;
this.startTime = startTime;
this.nextShowTime = nextShowTime;
this.nextShowPrize = nextShowPrize;
this.upcoming = upcoming;
this.prize = prize;
this.broadcast = broadcast;
this.gameKey = gameKey;
this.broadcastFull = broadcastFull;
}
}
+143
View File
@@ -0,0 +1,143 @@
import https from 'https';
import Account from './Account';
const HOST = 'api-quiz.hype.space';
const headers = {
'x-hq-client': 'Android/1.6.2',
'content-type': 'application/json; charset=UTF-8',
'user-agent': 'okhttp/3.8.0',
};
export default class Verification {
constructor({
callsEnabled,
expires,
phone,
retrySeconds,
verificationId,
}) {
this.callsEnabled = callsEnabled;
this.expires = expires;
this.phone = phone;
this.retrySeconds = retrySeconds;
this.verificationId = verificationId;
}
/*
* confirm(string code)
*
* Confirmed phone number (sms code) and returns an authentication token.
*
*/
confirm(code, callback) {
let account;
let error;
const body = {
code,
};
const options = {
host: HOST,
path: '/verifications/' + this.verificationId,
method: 'POST',
headers: {
...headers,
'content-length': JSON.stringify(body).length,
},
};
const req = https.request(options, (res, err) => {
if (err) {
return { response: null, error: err };
}
res.on('data', (data) => {
account = JSON.parse(data);
console.log('account data', account);
if (!account.accessToken) {
if (account.error) {
error = account.error;
} else {
error = data;
}
} else {
account = new Account(account);
}
callback({ response: account, error });
});
});
req.write(JSON.stringify(body));
req.end();
}
/*
* create(Verification verification, string username, string referrer, string region)
*
* Creates a new user and returns its account info.
*
* Account: {
* userId,
* username,
* admin,
* tester,
* guest,
* avatarUrl,
* loginToken,
* accessToken,
* authToken,
* };
*
*/
create(username, referrer, callback) {
let account;
let error;
const body = {
country: 'US',
language: 'en',
referringUsername: referrer,
username,
verificationId: this.verificationId,
};
const options = {
host: HOST,
path: '/users',
method: 'POST',
headers: {
...headers,
'content-length': JSON.stringify(body).length,
},
};
const req = https.request(options, (res, err) => {
if (err) {
return { response: null, error: err };
}
res.on('data', (data) => {
account = JSON.parse(data);
if (!account.accessToken) {
if (account.error) {
error = account.error;
} else {
error = data;
}
account = null;
} else {
account = new Account(account);
}
callback({ response: account, error });
});
});
req.write(JSON.stringify(body));
req.end();
}
}
+27
View File
@@ -0,0 +1,27 @@
{
"mainBearerToken": "yourMainAccessToken",
"players": [
{
"accessToken": "accessToken1",
"admin": false,
"authToken": "authToken1",
"avatarUrl": "https://d2xu1hdomh3nrx.cloudfront.net/default_avatars/Untitled-1_0003_red.png",
"guest": false,
"loginToken": "loginToken1",
"userId": 123456,
"username": "username1",
"tester": false
},
{
"accessToken": "accessToken2",
"admin": false,
"authToken": "authToken2",
"avatarUrl": "https://d2xu1hdomh3nrx.cloudfront.net/default_avatars/Untitled-1_0003_red.png",
"guest": false,
"loginToken": "loginToken2",
"userId": 123457,
"username": "username2",
"tester": false
}
]
}
+183
View File
@@ -0,0 +1,183 @@
import https from 'https';
import prompt from 'prompt';
import Moniker from 'moniker';
import { mainBearerToken } from './config.json';
import Account from './classes/Account';
import HQSchedule from './classes/HQSchedule';
import Verification from './classes/Verification';
const HOST = 'api-quiz.hype.space';
const INIT_TOKEN = mainBearerToken;
const headers = {
'x-hq-client': 'Android/1.6.2',
'content-type': 'application/json; charset=UTF-8',
'user-agent': 'okhttp/3.8.0',
};
const verify = (number, callback) => {
let verification;
let error;
const body = {
method: 'sms',
phone: number,
};
const options = {
host: HOST,
path: '/verifications',
method: 'POST',
headers: {
...headers,
'content-length': JSON.stringify(body).length,
},
};
const req = https.request(options, (res, err) => {
if (err) {
console.log(`Error occured verifying ${number}:`, err);
return { response: null, error: err };
}
res.on('data', (data) => {
verification = JSON.parse(data);
if (!verification.verificationId) {
if (verification.error) {
error = verification.error;
} else {
error = data;
}
} else {
verification = new Verification(verification);
}
callback({ response: verification, error });
});
});
req.write(JSON.stringify(body));
req.end();
};
const connect = (broadcastId, callback) => {
let verification;
let error;
const body = {
method: 'sms',
phone: number,
};
const options = {
host: HOST,
path: '/verifications',
method: 'POST',
headers: {
...headers,
'content-length': JSON.stringify(body).length,
},
};
const req = https.request(options, (res, err) => {
if (err) {
console.log(`Error occured verifying ${number}:`, err);
return { response: null, error: err };
}
res.on('data', (data) => {
verification = JSON.parse(data);
if (!verification.verificationId) {
if (verification.error) {
error = verification.error;
} else {
error = data;
}
} else {
verification = new Verification(verification);
}
callback({ response: verification, error });
});
});
req.write(JSON.stringify(body));
req.end();
};
const getSchedule = (callback) => {
let schedule;
let error;
const options = {
host: HOST,
path: '/shows/now?type=hq',
method: 'GET',
headers: {
'authorization': `Bearer ${INIT_TOKEN}`,
},
};
const req = https.request(options, (res, err) => {
if (err) {
console.log(`Error occured getting game schedule:`, err);
return { response: null, error: err };
}
res.on('data', (data) => {
schedule = JSON.parse(data);
if (!schedule) {
if (schedule.error) {
error = schedule.error;
} else {
error = data;
}
} else {
schedule = new HQSchedule(schedule);
}
callback({ response: schedule, error });
});
});
req.write(JSON.stringify({}));
req.end();
}
const names = Moniker.generator([Moniker.adjective, Moniker.noun], { glue: 'a', maxSize: 4 });
const newUser = `${names.choose()}${Number.parseInt(Math.random()*100)}`;
console.log('Creating user:', newUser);
prompt.start();
prompt.get(['number', 'referral'], (err, res) => {
const referral = res.referral;
console.log('Verifying with referral: ', res.number, referral);
verify(`+1${res.number}`, (result) => {
if (result.response) {
const verification = result.response;
console.log('Verified phone number with result:', verification);
prompt.start();
prompt.get(['code'], (err, res) => {
verification.confirm(res.code, (confirmResult) => {
if (confirmResult.response) {
const auth = confirmResult.response;
if (!auth.auth) {
verification.create(newUser, referral, (createResult) => {
console.log('createResult', createResult);
if (createResult.response) {
const account = createResult.response;
console.log('Creation result:', account);
} else if (createResult.error) console.log('Error creating account:', createResult.error);
});
} else {
console.log('This account already exists?', auth);
}
} else if (confirmResult.error) console.log('Error confirming code:', confirmResult.error);
});
});
} else if (result.error) console.log('Error verifying phone:', result.error);
});
});
+117
View File
@@ -0,0 +1,117 @@
import request from 'request';
import WebSocket from 'ws';
import { mainBearerToken, players } from './config.json';
import Account from './classes/Account';
const HOST = 'api-quiz.hype.space';
const INIT_TOKEN = mainBearerToken;
const headers = {
'x-hq-client': 'Android/1.6.2',
'content-type': 'application/json; charset=UTF-8',
'user-agent': 'okhttp/3.8.0',
};
let playersInGame = players.map((player) => new Account(player));
const removePlayer = (userId) => {
playersInGame = players.filter((player) => player.userId !== userId);
}
request('https://api-quiz.hype.space/shows/now', (error, response, body) => {
const result = JSON.parse(body);
if (!result.active) {
console.log('Game Not Active; Using debug server instead...');
}
const { broadcastId = 44433, socketUrl = 'wss://hqecho.herokuapp.com/' } = result.broadcast || {};
const options = {
headers: {
Authorization: `Bearer ${INIT_TOKEN}`,
},
};
const ws = new WebSocket(socketUrl, options);
ws.on('open', () => {
console.log('Master connected to websocket');
playersInGame.forEach((player) => {
const playerOptions = {
headers: {
Authorization: `Bearer ${player.accessToken}`,
},
};
const pws = new WebSocket(socketUrl, playerOptions);
pws.on('open', () => {
console.log(`Player ${player.username} has connected to websocket`);
pws.send(JSON.stringify({ type:'subscribe', broadcastId }), () => {
console.log(`\tPlayer ${player.username} has subscribed to game`);
player.activate(broadcastId, pws);
});
});
});
});
ws.on('message', (data) => {
const { answers = [], type = null } = JSON.parse(data);
// check if data type is a question not just like chat messages
if (type === 'questionFinished') {
console.log(`You have ${playersInGame.length} players still in game.`);
}
if (type === 'questionSummary') {
const questionSummary = JSON.parse(data);
const correctAnswer = questionSummary.answerCounts.filter(answer => answer.correct).answerId;
playersInGame.forEach((player) => {
if (player.lastAnswerId !== correctAnswer) {
console.log(`Player ${player.username} has been eliminated.`);
removePlayer(player.userId);
}
});
}
if (type !== 'question') return;
const { questionNumber, question: theQuestion, questionId } = JSON.parse(data);
console.log(`Question #${questionNumber}: ${theQuestion}`);
console.log(`Choice 1: ${answers[0].text}`);
console.log(`Choice 2: ${answers[1].text}`);
console.log(`Choice 3: ${answers[2].text}`);
prompt.start();
prompt.get(['answer'], (err, res) => {
const input = res.answer.split(',');
switch (input.length) {
case 1:
playersInGame.forEach((player, index) => {
console.log(`Player ${player.username} sent answer ${input[0]}`);
const callback = (correct) => {
if (!correct) playersInGame.splice(index, 1);
};
player.sendAnswer(questionId, answers[input[0] - 1].answerId);
});
break;
case 2:
playersInGame.forEach((player, index) => {
console.log(`Player ${player.username} sent answer ${input[index % 2]}`);
const callback = (correct) => {
if (!correct) playersInGame.splice(index, 1);
};
player.sendAnswer(questionId, answers[input[index % 2] - 1].answerId)
});
break;
case 3:
playersInGame.forEach((player, index) => {
console.log(`Player ${player.username} sent answer ${input[index % 3]}`);
const callback = (correct) => {
if (!correct) playersInGame.splice(index, 1);
};
player.sendAnswer(questionId, answers[input[index % 3] - 1].answerId)
});
break;
default:
console.log('ERROR: you sent too many answer choices');
break;
}
});
});
});
+27
View File
@@ -0,0 +1,27 @@
{
"name": "hqbot",
"version": "1.0.0",
"description": "",
"main": "hqnode.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "babel-node hqnode.js --presets env,es2016,stage-2",
"create": "babel-node createAccount.js --presets env,es2016,stage-2"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2016": "^6.24.1",
"babel-preset-stage-2": "^6.24.1"
},
"dependencies": {
"http": "0.0.0",
"https": "^1.0.0",
"moniker": "^0.1.2",
"prompt": "^1.0.0",
"request": "^2.87.0",
"ws": "^5.2.1"
}
}