Skip to content

Commit 60e8b63

Browse files
committed
Add support for student video question
1 parent ef3a10d commit 60e8b63

File tree

2 files changed

+209
-12
lines changed

2 files changed

+209
-12
lines changed

src/commonhandler.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,48 @@ export class CommonConnection {
258258
time: alloffers[label]
259259
})
260260
}
261-
socket.emit('avofferList', { offers })
261+
if (offers.length > 0) socket.emit('avofferList', { offers })
262+
}
263+
264+
async emitVideoquestions(socket, args) {
265+
const allquestions = await this.redis.hGetAll(
266+
'lecture:' + args.lectureuuid + ':videoquestion'
267+
)
268+
const vquestions = []
269+
for (const label in allquestions) {
270+
try {
271+
const labels = label.split(':')
272+
const obj = JSON.parse(allquestions[label])
273+
vquestions.push({
274+
id: labels[1],
275+
...obj
276+
})
277+
} catch (error) {
278+
console.log('Problem vquestion parse', error)
279+
}
280+
}
281+
if (vquestions.length > 0) socket.emit('videoquestionList', { vquestions })
282+
}
283+
284+
async closeVideoQuestion(args, cmd) {
285+
if (!cmd.id) return // do not proceed without id.
286+
const roomname = this.getRoomName(args.lectureuuid)
287+
288+
const message = {
289+
id: cmd.id
290+
}
291+
292+
this.notepadio.to(roomname).emit('closevideoquestion', message)
293+
this.screenio.to(roomname).emit('closevideoquestion', message)
294+
this.notesio.to(roomname).emit('closevideoquestion', message)
295+
296+
try {
297+
await this.redis.hDel('lecture:' + args.lectureuuid + ':videoquestion', [
298+
'permitted:' + cmd.id
299+
])
300+
} catch (error) {
301+
console.log('problem in closeVideoQuestion', error)
302+
}
262303
}
263304

264305
getRoomName(uuid) {
@@ -393,6 +434,9 @@ export class CommonConnection {
393434
ret.next = array[index + 1].url
394435
ret.nextspki = array[index + 1].spki
395436
}
437+
if (index === 0 && cmd.tempOut) {
438+
ret.tempOut = cmd.tempOut
439+
}
396440
return { data: ret, key: ele.key }
397441
})
398442
.map(async (ele) => {

src/noteshandler.js

Lines changed: 164 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class NotesConnection extends CommonConnection {
2727
this.mongo = args.mongo
2828
this.notesio = args.notesio
2929
this.notepadio = args.notepadio
30+
this.screenio = args.screenio
3031
this.getFileURL = args.getFileURL
3132

3233
this.noteshandlerURL = args.noteshandlerURL
@@ -90,6 +91,7 @@ export class NotesConnection extends CommonConnection {
9091
socket.emit('presinfo', readypresinfo)
9192
}
9293
this.emitAVOffers(socket, purenotes)
94+
this.emitVideoquestions(socket, purenotes)
9395

9496
socket.on(
9597
'reauthor',
@@ -113,6 +115,9 @@ export class NotesConnection extends CommonConnection {
113115
encData: cmd.encData,
114116
keyindex: cmd.keyindex,
115117
iv: cmd.iv,
118+
videoquestion: cmd.videoquestion
119+
? { id: purenotes.socketid }
120+
: undefined,
116121
userhash: userhash
117122
})
118123

@@ -121,6 +126,20 @@ export class NotesConnection extends CommonConnection {
121126
// console.log("chatquestion",cmd);
122127
})
123128

129+
socket.on('closevideoquestion', (cmd) => {
130+
this.closeVideoQuestion(purenotes, { id: purenotes.socketid }).catch(
131+
(error) => {
132+
console.log('Problem in closeVideoQuestion', error)
133+
}
134+
)
135+
})
136+
137+
socket.on('avoffer', (cmd) => {
138+
this.handleVQoffer(purenotes, cmd).catch((error) => {
139+
console.log('Problem in handleVQoffer', error)
140+
})
141+
})
142+
124143
socket.on(
125144
'castvote',
126145
async function (data, callback) {
@@ -168,23 +187,46 @@ export class NotesConnection extends CommonConnection {
168187
)
169188

170189
socket.on('getrouting', async (cmd, callback) => {
190+
let tempOut
191+
if (cmd.dir === 'out' && cmd.id === purenotes.socketid) {
192+
let toid
193+
try {
194+
await Promise.any([
195+
routerurl,
196+
new Promise((resolve, reject) => {
197+
toid = setTimeout(reject, 20 * 1000)
198+
})
199+
])
200+
if (toid) clearTimeout(toid)
201+
toid = undefined
202+
tempOut = await this.getTempOutTransport(purenotes, await routerurl)
203+
} catch (error) {
204+
callback({ error: 'getrouting: timeout or error tempout: ' + error })
205+
}
206+
}
207+
171208
if (
172209
cmd &&
173210
cmd.id &&
174211
cmd.dir &&
175-
cmd.dir === 'in' /* || cmd.dir === 'out' */ // a notes can only receive, later with special permission
212+
(cmd.dir === 'in' || tempOut) /* || cmd.dir === 'out' */ // a notes can only receive, later with special permission
176213
) {
177214
try {
178215
let toid
179-
Promise.any([
216+
await Promise.any([
180217
routerurl,
181218
new Promise((resolve, reject) => {
182219
toid = setTimeout(reject, 20 * 1000)
183220
})
184221
])
185222
if (toid) clearTimeout(toid)
186223
toid = undefined
187-
this.getRouting(purenotes, cmd, await routerurl, callback)
224+
this.getRouting(
225+
purenotes,
226+
{ ...cmd, tempOut },
227+
await routerurl,
228+
callback
229+
)
188230
} catch (error) {
189231
callback({ error: 'getrouting: timeout or error: ' + error })
190232
}
@@ -234,7 +276,7 @@ export class NotesConnection extends CommonConnection {
234276
this.handleKeymasterQuery(purenotes)
235277
})
236278

237-
socket.on('disconnect', () => {
279+
socket.on('disconnect', async () => {
238280
console.log(
239281
'Notes Client %s with ip %s disconnected',
240282
socket.id,
@@ -243,13 +285,39 @@ export class NotesConnection extends CommonConnection {
243285
if (purenotes) {
244286
if (purenotes.roomname) {
245287
socket.leave(purenotes.roomname)
246-
this.redis.hDel(
247-
'lecture:' + purenotes.lectureuuid + ':idents',
248-
purenotes.socketid
249-
)
250-
this.notepadio
251-
.to(purenotes.roomname)
252-
.emit('identDelete', { id: purenotes.socketid })
288+
try {
289+
const proms = []
290+
proms.push(
291+
this.redis.hDel(
292+
'lecture:' + purenotes.lectureuuid + ':idents',
293+
purenotes.socketid
294+
)
295+
)
296+
proms.push(
297+
this.redis.hDel(
298+
'lecture:' + purenotes.lectureuuid + ':videoquestion',
299+
'permitted:' + purenotes.socketid
300+
)
301+
)
302+
this.notepadio
303+
.to(purenotes.roomname)
304+
.emit('identDelete', { id: purenotes.socketid })
305+
306+
const promres = await Promise.all(proms)
307+
if (promres[1] > 0) {
308+
this.notepadio
309+
.to(purenotes.roomname)
310+
.emit('closevideoquestion', { id: purenotes.socketid })
311+
this.screenio
312+
.to(purenotes.roomname)
313+
.emit('closevideoquestion', { id: purenotes.socketid })
314+
this.notesio
315+
.to(purenotes.roomname)
316+
.emit('closevideoquestion', { id: purenotes.socketid })
317+
}
318+
} catch (error) {
319+
console.log('Problem disconnect:', error)
320+
}
253321
// console.log('notes disconnected leave room', purenotes.roomname)
254322
purenotes.roomname = null
255323
}
@@ -277,6 +345,91 @@ export class NotesConnection extends CommonConnection {
277345
return { token: await this.signNotesJwt(newtoken), decoded: newtoken }
278346
}
279347

348+
async getTempOutTransport(args, routerurl) {
349+
try {
350+
// first check permissions
351+
const exists = await this.redis.hExists(
352+
'lecture:' + args.lectureuuid + ':videoquestion',
353+
'permitted:' + args.socketid
354+
)
355+
if (!exists) return
356+
// very well we have the permission, so generate a token for temperory perms
357+
358+
const routercol = this.mongo.collection('avsrouters')
359+
360+
const majorid = args.lectureuuid
361+
const clientid = args.lectureuuid + ':' + args.socketid
362+
const router = await routercol.findOne(
363+
{
364+
url: routerurl
365+
},
366+
{
367+
projection: {
368+
_id: 0,
369+
url: 1,
370+
region: 1,
371+
key: 1,
372+
spki: 1,
373+
primaryRealms: { $elemMatch: { $eq: majorid } },
374+
hashSalt: 1,
375+
localClients: { $elemMatch: { $eq: clientid } },
376+
remoteClients: { $elemMatch: { $eq: clientid } }
377+
}
378+
}
379+
)
380+
381+
const calcHash = async (input) => {
382+
const hash = createHash('sha256')
383+
hash.update(input)
384+
// console.log('debug router info', router)
385+
hash.update(router.hashSalt)
386+
return hash.digest('base64')
387+
}
388+
389+
const realmhash = calcHash(args.lectureuuid)
390+
const clienthash = calcHash(args.socketid)
391+
392+
let token = {}
393+
// todo hash table
394+
token.accessWrite = [
395+
(await realmhash).replace(/[+/]/g, '\\$&') + ':[a-zA-Z0-9-/+=]+'
396+
]
397+
token.realm = await realmhash
398+
token.client = await clienthash
399+
token = this.signAvsJwt(token)
400+
return await token
401+
} catch (error) {
402+
console.log('Problem getTempOutTransport', error)
403+
throw new Error()
404+
}
405+
}
406+
407+
async handleVQoffer(args, cmd) {
408+
// ok to things to do, inform the others about the offer
409+
// and store the information in redis
410+
411+
if (
412+
cmd.type !== 'video' &&
413+
cmd.type !== 'audio' /* && cmd.type !== 'screen' */
414+
) {
415+
return
416+
}
417+
418+
const roomname = this.getRoomName(args.lectureuuid)
419+
420+
const message = {
421+
id: args.socketid,
422+
type: cmd.type,
423+
db: cmd.db // loundness in case of audio
424+
}
425+
426+
this.notepadio.to(roomname).emit('vqoffer', message)
427+
this.screenio.to(roomname).emit('vqoffer', message)
428+
this.notesio.to(roomname).emit('vqoffer', message)
429+
430+
// VQ offers are not saved
431+
}
432+
280433
async getPresentationinfo(args) {
281434
try {
282435
let lectprop = this.redis.hmGet('lecture:' + args.lectureuuid, [

0 commit comments

Comments
 (0)