1
+ const { program } = require ( "commander" )
1
2
const express = require ( "express" )
2
3
const http = require ( "http" )
3
4
const axios = require ( "axios" )
@@ -27,8 +28,20 @@ const otreeRestKey = process.env.OTREE_REST_KEY
27
28
const apiKey = process . env . API_KEY
28
29
const secretKey = process . env . SECRET_KEY
29
30
const keyWordArray = CryptoJS . enc . Base64 . parse ( apiKey )
30
- const port = process . argv [ 2 ] || "8060"
31
- const userDbFile = "./data/userdb.json"
31
+
32
+ program
33
+ . option ( "-p, --port <int>" , "server listen port" )
34
+ . option ( "--reset-db" , "reset users database" )
35
+ . option ( "--db-file <type>" , "user database file to use" )
36
+
37
+ program . parse ( process . argv )
38
+ const options = program . opts ( )
39
+ console . log ( options . port )
40
+ console . log ( options . resetDb )
41
+ console . log ( options )
42
+
43
+ const port = options . port || "8060"
44
+ const userDbFile = options . dbFile || "./data/userdb.json"
32
45
//const publicKey = fs.readFileSync("./public-key.pem", "utf8")
33
46
//
34
47
process . on ( "SIGINT" , function ( ) {
@@ -280,13 +293,22 @@ function startReadyGames(experiments, agreementIds, usersDb) {
280
293
agreement . urls ,
281
294
agreement . server ,
282
295
)
283
- agreedUsersIds . forEach ( ( userId ) => {
284
- const compoundKey = `${ userId } :${ agreement . experimentId } `
296
+
297
+ console . log ( agreedUsersIds )
298
+ console . log ( nonAgreedUsersIds )
299
+
300
+ //agreedUsersIds.forEach((userId) => {
301
+ agreedUsersIds . forEach ( ( compoundKey ) => {
302
+ // const compoundKey = `${userId}:${agreement.experimentId}`
303
+ console . log ( `agree: ${ compoundKey } ` )
285
304
const user = usersDb . get ( compoundKey )
286
305
user . changeState ( "queued" )
287
306
} )
288
- nonAgreedUsersIds . forEach ( ( userId ) => {
289
- const compoundKey = `${ userId } :${ agreement . experimentId } `
307
+ //nonAgreedUsersIds.forEach((userId) => {
308
+ nonAgreedUsersIds . forEach ( ( compoundKey ) => {
309
+ // usersDb.dump()
310
+ // const compoundKey = `${userId}:${agreement.experimentId}`
311
+ console . log ( `Non agree: ${ compoundKey } ` )
290
312
const user = usersDb . get ( compoundKey )
291
313
user . reset ( )
292
314
} )
@@ -301,7 +323,7 @@ function startReadyGames(experiments, agreementIds, usersDb) {
301
323
conditionObject . waitForCount === 0 &&
302
324
conditionObject . server === null
303
325
) {
304
- console . warn ( `[WARNING] experiment ${ experimentId } ran out of slots!` )
326
+ console . warn ( `[WARNING] Experiment ${ experimentId } ran out of slots!` )
305
327
scheduler . resetQueue ( )
306
328
conditionObject . users . forEach ( ( user ) => {
307
329
user . reset ( )
@@ -314,14 +336,16 @@ function startReadyGames(experiments, agreementIds, usersDb) {
314
336
315
337
async function main ( ) {
316
338
const experiments = { }
339
+ if ( options . resetDb && fs . existsSync ( userDbFile ) ) {
340
+ console . log ( `Deleting ${ userDbFile } file!` )
341
+ fs . unlinkSync ( userDbFile )
342
+ }
317
343
/**
318
344
*
319
- * @type {Map<string , User> }
345
+ * @type {Map<`${userId}:${experimentId}` , User> }
320
346
*/
321
- //const usersDb = new Map()
322
347
const usersDb = new UserDb ( userDbFile )
323
348
await usersDb . load ( )
324
- const userMapping = { }
325
349
const agreementIds = { }
326
350
const expToEnable = config . experiments . map ( ( e ) => e . name )
327
351
// Load schedulers from directory
@@ -406,21 +430,31 @@ async function main() {
406
430
"/api/lissparticipants/:userId" ,
407
431
validateSignature ,
408
432
async ( req , res ) => {
409
- const participantUrl = userMapping [ req . params . userId ]
410
- if ( ! participantUrl ) {
411
- res . status ( 404 ) . json ( { message : `${ req . params . userId } not found.` } )
412
- return
433
+ function flatten ( arr ) {
434
+ return arr . reduce ( function ( flat , toFlatten ) {
435
+ return flat . concat (
436
+ Array . isArray ( toFlatten ) ? flatten ( toFlatten ) : toFlatten ,
437
+ )
438
+ } , [ ] )
413
439
}
414
- const parseUrl = url . parse ( participantUrl )
415
- //const hostname = parseUrl.hostname
416
- const participantCode = lastElement ( parseUrl . pathname . split ( "/" ) )
417
- const results = await db . parQuery ( `SELECT *
418
- FROM otree_participant
419
- WHERE code = '${ participantCode } '` )
420
- const result = results . filter ( ( r ) => {
421
- return r . length !== 0
422
- } )
423
- res . status ( 201 ) . json ( result )
440
+ const results = usersDb
441
+ . find ( req . params . userId )
442
+ . map ( ( u ) => u . serialize ( ) )
443
+ . filter ( ( u ) => u . redirectedUrl )
444
+ . map ( async ( u ) => {
445
+ const participantUrl = u . redirectedUrl
446
+ const parseUrl = url . parse ( participantUrl )
447
+ const participantCode = lastElement ( parseUrl . pathname . split ( "/" ) )
448
+ const sqlResults = await db . parQuery ( `SELECT *
449
+ FROM otree_participant
450
+ WHERE code = '${ participantCode } '` )
451
+ const nonEmpty = sqlResults . filter ( ( r ) => {
452
+ return r . length !== 0
453
+ } )
454
+ return nonEmpty
455
+ } )
456
+ const vals = await Promise . all ( results )
457
+ res . status ( 201 ) . json ( flatten ( vals ) )
424
458
} ,
425
459
)
426
460
@@ -616,7 +650,7 @@ async function main() {
616
650
}
617
651
usersDb . get ( compoundKey ) . changeState ( "agreed" )
618
652
// If everyone agrees, start game
619
- if ( agreement . agree ( userId ) ) {
653
+ if ( agreement . agree ( compoundKey ) ) {
620
654
console . log ( "Start Game!" )
621
655
startGame ( agreement . agreedUsers , agreement . urls , agreement . experimentId )
622
656
}
@@ -638,23 +672,23 @@ async function main() {
638
672
console . log ( `Starting game with users: ${ users } and urls ${ urls } .` )
639
673
for ( let i = 0 ; i < users . length ; i ++ ) {
640
674
const userId = users [ i ]
641
- const compoundKey = `${ userId } :${ experimentId } `
675
+ // const compoundKey = `${userId}:${experimentId}`
676
+ const compoundKey = userId
642
677
const user = usersDb . get ( compoundKey )
643
678
user . changeState ( "redirected" )
644
679
const expUrl = new URL ( urls [ i ] )
645
- userMapping [ userId ] = expUrl
646
680
// Set user variables on oTree server
647
681
// Vars in oTree experiment template are accessed using
648
682
// the syntax {{ player.participant.vars.age }} where age is a var
649
- const oTreeVars = user . tokenParams ?. oTreeVars || { }
683
+ // const oTreeVars = user.tokenParams?.oTreeVars || {}
650
684
// First update user variables on oTree server
651
685
// then redirect
652
- const config = {
653
- headers : {
654
- "otree-rest-key" : otreeRestKey ,
655
- } ,
656
- }
657
- const participantCode = expUrl . pathname . split ( "/" ) . pop ( )
686
+ // const config = {
687
+ // headers: {
688
+ // "otree-rest-key": otreeRestKey,
689
+ // },
690
+ // }
691
+ // const participantCode = expUrl.pathname.split("/").pop()
658
692
const sock = user . webSocket
659
693
// Emit a custom event with the game room URL
660
694
user . redirectedUrl = `${ expUrl } ?participant_label=${ user . userId } `
0 commit comments