| 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 | } |