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