anear-js-api 0.2.2 → 0.3.2
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.
- package/lib/api/AnearApi.js +8 -1
- package/lib/api/ApiService.js +1 -1
- package/lib/index.js +2 -3
- package/lib/messaging/AnearMessaging.js +144 -105
- package/lib/models/AnearEvent.js +125 -69
- package/lib/models/JsonApiResource.js +5 -38
- package/lib/utils/AnearXstate.js +71 -0
- package/lib/utils/AnearXstateDefaults.js +108 -0
- package/lib/utils/Logger.js +11 -7
- package/lib/utils/Participants.js +10 -2
- package/lib/utils/Persist.js +1 -31
- package/package.json +7 -6
- package/tests/AnearEvent.test.js +250 -129
- package/tests/AnearParticipant.test.js +5 -5
- package/tests/Participants.test.js +18 -5
- package/tests/Persist.test.js +0 -42
package/lib/api/AnearApi.js
CHANGED
|
@@ -24,6 +24,13 @@ class AnearApi extends ApiService {
|
|
|
24
24
|
return json
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
async getApp(appId) {
|
|
28
|
+
logger.debug(`API: GET app ${appId}`)
|
|
29
|
+
|
|
30
|
+
const json = await this.get("apps", {id: appId})
|
|
31
|
+
return json
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
async getZoneEvents(zoneId) {
|
|
28
35
|
logger.debug(`API: GET zone_events ${zoneId}`)
|
|
29
36
|
|
|
@@ -38,7 +45,7 @@ class AnearApi extends ApiService {
|
|
|
38
45
|
try {
|
|
39
46
|
const json = await this.post("transitions", {event_name: eventName}, relationships)
|
|
40
47
|
const attrs = json.data.attributes
|
|
41
|
-
logger.info(`newState is ${attrs.state}`)
|
|
48
|
+
logger.info(`API: newState is ${attrs.state}`)
|
|
42
49
|
return attrs
|
|
43
50
|
} catch(err) {
|
|
44
51
|
logger.error(err)
|
package/lib/api/ApiService.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const JsonApiResource = require('./models/JsonApiResource')
|
|
4
4
|
const JsonApiArrayResource = require('./models/JsonApiArrayResource')
|
|
5
|
-
const AnearEvent = require('./models/AnearEvent')
|
|
5
|
+
const {AnearEvent, logger} = require('./models/AnearEvent')
|
|
6
6
|
const AnearParticipant = require('./models/AnearParticipant')
|
|
7
7
|
const AnearMessaging = require('./messaging/AnearMessaging')
|
|
8
8
|
const AnearApiService = require('./api/ApiService')
|
|
9
|
-
const Logger = require('./utils/Logger')
|
|
10
9
|
const Fixtures = require('../tests/fixtures')
|
|
11
10
|
const MockMessaging = require('./messaging/__mocks__/AnearMessaging')
|
|
12
11
|
|
|
@@ -14,10 +13,10 @@ module.exports = {
|
|
|
14
13
|
JsonApiResource,
|
|
15
14
|
JsonApiArrayResource,
|
|
16
15
|
AnearEvent,
|
|
16
|
+
logger,
|
|
17
17
|
AnearParticipant,
|
|
18
18
|
AnearMessaging,
|
|
19
19
|
AnearApiService,
|
|
20
|
-
Logger,
|
|
21
20
|
Fixtures,
|
|
22
21
|
MockMessaging,
|
|
23
22
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const Ably = require('ably/promises')
|
|
3
3
|
const AnearApi = require('../api/AnearApi')
|
|
4
4
|
const logger = require('../utils/Logger')
|
|
5
|
+
const { Mutex } = require('async-mutex')
|
|
5
6
|
|
|
6
7
|
const AppId = process.env.ANEARAPP_APP_ID
|
|
7
8
|
|
|
@@ -12,6 +13,9 @@ const CreateEventMessageType = 'create_event'
|
|
|
12
13
|
const ExitEventMessageType = 'exit_event'
|
|
13
14
|
const EventTransitionMessageType = 'event_transition'
|
|
14
15
|
|
|
16
|
+
const PRESENCE_ENTER = 'enter'
|
|
17
|
+
const PRESENCE_LEAVE = 'leave'
|
|
18
|
+
|
|
15
19
|
// any channel messages sent with 5 secs (5s) of initial attach will be delivered
|
|
16
20
|
// to the subscribers
|
|
17
21
|
const ChannelParams = {params: {rewind: "5s"}}
|
|
@@ -26,6 +30,7 @@ class AnearMessaging {
|
|
|
26
30
|
this.api = new AnearApi()
|
|
27
31
|
this.AnearEventClass = AnearEventClass
|
|
28
32
|
this.AnearParticipantClass = AnearParticipantClass
|
|
33
|
+
this.mutex = new Mutex()
|
|
29
34
|
|
|
30
35
|
|
|
31
36
|
const baseUrl = this.api.api_base_url
|
|
@@ -62,13 +67,21 @@ class AnearMessaging {
|
|
|
62
67
|
this.realtime.connection.on(
|
|
63
68
|
"connected",
|
|
64
69
|
async () => {
|
|
70
|
+
await this.getAppInfo(AppId)
|
|
65
71
|
logger.info("Ably connected!")
|
|
66
|
-
await this.reloadAnyEventsInProgress(AppId)
|
|
67
72
|
await this.setupCreateEventChannel()
|
|
73
|
+
await this.reloadAnyEventsInProgress(AppId)
|
|
68
74
|
}
|
|
69
75
|
)
|
|
70
76
|
}
|
|
71
77
|
|
|
78
|
+
async getAppInfo(appId) {
|
|
79
|
+
const anearApp = await this.api.getApp(appId)
|
|
80
|
+
logger.info("================")
|
|
81
|
+
logger.info(`STARTING APP ${anearApp.data.attributes['short-name']}`)
|
|
82
|
+
logger.info("================")
|
|
83
|
+
}
|
|
84
|
+
|
|
72
85
|
getChannel(channelName, channelParams = ChannelParams) {
|
|
73
86
|
return this.realtime.channels.get(channelName, channelParams)
|
|
74
87
|
}
|
|
@@ -81,31 +94,31 @@ class AnearMessaging {
|
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
setParticipantTimer(eventId,
|
|
85
|
-
const participantId =
|
|
97
|
+
setParticipantTimer(eventId, participant, timeoutMilliseconds) {
|
|
98
|
+
const participantId = participant.id
|
|
86
99
|
|
|
87
100
|
this.clearParticipantTimer(participantId)
|
|
88
101
|
|
|
89
102
|
if (timeoutMilliseconds === 0) return
|
|
90
103
|
|
|
91
|
-
logger.debug(`setting ${timeoutMilliseconds} msec timer for event ${eventId}, participant ${
|
|
104
|
+
logger.debug(`setting ${timeoutMilliseconds} msec timer for event ${eventId}, participant ${participant.id}`)
|
|
92
105
|
|
|
93
106
|
this.participantTimers[participantId] = setTimeout(
|
|
94
|
-
async () => await this.timerExpired(eventId,
|
|
107
|
+
async () => await this.timerExpired(eventId, participant, timeoutMilliseconds),
|
|
95
108
|
timeoutMilliseconds
|
|
96
109
|
)
|
|
97
110
|
}
|
|
98
111
|
|
|
99
|
-
async timerExpired(eventId,
|
|
100
|
-
const participantId =
|
|
112
|
+
async timerExpired(eventId, participant, timeoutMilliseconds) {
|
|
113
|
+
const participantId = participant.id
|
|
101
114
|
|
|
102
115
|
logger.debug(`participant (${eventId}, ${participantId}) TIMED OUT after ${timeoutMilliseconds} msecs`)
|
|
103
116
|
|
|
104
117
|
await this.getAnearEventWithLockFromStorage(
|
|
105
118
|
eventId,
|
|
106
119
|
async anearEvent => {
|
|
107
|
-
const
|
|
108
|
-
await anearEvent.participantTimedOut(
|
|
120
|
+
const participant = await this.getAnearParticipantFromStorage(participantId)
|
|
121
|
+
await anearEvent.participantTimedOut(participant)
|
|
109
122
|
await anearEvent.update()
|
|
110
123
|
}
|
|
111
124
|
)
|
|
@@ -115,25 +128,10 @@ class AnearMessaging {
|
|
|
115
128
|
return await this.AnearEventClass.getFromStorage(eventId, this)
|
|
116
129
|
}
|
|
117
130
|
|
|
118
|
-
async getAnearEventWithLockFromStorage(eventId, callback) {
|
|
119
|
-
return await this.AnearEventClass.getWithLockFromStorage(
|
|
120
|
-
eventId,
|
|
121
|
-
callback,
|
|
122
|
-
this
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
131
|
async getAnearParticipantFromStorage(participantId) {
|
|
127
132
|
return await this.AnearParticipantClass.getFromStorage(participantId)
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
async getAnearParticipantWithLockFromStorage(participantId, callback) {
|
|
131
|
-
return await this.AnearParticipantClass.getWithLockFromStorage(
|
|
132
|
-
participantId,
|
|
133
|
-
callback
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
135
|
async initEventRealtimeMessaging(anearEvent) {
|
|
138
136
|
|
|
139
137
|
if (this.eventChannels.hasOwnProperty(anearEvent.id)) {
|
|
@@ -162,34 +160,45 @@ class AnearMessaging {
|
|
|
162
160
|
// create the AnearEvent subclass, persist it in storage, and
|
|
163
161
|
// initialize its realtime messaging
|
|
164
162
|
//
|
|
165
|
-
logger.info(`
|
|
163
|
+
logger.info(`createEventMessagingCallback(${message.name})`)
|
|
166
164
|
|
|
167
165
|
try {
|
|
168
166
|
const eventJson = JSON.parse(message.data)
|
|
169
167
|
const anearEvent = new this.AnearEventClass(eventJson, this)
|
|
168
|
+
|
|
170
169
|
//
|
|
171
170
|
// if we are getting this event create message from history after a quick restart,
|
|
172
171
|
// we just return if the event already exists
|
|
173
172
|
//
|
|
174
|
-
await this.
|
|
173
|
+
await this.loadOrPersistEventAndInitialize(anearEvent)
|
|
175
174
|
} catch(err) {
|
|
176
175
|
logger.error(err)
|
|
177
176
|
}
|
|
178
177
|
}
|
|
179
178
|
|
|
180
|
-
async
|
|
179
|
+
async loadOrPersistEventAndInitialize(anearEvent) {
|
|
181
180
|
const eventExists = await anearEvent.exists()
|
|
182
181
|
|
|
183
182
|
logger.info(`Event ${anearEvent.id} ${eventExists ? "already exists" : "does not exist"} in Storage`)
|
|
184
183
|
|
|
184
|
+
let loadedEvent = anearEvent
|
|
185
|
+
|
|
185
186
|
if (!eventExists) {
|
|
186
|
-
await
|
|
187
|
-
|
|
187
|
+
await this.runExclusive("createEventCallback", async () => {
|
|
188
|
+
await anearEvent.createdEventCallback()
|
|
189
|
+
await anearEvent.persist()
|
|
190
|
+
anearEvent.startStateMachine()
|
|
191
|
+
await this.initEventRealtimeMessaging(anearEvent)
|
|
192
|
+
})
|
|
193
|
+
} else {
|
|
194
|
+
loadedEvent = await this.getAnearEventFromStorage(anearEvent.id)
|
|
195
|
+
await this.initEventRealtimeMessaging(loadedEvent)
|
|
196
|
+
loadedEvent.startStateMachine()
|
|
188
197
|
}
|
|
189
198
|
|
|
190
|
-
logger.info(`New ${
|
|
199
|
+
logger.info(`New ${loadedEvent.constructor.name} Event: `, loadedEvent.toJSON())
|
|
191
200
|
|
|
192
|
-
|
|
201
|
+
return loadedEvent
|
|
193
202
|
}
|
|
194
203
|
|
|
195
204
|
async reloadAnyEventsInProgress(appId) {
|
|
@@ -202,7 +211,8 @@ class AnearMessaging {
|
|
|
202
211
|
for (const eventData of events) {
|
|
203
212
|
const eventJson = await this.api.getEvent(eventData.id)
|
|
204
213
|
const anearEvent = new this.AnearEventClass(eventJson, this)
|
|
205
|
-
await this.
|
|
214
|
+
// const loadedEvent = await this.loadOrPersistEventAndInitialize(anearEvent)
|
|
215
|
+
// await this.refreshActiveParticipants(loadedEvent) DOES NOT WORK YET
|
|
206
216
|
}
|
|
207
217
|
}
|
|
208
218
|
} catch (err) {
|
|
@@ -210,6 +220,20 @@ class AnearMessaging {
|
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
|
|
223
|
+
async refreshActiveParticipants(anearEvent) {
|
|
224
|
+
const allParticipants = anearEvent.participants.active(false)
|
|
225
|
+
|
|
226
|
+
return Promise.all(
|
|
227
|
+
allParticipants.map(
|
|
228
|
+
async participant => await this.processParticipantEnter(
|
|
229
|
+
anearEvent,
|
|
230
|
+
participant.id,
|
|
231
|
+
participant.geoLocation
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
213
237
|
async setupCreateEventChannel() {
|
|
214
238
|
logger.info(`attaching to channel ${AnearCreateEventChannelName}`)
|
|
215
239
|
|
|
@@ -238,14 +262,14 @@ class AnearMessaging {
|
|
|
238
262
|
|
|
239
263
|
this.subscribePresenceEvent(
|
|
240
264
|
spectatorsChannel,
|
|
241
|
-
|
|
242
|
-
async message => await this.spectatorEnterMessagingCallback(anearEvent
|
|
265
|
+
PRESENCE_ENTER,
|
|
266
|
+
async message => await this.spectatorEnterMessagingCallback(anearEvent, message)
|
|
243
267
|
)
|
|
244
268
|
|
|
245
269
|
this.subscribePresenceEvent(
|
|
246
270
|
spectatorsChannel,
|
|
247
|
-
|
|
248
|
-
async message => await this.spectatorLeaveMessagingCallback(anearEvent
|
|
271
|
+
PRESENCE_LEAVE,
|
|
272
|
+
async message => await this.spectatorLeaveMessagingCallback(anearEvent, message)
|
|
249
273
|
)
|
|
250
274
|
}
|
|
251
275
|
|
|
@@ -258,23 +282,23 @@ class AnearMessaging {
|
|
|
258
282
|
|
|
259
283
|
await this.subscribePresenceEventWithHistory(
|
|
260
284
|
actionsChannel,
|
|
261
|
-
|
|
262
|
-
async message => await this.participantEnterMessagingCallback(anearEvent
|
|
285
|
+
PRESENCE_ENTER,
|
|
286
|
+
async message => await this.participantEnterMessagingCallback(anearEvent, message)
|
|
263
287
|
)
|
|
264
288
|
this.subscribeEventMessages(
|
|
265
289
|
actionsChannel,
|
|
266
290
|
ActionMessageType,
|
|
267
|
-
async message => await this.participantActionMessagingCallback(anearEvent
|
|
291
|
+
async message => await this.participantActionMessagingCallback(anearEvent, message)
|
|
268
292
|
)
|
|
269
293
|
this.subscribePresenceEvent(
|
|
270
294
|
actionsChannel,
|
|
271
|
-
|
|
272
|
-
async message => await this.participantLeaveMessagingCallback(anearEvent
|
|
295
|
+
PRESENCE_LEAVE,
|
|
296
|
+
async message => await this.participantLeaveMessagingCallback(anearEvent, message)
|
|
273
297
|
)
|
|
274
298
|
this.subscribeEventMessages(
|
|
275
299
|
actionsChannel,
|
|
276
300
|
ExitEventMessageType,
|
|
277
|
-
async message => await this.participantExplicitExitMessagingCallback(anearEvent
|
|
301
|
+
async message => await this.participantExplicitExitMessagingCallback(anearEvent, message)
|
|
278
302
|
)
|
|
279
303
|
}
|
|
280
304
|
|
|
@@ -298,20 +322,22 @@ class AnearMessaging {
|
|
|
298
322
|
return participantsChannel
|
|
299
323
|
}
|
|
300
324
|
|
|
301
|
-
async participantExplicitExitMessagingCallback(
|
|
325
|
+
async participantExplicitExitMessagingCallback(anearEvent, message) {
|
|
302
326
|
//
|
|
303
327
|
// client user deliberately cancels out of event
|
|
304
328
|
//
|
|
305
329
|
const participantId = message.data.participantId
|
|
306
330
|
|
|
307
|
-
logger.debug(`ExitEventMessage received from ${participantId} for event ${
|
|
331
|
+
logger.debug(`ExitEventMessage received from ${participantId} for event ${anearEvent.id}`)
|
|
308
332
|
|
|
309
|
-
await this.closeParticipant(
|
|
310
|
-
|
|
333
|
+
await this.closeParticipant(
|
|
334
|
+
anearEvent,
|
|
335
|
+
participantId,
|
|
336
|
+
(anearEvent, participant) => anearEvent.participantClose(participant)
|
|
311
337
|
)
|
|
312
338
|
}
|
|
313
339
|
|
|
314
|
-
async participantEnterMessagingCallback(
|
|
340
|
+
async participantEnterMessagingCallback(anearEvent, presenceMessage) {
|
|
315
341
|
// presenceMessage.clientId is the participant's user_id
|
|
316
342
|
// presenceMessage.data = {
|
|
317
343
|
// id: participantId,
|
|
@@ -321,89 +347,83 @@ class AnearMessaging {
|
|
|
321
347
|
const participantId = presenceMessage.data.id
|
|
322
348
|
const geoLocation = presenceMessage.data.geoLocation
|
|
323
349
|
|
|
324
|
-
logger.debug(`**** ENTER PARTICIPANT **** event: ${
|
|
350
|
+
logger.debug(`**** ENTER PARTICIPANT **** event: ${anearEvent.id}, participant: ${participantId}`)
|
|
325
351
|
|
|
352
|
+
await this.processParticipantEnter(anearEvent, participantId, geoLocation)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async processParticipantEnter(anearEvent, participantId, geoLocation) {
|
|
356
|
+
|
|
357
|
+
logger.debug(`processing Participant Enter for event: ${anearEvent.id}, participant: ${participantId}`)
|
|
326
358
|
//
|
|
327
359
|
// get the participant data from the API (this will also validate the participant).
|
|
328
360
|
// check if the participant is already in storage, and if so, instantiate, else
|
|
329
361
|
// instantiate from API response
|
|
330
362
|
//
|
|
331
363
|
try {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const anearParticipantJson = await this.api.getEventParticipantJson(participantId)
|
|
335
|
-
const anearParticipant = new this.AnearParticipantClass(anearParticipantJson)
|
|
364
|
+
const participantJson = await this.api.getEventParticipantJson(participantId)
|
|
365
|
+
const participant = new this.AnearParticipantClass(participantJson)
|
|
336
366
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
await this.setupPrivatePublishingChannel(anearParticipant)
|
|
367
|
+
participant.geoLocation = geoLocation
|
|
340
368
|
|
|
341
369
|
const persistedAnearParticipant = await this.AnearParticipantClass.getFromStorage(participantId)
|
|
342
370
|
|
|
343
|
-
const eventLockCallback = async (anearEvent) => {
|
|
344
|
-
await anearEvent.participantEnter(anearParticipant)
|
|
345
|
-
await anearEvent.update()
|
|
346
|
-
}
|
|
347
|
-
|
|
348
371
|
if (persistedAnearParticipant) {
|
|
349
|
-
|
|
350
|
-
await anearParticipant.update()
|
|
372
|
+
participant.context = persistedAnearParticipant.context
|
|
351
373
|
}
|
|
352
374
|
|
|
353
|
-
await this.
|
|
354
|
-
|
|
375
|
+
await this.runExclusive("participantEnterCallback", async () => {
|
|
376
|
+
await this.setupPrivatePublishingChannel(participant)
|
|
377
|
+
await anearEvent.participantEnter(participant)
|
|
378
|
+
await anearEvent.update()
|
|
379
|
+
})
|
|
355
380
|
} catch(error) {
|
|
356
381
|
// participant not found or is not currently marked active at the API service
|
|
357
382
|
// don't allow participation. FIX: we need to publish to the private channel
|
|
358
383
|
// with an error message type.
|
|
359
|
-
logger.error(`
|
|
384
|
+
logger.error(`processParticipanEnter(${anearEvent.id}, ${participantId}) error: `, error)
|
|
360
385
|
}
|
|
361
386
|
}
|
|
362
387
|
|
|
363
|
-
async spectatorEnterMessagingCallback(
|
|
388
|
+
async spectatorEnterMessagingCallback(anearEvent, message) {
|
|
364
389
|
const userId = message.clientId
|
|
365
|
-
const anearEvent = await this.getAnearEventFromStorage(eventId)
|
|
366
390
|
|
|
367
|
-
logger.debug(`**** ENTER SPECTATOR **** event: ${
|
|
391
|
+
logger.debug(`**** ENTER SPECTATOR **** event: ${anearEvent.id}, user: ${userId}`)
|
|
368
392
|
|
|
369
393
|
await anearEvent.refreshSpectator()
|
|
370
394
|
}
|
|
371
395
|
|
|
372
|
-
async spectatorLeaveMessagingCallback(
|
|
396
|
+
async spectatorLeaveMessagingCallback(anearEvent, message) {
|
|
373
397
|
const userId = message.clientId
|
|
374
|
-
logger.debug(`**** LEAVE SPECTATOR **** event: ${
|
|
398
|
+
logger.debug(`**** LEAVE SPECTATOR **** event: ${anearEvent.id}, user: ${userId}`)
|
|
375
399
|
}
|
|
376
400
|
|
|
377
|
-
async participantLeaveMessagingCallback(
|
|
401
|
+
async participantLeaveMessagingCallback(anearEvent, message) {
|
|
378
402
|
// this can be just a temporary leave (refresh browser for example), so we don't do anything
|
|
379
403
|
// for now
|
|
380
404
|
const userId = message.clientId
|
|
381
405
|
logger.debug(`**** LEAVE PARTICIPANT **** participantLeaveMessagingCallback(user: ${userId})`)
|
|
382
406
|
}
|
|
383
407
|
|
|
384
|
-
async closeParticipant(
|
|
408
|
+
async closeParticipant(anearEvent, participantId, callback) {
|
|
385
409
|
logger.debug(`closeParticipant(${participantId})`)
|
|
386
410
|
|
|
387
411
|
this.clearParticipantTimer(participantId)
|
|
388
412
|
|
|
389
|
-
await this.
|
|
390
|
-
eventId,
|
|
391
|
-
async (anearEvent) => {
|
|
392
|
-
const anearParticipant = await this.getAnearParticipantFromStorage(participantId)
|
|
393
|
-
|
|
413
|
+
const participant = await this.getAnearParticipantFromStorage(participantId)
|
|
394
414
|
|
|
395
|
-
|
|
396
|
-
|
|
415
|
+
if (participant) {
|
|
416
|
+
await this.detachParticipantPrivateChannel(anearEvent.id, participant)
|
|
397
417
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
418
|
+
await this.runExclusive("closeParticipant", async () => {
|
|
419
|
+
await callback(anearEvent, participant)
|
|
420
|
+
await anearEvent.update()
|
|
421
|
+
})
|
|
422
|
+
}
|
|
403
423
|
}
|
|
404
424
|
|
|
405
|
-
async detachParticipantPrivateChannel(eventId,
|
|
406
|
-
const userId =
|
|
425
|
+
async detachParticipantPrivateChannel(eventId, participant) {
|
|
426
|
+
const userId = participant.userId
|
|
407
427
|
const channel = this.eventChannels[eventId].privates[userId]
|
|
408
428
|
|
|
409
429
|
if (channel) {
|
|
@@ -411,26 +431,33 @@ class AnearMessaging {
|
|
|
411
431
|
delete this.eventChannels[eventId].privates[userId]
|
|
412
432
|
}
|
|
413
433
|
}
|
|
414
|
-
|
|
415
|
-
|
|
434
|
+
async participantActionMessagingCallback(anearEvent, message) {
|
|
435
|
+
// e.g. message.data
|
|
436
|
+
// {
|
|
437
|
+
// participantId: "93387343489",
|
|
438
|
+
// payload: "{"reviewResponse":{"questionId": "ab88373ccf", "decision":"approved"}}"
|
|
439
|
+
// }
|
|
440
|
+
//
|
|
441
|
+
// actionEventName => "reviewResponse"
|
|
442
|
+
// actionPayload => {questionId: "ab88373ccf", decision:"approved"}
|
|
443
|
+
//
|
|
416
444
|
const payload = message.data.payload
|
|
417
445
|
const participantId = message.data.participantId
|
|
418
446
|
|
|
419
|
-
logger.debug(`participantActionMessagingCallback(${
|
|
447
|
+
logger.debug(`participantActionMessagingCallback(${anearEvent.id}, ${participantId})`)
|
|
420
448
|
|
|
421
449
|
this.clearParticipantTimer(participantId)
|
|
422
450
|
|
|
423
451
|
const actionJSON = JSON.parse(payload)
|
|
424
452
|
const [actionEventName, actionPayload] = Object.entries(actionJSON)[0]
|
|
425
453
|
|
|
426
|
-
await this.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
)
|
|
454
|
+
const participant = await this.getAnearParticipantFromStorage(participantId)
|
|
455
|
+
|
|
456
|
+
await this.runExclusive("participantActionCallback", async () => {
|
|
457
|
+
await anearEvent.participantAction(participant, actionEventName, actionPayload)
|
|
458
|
+
await anearEvent.update()
|
|
459
|
+
await participant.update()
|
|
460
|
+
})
|
|
434
461
|
}
|
|
435
462
|
|
|
436
463
|
async eventBroadcastMessagingCallback(eventId, message) {
|
|
@@ -441,12 +468,12 @@ class AnearMessaging {
|
|
|
441
468
|
await anearEvent.update()
|
|
442
469
|
}
|
|
443
470
|
|
|
444
|
-
async setupPrivatePublishingChannel(
|
|
445
|
-
const privateChannel = this.getChannel(
|
|
446
|
-
this.eventChannels[
|
|
471
|
+
async setupPrivatePublishingChannel(participant) {
|
|
472
|
+
const privateChannel = this.getChannel(participant.privateChannelName, {})
|
|
473
|
+
this.eventChannels[participant.eventId].privates[participant.userId] = privateChannel
|
|
447
474
|
await this.attachChannel(privateChannel)
|
|
448
475
|
|
|
449
|
-
logger.debug(`setupPrivatePublishingChannel(${
|
|
476
|
+
logger.debug(`setupPrivatePublishingChannel(${participant.privateChannelName}) state ${privateChannel.state}`)
|
|
450
477
|
}
|
|
451
478
|
|
|
452
479
|
async attachChannel(channel) {
|
|
@@ -457,6 +484,18 @@ class AnearMessaging {
|
|
|
457
484
|
}
|
|
458
485
|
}
|
|
459
486
|
|
|
487
|
+
async runExclusive(name, callback) {
|
|
488
|
+
logger.debug(`waiting for ${name} mutex`)
|
|
489
|
+
|
|
490
|
+
await this.mutex.runExclusive(
|
|
491
|
+
async () => {
|
|
492
|
+
logger.debug(`mutex ${name} locked!`)
|
|
493
|
+
await callback()
|
|
494
|
+
}
|
|
495
|
+
)
|
|
496
|
+
logger.debug(`mutex ${name} released!`)
|
|
497
|
+
}
|
|
498
|
+
|
|
460
499
|
subscribeEventMessages(channel, messageType, callback) {
|
|
461
500
|
channel.subscribe(messageType, callback)
|
|
462
501
|
logger.debug(`subscribed to ${messageType} messages on ${channel.name}`)
|
|
@@ -505,7 +544,7 @@ class AnearMessaging {
|
|
|
505
544
|
if (timeoutMilliseconds === 0) return
|
|
506
545
|
|
|
507
546
|
participants.forEach(
|
|
508
|
-
|
|
547
|
+
participant => this.setParticipantTimer(eventId, participant, timeoutMilliseconds)
|
|
509
548
|
)
|
|
510
549
|
}
|
|
511
550
|
|
|
@@ -521,18 +560,18 @@ class AnearMessaging {
|
|
|
521
560
|
|
|
522
561
|
async publishEventPrivateMessage(
|
|
523
562
|
eventId,
|
|
524
|
-
|
|
563
|
+
participant,
|
|
525
564
|
messageType,
|
|
526
565
|
css,
|
|
527
566
|
message,
|
|
528
567
|
timeoutMilliseconds=0,
|
|
529
568
|
timeoutCallback=null) {
|
|
530
569
|
|
|
531
|
-
const userId =
|
|
570
|
+
const userId = participant.userId
|
|
532
571
|
const channel = this.eventChannels[eventId].privates[userId]
|
|
533
572
|
if (!channel) throw new Error(`private channel not found. invalid user id ${userId}`)
|
|
534
573
|
|
|
535
|
-
const setTimerFunction = () => this.setParticipantTimer(eventId,
|
|
574
|
+
const setTimerFunction = () => this.setParticipantTimer(eventId, participant, timeoutMilliseconds)
|
|
536
575
|
|
|
537
576
|
await this.publishChannelMessageWithTimeout(
|
|
538
577
|
channel,
|