anear-js-api 0.3.33 → 0.3.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
const Ably = require('ably/promises')
|
|
3
3
|
const AnearApi = require('../api/AnearApi')
|
|
4
|
-
const ParticipantTimer = require('../utils/ParticipantTimer')
|
|
5
4
|
const logger = require('../utils/Logger')
|
|
6
5
|
|
|
7
6
|
const AppId = process.env.ANEARAPP_APP_ID
|
|
@@ -51,7 +50,6 @@ class AnearMessaging {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
this.eventChannels = {}
|
|
54
|
-
this.participantTimers = {}
|
|
55
53
|
|
|
56
54
|
this.initRealtime(clientOptions)
|
|
57
55
|
}
|
|
@@ -83,75 +81,6 @@ class AnearMessaging {
|
|
|
83
81
|
return this.realtime.channels.get(channelName, channelParams)
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
ensureParticipantTimer(anearEvent, participant, timeoutMsecs) {
|
|
87
|
-
// this is called when a new timer is being started for a privateMessage
|
|
88
|
-
// sent to a participant, or public message to all participants
|
|
89
|
-
// If the timer already exists and is paused, it is resumed with the timeRemaining
|
|
90
|
-
// [a starter function, timeRemaining] is returned
|
|
91
|
-
let timeRemaining = timeoutMsecs
|
|
92
|
-
let timerStarter = () => {}
|
|
93
|
-
|
|
94
|
-
if (timeoutMsecs > 0) {
|
|
95
|
-
const timer = this.participantTimers[participant.id] || this.createTimer(anearEvent, participant, timeoutMsecs)
|
|
96
|
-
|
|
97
|
-
if (timer.isRunning) {
|
|
98
|
-
timeRemaining = timer.interrupt()
|
|
99
|
-
} else {
|
|
100
|
-
timerStarter = () => timer.start(timeoutMsecs)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
logger.debug(`ensureParticipantTimer(timeRemaining: ${timeRemaining})`)
|
|
104
|
-
|
|
105
|
-
return [timerStarter, timeRemaining]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
createTimer(anearEvent, participant, timeoutMsecs) {
|
|
109
|
-
const timer = new ParticipantTimer(
|
|
110
|
-
participant.id,
|
|
111
|
-
async () => await this.timerExpired(anearEvent, participant, timeoutMsecs)
|
|
112
|
-
)
|
|
113
|
-
this.participantTimers[participant.id] = timer
|
|
114
|
-
|
|
115
|
-
return timer
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
destroyParticipantTimer(participantId) {
|
|
119
|
-
// participant will not be receiving any more display messages
|
|
120
|
-
// so we close out and delete the ParticipantTimer
|
|
121
|
-
const timer = this.participantTimers[participantId]
|
|
122
|
-
|
|
123
|
-
if (timer) {
|
|
124
|
-
timer.reset()
|
|
125
|
-
delete this.participantTimers[participantId]
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
resetAllParticipantTimers() {
|
|
130
|
-
// turns off all participant timers
|
|
131
|
-
Object.values(this.participantTimers).forEach(timer => timer.reset())
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
interruptParticipantTimer(participantId) {
|
|
135
|
-
const timer = this.participantTimers[participantId]
|
|
136
|
-
|
|
137
|
-
if (timer && timer.isRunning) timer.interrupt()
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
resetParticipantTimer(participantId) {
|
|
141
|
-
// called after participant takes Action before timer expires
|
|
142
|
-
const timer = this.participantTimers[participantId]
|
|
143
|
-
if (timer) timer.reset()
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async timerExpired(anearEvent, participant, timeoutMsecs) {
|
|
147
|
-
logger.debug(`participant (${anearEvent.id}, ${participant.id}) TIMED OUT after ${timeoutMsecs} msecs`)
|
|
148
|
-
|
|
149
|
-
delete this.participantTimers[participant.id]
|
|
150
|
-
|
|
151
|
-
await anearEvent.participantTimedOut(participant)
|
|
152
|
-
await anearEvent.update()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
84
|
async getAnearEventFromStorage(eventId) {
|
|
156
85
|
return await this.AnearEventClass.getFromStorage(eventId, this.AnearParticipantClass, this)
|
|
157
86
|
}
|
|
@@ -213,7 +142,7 @@ class AnearMessaging {
|
|
|
213
142
|
let loadedEvent = anearEvent
|
|
214
143
|
|
|
215
144
|
if (!eventExists) {
|
|
216
|
-
await anearEvent.runExclusive(
|
|
145
|
+
await anearEvent.runExclusive(`createEventCallback ${anearEvent.id}`, async () => {
|
|
217
146
|
await anearEvent.createdEventCallback()
|
|
218
147
|
await anearEvent.persist()
|
|
219
148
|
// start the state machine before initialiing Realtime Messaging
|
|
@@ -247,6 +176,8 @@ class AnearMessaging {
|
|
|
247
176
|
const anearEvent = new this.AnearEventClass(eventJson, this.AnearParticipantClass, this)
|
|
248
177
|
// This needs work!!
|
|
249
178
|
// loadedEvent = await this.getAnearEventFromStorage(anearEvent.id)
|
|
179
|
+
// NOTE: there should be existing presence state to read from action channel
|
|
180
|
+
// to drive this...not a reload from storage
|
|
250
181
|
// await this.refreshActiveParticipants(loadedEvent)
|
|
251
182
|
// await this.initEventRealtimeMessaging(loadedEvent)
|
|
252
183
|
// loadedEvent.startStateMachine()
|
|
@@ -260,7 +191,7 @@ class AnearMessaging {
|
|
|
260
191
|
|
|
261
192
|
async refreshActiveParticipants(anearEvent) {
|
|
262
193
|
await this.participants.reloadFromStorage(
|
|
263
|
-
p => this.processParticipantEnter(anearEvent, p.id
|
|
194
|
+
p => this.processParticipantEnter(anearEvent, p.id)
|
|
264
195
|
)
|
|
265
196
|
}
|
|
266
197
|
|
|
@@ -397,7 +328,7 @@ class AnearMessaging {
|
|
|
397
328
|
await this.processParticipantEnter(anearEvent, participantId, geoLocation)
|
|
398
329
|
}
|
|
399
330
|
|
|
400
|
-
async processParticipantEnter(anearEvent, participantId, geoLocation) {
|
|
331
|
+
async processParticipantEnter(anearEvent, participantId, geoLocation = null) {
|
|
401
332
|
|
|
402
333
|
logger.debug(`processing Participant Enter for event: ${anearEvent.id}, participant: ${participantId}`)
|
|
403
334
|
//
|
|
@@ -409,15 +340,15 @@ class AnearMessaging {
|
|
|
409
340
|
const participantJson = await this.api.getEventParticipantJson(participantId)
|
|
410
341
|
const participant = new this.AnearParticipantClass(participantJson, anearEvent)
|
|
411
342
|
|
|
412
|
-
participant.geoLocation = geoLocation // stored in-memory only
|
|
413
|
-
|
|
414
343
|
const persistedAnearParticipant = await this.getAnearParticipantFromStorage(participantId, anearEvent)
|
|
415
344
|
|
|
416
345
|
if (persistedAnearParticipant) {
|
|
417
346
|
participant.context = persistedAnearParticipant.context
|
|
418
347
|
}
|
|
419
348
|
|
|
420
|
-
await anearEvent.runExclusive(
|
|
349
|
+
await anearEvent.runExclusive(`participantEnterCallback ${participant.id}`, async () => {
|
|
350
|
+
participant.geoLocation = geoLocation
|
|
351
|
+
|
|
421
352
|
await this.setupPrivatePublishingChannel(participant)
|
|
422
353
|
await anearEvent.participantEnter(participant)
|
|
423
354
|
await anearEvent.update()
|
|
@@ -444,13 +375,15 @@ class AnearMessaging {
|
|
|
444
375
|
}
|
|
445
376
|
|
|
446
377
|
async participantLeaveMessagingCallback(anearEvent, message) {
|
|
447
|
-
// this can be just a temporary leave (a participant refreshing their browser for example),
|
|
378
|
+
// this can be just a temporary leave (a participant refreshing their browser for example),
|
|
379
|
+
// so pause any participant timers
|
|
448
380
|
const userId = message.clientId
|
|
449
381
|
const participantId = message.data.id
|
|
382
|
+
const participant = anearEvent.participants.getById(participantId)
|
|
450
383
|
|
|
451
|
-
logger.debug(`**** LEAVE PARTICIPANT **** participantLeaveMessagingCallback(participant: ${
|
|
384
|
+
logger.debug(`**** LEAVE PARTICIPANT **** participantLeaveMessagingCallback(participant: ${participant.id})`)
|
|
452
385
|
|
|
453
|
-
|
|
386
|
+
participant.interruptTimer()
|
|
454
387
|
}
|
|
455
388
|
|
|
456
389
|
async closeParticipant(anearEvent, participantId, callback = null) {
|
|
@@ -460,14 +393,14 @@ class AnearMessaging {
|
|
|
460
393
|
// and cleaning out any remaining participants.
|
|
461
394
|
logger.debug(`closeParticipant(${participantId})`)
|
|
462
395
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const participant = await this.getAnearParticipantFromStorage(participantId, anearEvent)
|
|
396
|
+
const participant = anearEvent.participants.getById(participantId)
|
|
466
397
|
|
|
467
398
|
if (participant) {
|
|
399
|
+
participant.destroyTimer()
|
|
400
|
+
|
|
468
401
|
await this.detachParticipantPrivateChannel(anearEvent.id, participant)
|
|
469
402
|
|
|
470
|
-
await anearEvent.runExclusive(
|
|
403
|
+
await anearEvent.runExclusive(`closeParticipant ${participant.id}`, async () => {
|
|
471
404
|
if (callback) {
|
|
472
405
|
await callback(anearEvent, participant)
|
|
473
406
|
}
|
|
@@ -499,16 +432,16 @@ class AnearMessaging {
|
|
|
499
432
|
const participantId = message.data.participantId
|
|
500
433
|
const payload = message.data.payload
|
|
501
434
|
|
|
502
|
-
|
|
435
|
+
const participant = anearEvent.participants.getById(participantId)
|
|
436
|
+
|
|
437
|
+
participant.resetTimer() // participant responded in time, reset any running timer
|
|
503
438
|
|
|
504
439
|
logger.debug(`participantActionMessagingCallback(${anearEvent.id}, ${participantId})`)
|
|
505
440
|
|
|
506
441
|
const actionJSON = JSON.parse(payload)
|
|
507
442
|
const [actionEventName, actionPayload] = Object.entries(actionJSON)[0]
|
|
508
443
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
await anearEvent.runExclusive("participantActionCallback", async () => {
|
|
444
|
+
await anearEvent.runExclusive(`participantActionCallback ${participant.id}`, async () => {
|
|
512
445
|
await anearEvent.participantAction(participant, actionEventName, actionPayload)
|
|
513
446
|
await anearEvent.update()
|
|
514
447
|
await participant.update()
|
|
@@ -579,14 +512,14 @@ class AnearMessaging {
|
|
|
579
512
|
)
|
|
580
513
|
}
|
|
581
514
|
|
|
582
|
-
setMultipleParticipantTimers(
|
|
515
|
+
setMultipleParticipantTimers(participants, timeoutMsecs) {
|
|
583
516
|
if (timeoutMsecs === 0) return [() => {}, 0]
|
|
584
517
|
|
|
585
518
|
const participantTimers = []
|
|
586
519
|
|
|
587
520
|
participants.forEach(
|
|
588
521
|
participant => {
|
|
589
|
-
const [startTimer, _timeRemaining] =
|
|
522
|
+
const [startTimer, _timeRemaining] = participant.ensureTimer(timeoutMsecs)
|
|
590
523
|
participantTimers.push(startTimer)
|
|
591
524
|
}
|
|
592
525
|
)
|
|
@@ -598,7 +531,7 @@ class AnearMessaging {
|
|
|
598
531
|
const eventId = anearEvent.id
|
|
599
532
|
const channel = this.eventChannels[eventId].participants
|
|
600
533
|
|
|
601
|
-
const [startTimers, timeRemaining] = this.setMultipleParticipantTimers(
|
|
534
|
+
const [startTimers, timeRemaining] = this.setMultipleParticipantTimers(participants, timeoutMsecs)
|
|
602
535
|
|
|
603
536
|
await this.publishMessage(
|
|
604
537
|
channel,
|
|
@@ -623,7 +556,7 @@ class AnearMessaging {
|
|
|
623
556
|
const channel = this.eventChannels[anearEvent.id].privates[userId]
|
|
624
557
|
if (!channel) throw new Error(`private channel not found. invalid user id ${userId}`)
|
|
625
558
|
|
|
626
|
-
const [startTimer, timeRemaining] =
|
|
559
|
+
const [startTimer, timeRemaining] = participant.ensureTimer(timeoutMsecs)
|
|
627
560
|
|
|
628
561
|
await this.publishMessage(
|
|
629
562
|
channel,
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict"
|
|
2
|
+
|
|
2
3
|
const JsonApiResource = require('./JsonApiResource')
|
|
4
|
+
const ParticipantTimer = require('../utils/ParticipantTimer')
|
|
5
|
+
const logger = require('../utils/Logger')
|
|
6
|
+
|
|
3
7
|
const HostUserType = "host"
|
|
4
8
|
|
|
5
9
|
class AnearParticipant extends JsonApiResource {
|
|
6
10
|
constructor(json, anearEvent) {
|
|
7
11
|
super(json)
|
|
8
12
|
this.anearEvent = anearEvent
|
|
13
|
+
this.timer = null
|
|
9
14
|
this._state = json.state
|
|
10
15
|
this._timestamp = json.timestamp
|
|
11
16
|
this._geoLocation = null
|
|
@@ -78,6 +83,59 @@ class AnearParticipant extends JsonApiResource {
|
|
|
78
83
|
get privateChannelName() {
|
|
79
84
|
return this.attributes['private-channel-name']
|
|
80
85
|
}
|
|
86
|
+
|
|
87
|
+
ensureTimer(timeoutMsecs) {
|
|
88
|
+
// this is called when a new timer is being started for a privateMessage
|
|
89
|
+
// sent to a participant, or public message to all participants
|
|
90
|
+
// If the timer already exists and is paused, it is resumed with the timeRemaining
|
|
91
|
+
// [a starter function, timeRemaining] is returned
|
|
92
|
+
let timeRemaining = timeoutMsecs
|
|
93
|
+
let timerStarter = () => {}
|
|
94
|
+
|
|
95
|
+
if (timeoutMsecs > 0) {
|
|
96
|
+
|
|
97
|
+
this.timer ||= new ParticipantTimer(
|
|
98
|
+
this.id,
|
|
99
|
+
async () => await this.timerExpired(timeoutMsecs)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if (this.timer.isRunning) {
|
|
103
|
+
timeRemaining = this.timer.interrupt()
|
|
104
|
+
} else {
|
|
105
|
+
timerStarter = () => this.timer.start(timeoutMsecs)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
logger.debug(`ensureTimer(timeRemaining: ${timeRemaining})`)
|
|
109
|
+
|
|
110
|
+
return [timerStarter, timeRemaining]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
destroyTimer() {
|
|
114
|
+
// participant will not be receiving any more display messages
|
|
115
|
+
// so we close out and delete the timer
|
|
116
|
+
if (this.timer) {
|
|
117
|
+
this.timer.reset()
|
|
118
|
+
this.timer = null
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async timerExpired(timeoutMsecs) {
|
|
123
|
+
logger.debug(`participant (${this.anearEvent.id}, ${this.id}) TIMED OUT after ${timeoutMsecs} msecs`)
|
|
124
|
+
|
|
125
|
+
this.timer = null
|
|
126
|
+
|
|
127
|
+
await this.anearEvent.participantTimedOut(this)
|
|
128
|
+
await this.anearEvent.update()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interruptTimer() {
|
|
132
|
+
if (this.timer && this.timer.isRunning) this.timer.interrupt()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
resetTimer() {
|
|
136
|
+
// called after participant takes Action before timer expires
|
|
137
|
+
if (this.timer) this.timer.reset()
|
|
138
|
+
}
|
|
81
139
|
}
|
|
82
140
|
|
|
83
141
|
module.exports = AnearParticipant
|