-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
220 lines (201 loc) · 7.57 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
require('babel-register');
var express = require('express');
var path = require('path');
var HashMap = require('hashmap');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var crypto = require("crypto");
var Player = require('./player.js');
var MongoClient = require('mongodb').MongoClient;
var app = express();
var kahoots = null;
var KAHOOT_COUNT = 0;
MongoClient.connect('mongodb://localhost:27017/KahootChallenge', function(err,database) {
kahoots = database.collection("Kahoots");
kahoots.count({}, function(err, count) {
KAHOOT_COUNT = count;
});
})
const PORT=8080;
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
//waitingForJoin tracks people who have a link and are waiting for it to be clicked.
var waitingForJoin = new HashMap();
//games stores all active games
var games = new HashMap();
app.get('/play/:kahootID', function(req, res) {
//Give the user an ID and send them the default game page
var user = generateRandomHash();
res.cookie("playerID", user);
res.sendFile('game.html', {root : __dirname});
});
app.get('/play/:kahootID/:otherUserCookie', function(req, res) {
//This happens if smomeone follows their own link
if(req.cookies.playerID == req.params.otherUserCookie) {
res.send("Send the link to a friend.");
}
//Give the user an ID and send them the default game page
else {
var user = generateRandomHash();
res.cookie("playerID", user);
res.sendFile('game.html', {root : __dirname});
}
});
app.post('/getKahoots', function(req, res) {
//Gets kahoots to be shown on the home page. Skips kahoots for pagination.
var skip = (req.body.page - 1) * 30;
kahoots.find().sort({index: 1}).skip(skip).limit(30).toArray(function(err, result) {
var kahoots = [];
for (var i = 0; i < result.length; i++) {
kahoots.push({cover: result[i].cover, username: result[i].creator_username,
title: result[i].title, description: result[i].description,
numQuestions: result[i].questions.length, index: result[i].index});
}
res.send(JSON.stringify({kahoots: kahoots, hasMore: skip < KAHOOT_COUNT}));
});
});
app.post('/searchKahoots', function(req, res) {
//Finds all kahoots that have the given value in their title or description
var val = req.body.searchVal;
var regex = new RegExp(val, "i");
kahoots.find({$or: [{title: regex}, {description: regex}]}).sort({index: 1}).toArray(function(err, result) {
var kahoots = [];
for (var i = 0; i < result.length; i++) {
kahoots.push({cover: result[i].cover, username: result[i].creator_username,
title: result[i].title, description: result[i].description,
numQuestions: result[i].questions.length, index: result[i].index});
}
res.send(JSON.stringify(kahoots));
});
});
app.post('/waitingForJoin', function(req, res) {
//Once the user submits a name, their res object is stored. A response is sent when someone clicks the link.
var user = req.cookies.playerID;
var name = req.body.name;
var kahootID = parseInt(req.body.kahootID);
waitingForJoin.set(user, {name: name, res: res, kahootID: kahootID, createTime: Date.now()});
});
app.post('/joiningGame', function(req, res) {
//The user comes here when they click on a link given to them.
var user = req.cookies.playerID;
var otherUser = req.body.otherUser;
var name = req.body.name;
var other = waitingForJoin.get(otherUser);
if(!other) {
res.status(400);
res.send("Game not found");
return;
}
var kahootID = other.kahootID;
//Send the initial state of the game to both players
getQuestionCount(kahootID, function(qCount) {
var newGame = {kahootID: kahootID, currentQ: 1, totalQ: qCount, waitingPlayer: null, createTime: Date.now()};
newGame.players = [new Player(name, user, res), new Player(other.name, otherUser, other.res)];
waitingForJoin.remove(user);
games.set(user, newGame)
games.set(otherUser, newGame);
sendLeaderBoard(newGame, null, newGame.players[0]);
sendLeaderBoard(newGame, null, newGame.players[1]);
});
});
app.post('/nextQuestion', function(req, res) {
var user = req.cookies.playerID;
var game = games.get(user);
getQuestion(game.kahootID, game.currentQ, game.totalQ, function(question) {
res.send(JSON.stringify(question));
});
});
app.post('/answerQuestion', function(req, res) {
var user = req.cookies.playerID;
var answer = req.body.answer;
var time = req.body.time;
var game = games.get(user);
var player = game.players[0].ID == user ? game.players[0] : game.players[1];
evaluateAnswer(game.kahootID, game.currentQ, answer, time, function(deltaScore, correctAnswers) {
player.changeScore(deltaScore, answer);
player.res = res;
//If this is the first player to answer, make them wait for the next person.
if(game.waitingPlayer == null) {
game.waitingPlayer = player;
}
else {
sendLeaderBoard(game, correctAnswers, player, game.waitingPlayer.lastAnswer);
sendLeaderBoard(game, correctAnswers, game.waitingPlayer, player.lastAnswer);
game.currentQ = game.currentQ + 1;
game.waitingPlayer = null;
}
});
});
function sendLeaderBoard(game, correctAnswers, player, otherAnswer) {
var p = game.players;
var leaderBoard = [{name: p[0].name, score: p[0].score}, {name: p[1].name, score: p[1].score}];
if(p[1].score > p[0].score)
leaderBoard = [{name: p[1].name, score: p[1].score}, {name: p[0].name, score: p[0].score}];
var toSend = {deltaScore: player.deltaScore, leaderBoard: leaderBoard, correctAnswers: correctAnswers, otherAnswer: otherAnswer};
player.res.send(JSON.stringify(toSend));
}
function getQuestionCount(kahootID, callback) {
var query = {index: kahootID};
kahoots.find(query).toArray(function (err, result) {
callback(result[0].questions.length);
});
}
function getQuestion(kahootID, qNum, totalQ, callback) {
var query = {index: kahootID};
kahoots.find(query).toArray(function (err, result) {
var qInfo = result[0].questions[qNum - 1];
var answers = qInfo.choices.map((ans) => ans.answer);
callback({question: qInfo.question, answerTime: qInfo.time, answers: answers, currentQ: qNum, totalQ: totalQ, image: qInfo.image});
});
}
function evaluateAnswer(kahootID, currentQ, answer, time, callback) {
var query = {index: kahootID};
kahoots.find(query).toArray(function (err, result) {
var correctAnswers = [];
var choices = result[0].questions[currentQ - 1].choices;
for(var i = 0; i < choices.length; i++)
if(choices[i].correct) correctAnswers.push(i);
var correct = false;
if(answer != null && answer != "null")
correct = choices[answer].correct;
if(correct) {
var totalTime = result[0].questions[currentQ - 1].time;
if(time < 500) {
callback(1000, correctAnswers);
}
else {
var deltaScore = Math.round(1000 * (1 - ((time/totalTime) / 2)));
callback(deltaScore, correctAnswers);
}
}
else {
callback(0, correctAnswers);
}
});
}
function generateRandomHash() {
return crypto.randomBytes(3).toString('hex');
}
setInterval(function() {
var values = games.values();
values.forEach(function(game) {
//Game deleted after 2 hours
if(Date.now() - game.createTime > 7200000) {
games.delete(games.search(game));
}
});
}, 1800000);
setInterval(function() {
var values = waitingForJoin.values();
values.forEach(function(waitingToJoin) {
//waitingToJoin deleted after 2 hours
if(Date.now() - waitingToJoin.createTime > 7200000) {
waitingForJoin.delete(waitingForJoin.search(waitingToJoin));
}
});
}, 1740000);
app.listen(PORT, function(){
console.log('Server listening');
});