early draft of sockets logic for monitoring
[qomet.git] / sockets.js
1 const message = require("./public/javascripts/utils/socketMessages");
2 const params = require("./config/parameters");
3 const AssessmentEntity = require("./entities/assessment");
4 const ObjectId = require("bson-objectid");
5
6 // TODO: when teacher connect on monitor, io.of("appropriate namespace").on(connect student) { ... }
7 // --> 2 sockets on monitoring page: one with ns "/" et one dedicated to the exam, triggered after the first
8 // --> The monitoring page should not be closed during exam (otherwise monitors won't receive any more data)
9
10 function examRoom(socket) {
11 let students = { };
12 const aid = ObjectId(socket.handshake.query.aid);
13
14 // Student or monitor stuff
15 const isTeacher = !!socket.handshake.query.secret && socket.handshake.query.secret == params.secret;
16
17 if (isTeacher)
18 {
19 socket.on(message.newAnswer, m => { //got answer from student
20 socket.emit(message.newAnswer, m);
21 });
22 socket.on(message.allAnswers, m => { //send feedback to student (answers)
23 if (!!students[m.number]) //TODO: namespace here... room quiz
24 socket.broadcast.to(students[m.number]).emit(message.allAnswers, m);
25 });
26 socket.on("disconnect", m => {
27 // Reset student array if no more active teacher connections (TODO: condition)
28 students = { };
29 });
30 }
31
32 else //student
33 {
34 const number = socket.handshake.query.number;
35 const password = socket.handshake.query.password;
36 AssessmentEntity.checkPassword(aid, number, password, (err,ret) => {
37 if (!!err || !ret)
38 return; //wrong password, or some unexpected error...
39 // Prevent socket connection (just ignore) if student already connected
40 if (!!students[number])
41 return;
42 students[number] = {
43 sid: socket.id,
44 password: password,
45 };
46 socket.on(message.allAnswers, () => { //got all answers from teacher
47 socket.emit(message.allAnswers, m);
48 });
49 socket.on("disconnect", () => {
50 // ..
51 //TODO: notify monitor (highlight red), redirect
52 });
53 // NOTE: nothing on disconnect --> teacher disconnect trigger students cleaning
54 });
55 }
56 }
57
58 module.exports = function(io) {
59
60 // NOTE: if prof connected with 2 tabs and close 1, quizz should not break, thus following counter
61 let namespaces = { };
62
63 io.of("/").on("connection", socketProf => {
64 function closeQuizz(fullPath) {
65 namespaces[fullPath].counter--;
66 if (namespaces[fullPath].counter == 0)
67 {
68 // https://stackoverflow.com/questions/26400595/socket-io-how-do-i-remove-a-namespace
69 const connectedSockets = Object.keys(namespaces[fullPath].nsp.connected);
70 connectedSockets.forEach( sid => {
71 namespaces[fullPath].nsp.connected[sid].disconnect();
72 });
73 namespaces[fullPath].nsp.removeAllListeners();
74 delete io.nsps[fullPath];
75 }
76 }
77 // Only prof account can connect default namespace
78 socketProf.on(message.startQuizz, m => {
79 // m contient quizz ID + fullPath (initials+path+name)
80 const quizzNamespace = io.of(m.fullPath);
81 if (!namespaces[m.fullPath])
82 {
83 namespaces[m.fullPath] = { nsp:quizzNamespace, counter:1 };
84 quizzNamespace.on("connection", quizzRoom); //après ça : prof can connect in quizz too
85 socketProf.emit(message.quizzReady);
86 socketProf.on(message.endQuizz, m2 => {
87 closeQuizz(m.fullPath);
88 });
89 socketProf.on("disconnect", m2 => {
90 closeQuizz(m.fullPath); //TODO: this should delete all students in array
91 });
92 }
93 else
94 namespaces[m.fullPath]++;
95 });
96 });
97 }