anear-js-api 0.2.2 → 0.3.0
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 +114 -99
- 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,6 +67,7 @@ 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
72
|
await this.reloadAnyEventsInProgress(AppId)
|
|
67
73
|
await this.setupCreateEventChannel()
|
|
@@ -69,6 +75,13 @@ class AnearMessaging {
|
|
|
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,33 +160,38 @@ 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
|
|
|
185
184
|
if (!eventExists) {
|
|
186
|
-
await
|
|
187
|
-
|
|
185
|
+
await this.runExclusive("createEventCallback", async () => {
|
|
186
|
+
await anearEvent.createdEventCallback()
|
|
187
|
+
await anearEvent.persist()
|
|
188
|
+
})
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
logger.info(`New ${anearEvent.constructor.name} Event: `, anearEvent.toJSON())
|
|
191
192
|
|
|
193
|
+
anearEvent.startStateMachine()
|
|
194
|
+
|
|
192
195
|
await this.initEventRealtimeMessaging(anearEvent)
|
|
193
196
|
}
|
|
194
197
|
|
|
@@ -202,7 +205,7 @@ class AnearMessaging {
|
|
|
202
205
|
for (const eventData of events) {
|
|
203
206
|
const eventJson = await this.api.getEvent(eventData.id)
|
|
204
207
|
const anearEvent = new this.AnearEventClass(eventJson, this)
|
|
205
|
-
await this.
|
|
208
|
+
await this.loadOrPersistEventAndInitialize(anearEvent)
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
} catch (err) {
|
|
@@ -238,14 +241,14 @@ class AnearMessaging {
|
|
|
238
241
|
|
|
239
242
|
this.subscribePresenceEvent(
|
|
240
243
|
spectatorsChannel,
|
|
241
|
-
|
|
242
|
-
async message => await this.spectatorEnterMessagingCallback(anearEvent
|
|
244
|
+
PRESENCE_ENTER,
|
|
245
|
+
async message => await this.spectatorEnterMessagingCallback(anearEvent, message)
|
|
243
246
|
)
|
|
244
247
|
|
|
245
248
|
this.subscribePresenceEvent(
|
|
246
249
|
spectatorsChannel,
|
|
247
|
-
|
|
248
|
-
async message => await this.spectatorLeaveMessagingCallback(anearEvent
|
|
250
|
+
PRESENCE_LEAVE,
|
|
251
|
+
async message => await this.spectatorLeaveMessagingCallback(anearEvent, message)
|
|
249
252
|
)
|
|
250
253
|
}
|
|
251
254
|
|
|
@@ -258,23 +261,23 @@ class AnearMessaging {
|
|
|
258
261
|
|
|
259
262
|
await this.subscribePresenceEventWithHistory(
|
|
260
263
|
actionsChannel,
|
|
261
|
-
|
|
262
|
-
async message => await this.participantEnterMessagingCallback(anearEvent
|
|
264
|
+
PRESENCE_ENTER,
|
|
265
|
+
async message => await this.participantEnterMessagingCallback(anearEvent, message)
|
|
263
266
|
)
|
|
264
267
|
this.subscribeEventMessages(
|
|
265
268
|
actionsChannel,
|
|
266
269
|
ActionMessageType,
|
|
267
|
-
async message => await this.participantActionMessagingCallback(anearEvent
|
|
270
|
+
async message => await this.participantActionMessagingCallback(anearEvent, message)
|
|
268
271
|
)
|
|
269
272
|
this.subscribePresenceEvent(
|
|
270
273
|
actionsChannel,
|
|
271
|
-
|
|
272
|
-
async message => await this.participantLeaveMessagingCallback(anearEvent
|
|
274
|
+
PRESENCE_LEAVE,
|
|
275
|
+
async message => await this.participantLeaveMessagingCallback(anearEvent, message)
|
|
273
276
|
)
|
|
274
277
|
this.subscribeEventMessages(
|
|
275
278
|
actionsChannel,
|
|
276
279
|
ExitEventMessageType,
|
|
277
|
-
async message => await this.participantExplicitExitMessagingCallback(anearEvent
|
|
280
|
+
async message => await this.participantExplicitExitMessagingCallback(anearEvent, message)
|
|
278
281
|
)
|
|
279
282
|
}
|
|
280
283
|
|
|
@@ -298,20 +301,22 @@ class AnearMessaging {
|
|
|
298
301
|
return participantsChannel
|
|
299
302
|
}
|
|
300
303
|
|
|
301
|
-
async participantExplicitExitMessagingCallback(
|
|
304
|
+
async participantExplicitExitMessagingCallback(anearEvent, message) {
|
|
302
305
|
//
|
|
303
306
|
// client user deliberately cancels out of event
|
|
304
307
|
//
|
|
305
308
|
const participantId = message.data.participantId
|
|
306
309
|
|
|
307
|
-
logger.debug(`ExitEventMessage received from ${participantId} for event ${
|
|
310
|
+
logger.debug(`ExitEventMessage received from ${participantId} for event ${anearEvent.id}`)
|
|
308
311
|
|
|
309
|
-
await this.closeParticipant(
|
|
310
|
-
|
|
312
|
+
await this.closeParticipant(
|
|
313
|
+
anearEvent,
|
|
314
|
+
participantId,
|
|
315
|
+
(anearEvent, participant) => anearEvent.participantClose(participant)
|
|
311
316
|
)
|
|
312
317
|
}
|
|
313
318
|
|
|
314
|
-
async participantEnterMessagingCallback(
|
|
319
|
+
async participantEnterMessagingCallback(anearEvent, presenceMessage) {
|
|
315
320
|
// presenceMessage.clientId is the participant's user_id
|
|
316
321
|
// presenceMessage.data = {
|
|
317
322
|
// id: participantId,
|
|
@@ -321,7 +326,7 @@ class AnearMessaging {
|
|
|
321
326
|
const participantId = presenceMessage.data.id
|
|
322
327
|
const geoLocation = presenceMessage.data.geoLocation
|
|
323
328
|
|
|
324
|
-
logger.debug(`**** ENTER PARTICIPANT **** event: ${
|
|
329
|
+
logger.debug(`**** ENTER PARTICIPANT **** event: ${anearEvent.id}, participant: ${participantId}`)
|
|
325
330
|
|
|
326
331
|
//
|
|
327
332
|
// get the participant data from the API (this will also validate the participant).
|
|
@@ -331,79 +336,70 @@ class AnearMessaging {
|
|
|
331
336
|
try {
|
|
332
337
|
logger.debug(`API fetch participant info for ${participantId}`)
|
|
333
338
|
|
|
334
|
-
const
|
|
335
|
-
const
|
|
339
|
+
const participantJson = await this.api.getEventParticipantJson(participantId)
|
|
340
|
+
const participant = new this.AnearParticipantClass(participantJson)
|
|
336
341
|
|
|
337
|
-
|
|
342
|
+
participant.geoLocation = geoLocation
|
|
338
343
|
|
|
339
|
-
await this.setupPrivatePublishingChannel(
|
|
344
|
+
await this.setupPrivatePublishingChannel(participant)
|
|
340
345
|
|
|
341
346
|
const persistedAnearParticipant = await this.AnearParticipantClass.getFromStorage(participantId)
|
|
342
347
|
|
|
343
|
-
const eventLockCallback = async (anearEvent) => {
|
|
344
|
-
await anearEvent.participantEnter(anearParticipant)
|
|
345
|
-
await anearEvent.update()
|
|
346
|
-
}
|
|
347
|
-
|
|
348
348
|
if (persistedAnearParticipant) {
|
|
349
|
-
|
|
350
|
-
await anearParticipant.update()
|
|
349
|
+
participant.context = persistedAnearParticipant.context
|
|
351
350
|
}
|
|
352
351
|
|
|
353
|
-
await this.
|
|
354
|
-
|
|
352
|
+
await this.runExclusive("participantEnterCallback", async () => {
|
|
353
|
+
await anearEvent.participantEnter(participant)
|
|
354
|
+
await anearEvent.update()
|
|
355
|
+
})
|
|
355
356
|
} catch(error) {
|
|
356
357
|
// participant not found or is not currently marked active at the API service
|
|
357
358
|
// don't allow participation. FIX: we need to publish to the private channel
|
|
358
359
|
// with an error message type.
|
|
359
|
-
logger.error(`participantEnterMessagingCallback(${
|
|
360
|
+
logger.error(`participantEnterMessagingCallback(${anearEvent.id}, ${participantId}) error: `, error)
|
|
360
361
|
}
|
|
361
362
|
}
|
|
362
363
|
|
|
363
|
-
async spectatorEnterMessagingCallback(
|
|
364
|
+
async spectatorEnterMessagingCallback(anearEvent, message) {
|
|
364
365
|
const userId = message.clientId
|
|
365
|
-
const anearEvent = await this.getAnearEventFromStorage(eventId)
|
|
366
366
|
|
|
367
|
-
logger.debug(`**** ENTER SPECTATOR **** event: ${
|
|
367
|
+
logger.debug(`**** ENTER SPECTATOR **** event: ${anearEvent.id}, user: ${userId}`)
|
|
368
368
|
|
|
369
369
|
await anearEvent.refreshSpectator()
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
async spectatorLeaveMessagingCallback(
|
|
372
|
+
async spectatorLeaveMessagingCallback(anearEvent, message) {
|
|
373
373
|
const userId = message.clientId
|
|
374
|
-
logger.debug(`**** LEAVE SPECTATOR **** event: ${
|
|
374
|
+
logger.debug(`**** LEAVE SPECTATOR **** event: ${anearEvent.id}, user: ${userId}`)
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
async participantLeaveMessagingCallback(
|
|
377
|
+
async participantLeaveMessagingCallback(anearEvent, message) {
|
|
378
378
|
// this can be just a temporary leave (refresh browser for example), so we don't do anything
|
|
379
379
|
// for now
|
|
380
380
|
const userId = message.clientId
|
|
381
381
|
logger.debug(`**** LEAVE PARTICIPANT **** participantLeaveMessagingCallback(user: ${userId})`)
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
async closeParticipant(
|
|
384
|
+
async closeParticipant(anearEvent, participantId, callback) {
|
|
385
385
|
logger.debug(`closeParticipant(${participantId})`)
|
|
386
386
|
|
|
387
387
|
this.clearParticipantTimer(participantId)
|
|
388
388
|
|
|
389
|
-
await this.
|
|
390
|
-
eventId,
|
|
391
|
-
async (anearEvent) => {
|
|
392
|
-
const anearParticipant = await this.getAnearParticipantFromStorage(participantId)
|
|
393
|
-
|
|
389
|
+
const participant = await this.getAnearParticipantFromStorage(participantId)
|
|
394
390
|
|
|
395
|
-
|
|
396
|
-
|
|
391
|
+
if (participant) {
|
|
392
|
+
await this.detachParticipantPrivateChannel(anearEvent.id, participant)
|
|
397
393
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
|
|
394
|
+
await this.runExclusive("closeParticipant", async () => {
|
|
395
|
+
await callback(anearEvent, participant)
|
|
396
|
+
await anearEvent.update()
|
|
397
|
+
})
|
|
398
|
+
}
|
|
403
399
|
}
|
|
404
400
|
|
|
405
|
-
async detachParticipantPrivateChannel(eventId,
|
|
406
|
-
const userId =
|
|
401
|
+
async detachParticipantPrivateChannel(eventId, participant) {
|
|
402
|
+
const userId = participant.userId
|
|
407
403
|
const channel = this.eventChannels[eventId].privates[userId]
|
|
408
404
|
|
|
409
405
|
if (channel) {
|
|
@@ -411,26 +407,33 @@ class AnearMessaging {
|
|
|
411
407
|
delete this.eventChannels[eventId].privates[userId]
|
|
412
408
|
}
|
|
413
409
|
}
|
|
414
|
-
|
|
415
|
-
|
|
410
|
+
async participantActionMessagingCallback(anearEvent, message) {
|
|
411
|
+
// e.g. message.data
|
|
412
|
+
// {
|
|
413
|
+
// participantId: "93387343489",
|
|
414
|
+
// payload: "{"reviewResponse":{"questionId": "ab88373ccf", "decision":"approved"}}"
|
|
415
|
+
// }
|
|
416
|
+
//
|
|
417
|
+
// actionEventName => "reviewResponse"
|
|
418
|
+
// actionPayload => {questionId: "ab88373ccf", decision:"approved"}
|
|
419
|
+
//
|
|
416
420
|
const payload = message.data.payload
|
|
417
421
|
const participantId = message.data.participantId
|
|
418
422
|
|
|
419
|
-
logger.debug(`participantActionMessagingCallback(${
|
|
423
|
+
logger.debug(`participantActionMessagingCallback(${anearEvent.id}, ${participantId})`)
|
|
420
424
|
|
|
421
425
|
this.clearParticipantTimer(participantId)
|
|
422
426
|
|
|
423
427
|
const actionJSON = JSON.parse(payload)
|
|
424
428
|
const [actionEventName, actionPayload] = Object.entries(actionJSON)[0]
|
|
425
429
|
|
|
426
|
-
await this.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
)
|
|
430
|
+
const participant = await this.getAnearParticipantFromStorage(participantId)
|
|
431
|
+
|
|
432
|
+
await this.runExclusive("participantActionCallback", async () => {
|
|
433
|
+
await anearEvent.participantAction(participant, actionEventName, actionPayload)
|
|
434
|
+
await anearEvent.update()
|
|
435
|
+
await participant.update()
|
|
436
|
+
})
|
|
434
437
|
}
|
|
435
438
|
|
|
436
439
|
async eventBroadcastMessagingCallback(eventId, message) {
|
|
@@ -441,12 +444,12 @@ class AnearMessaging {
|
|
|
441
444
|
await anearEvent.update()
|
|
442
445
|
}
|
|
443
446
|
|
|
444
|
-
async setupPrivatePublishingChannel(
|
|
445
|
-
const privateChannel = this.getChannel(
|
|
446
|
-
this.eventChannels[
|
|
447
|
+
async setupPrivatePublishingChannel(participant) {
|
|
448
|
+
const privateChannel = this.getChannel(participant.privateChannelName, {})
|
|
449
|
+
this.eventChannels[participant.eventId].privates[participant.userId] = privateChannel
|
|
447
450
|
await this.attachChannel(privateChannel)
|
|
448
451
|
|
|
449
|
-
logger.debug(`setupPrivatePublishingChannel(${
|
|
452
|
+
logger.debug(`setupPrivatePublishingChannel(${participant.privateChannelName}) state ${privateChannel.state}`)
|
|
450
453
|
}
|
|
451
454
|
|
|
452
455
|
async attachChannel(channel) {
|
|
@@ -457,6 +460,18 @@ class AnearMessaging {
|
|
|
457
460
|
}
|
|
458
461
|
}
|
|
459
462
|
|
|
463
|
+
async runExclusive(name, callback) {
|
|
464
|
+
logger.debug(`waiting for ${name} mutex`)
|
|
465
|
+
|
|
466
|
+
await this.mutex.runExclusive(
|
|
467
|
+
async () => {
|
|
468
|
+
logger.debug(`mutex ${name} locked!`)
|
|
469
|
+
await callback()
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
logger.debug(`mutex ${name} released!`)
|
|
473
|
+
}
|
|
474
|
+
|
|
460
475
|
subscribeEventMessages(channel, messageType, callback) {
|
|
461
476
|
channel.subscribe(messageType, callback)
|
|
462
477
|
logger.debug(`subscribed to ${messageType} messages on ${channel.name}`)
|
|
@@ -505,7 +520,7 @@ class AnearMessaging {
|
|
|
505
520
|
if (timeoutMilliseconds === 0) return
|
|
506
521
|
|
|
507
522
|
participants.forEach(
|
|
508
|
-
|
|
523
|
+
participant => this.setParticipantTimer(eventId, participant, timeoutMilliseconds)
|
|
509
524
|
)
|
|
510
525
|
}
|
|
511
526
|
|
|
@@ -521,18 +536,18 @@ class AnearMessaging {
|
|
|
521
536
|
|
|
522
537
|
async publishEventPrivateMessage(
|
|
523
538
|
eventId,
|
|
524
|
-
|
|
539
|
+
participant,
|
|
525
540
|
messageType,
|
|
526
541
|
css,
|
|
527
542
|
message,
|
|
528
543
|
timeoutMilliseconds=0,
|
|
529
544
|
timeoutCallback=null) {
|
|
530
545
|
|
|
531
|
-
const userId =
|
|
546
|
+
const userId = participant.userId
|
|
532
547
|
const channel = this.eventChannels[eventId].privates[userId]
|
|
533
548
|
if (!channel) throw new Error(`private channel not found. invalid user id ${userId}`)
|
|
534
549
|
|
|
535
|
-
const setTimerFunction = () => this.setParticipantTimer(eventId,
|
|
550
|
+
const setTimerFunction = () => this.setParticipantTimer(eventId, participant, timeoutMilliseconds)
|
|
536
551
|
|
|
537
552
|
await this.publishChannelMessageWithTimeout(
|
|
538
553
|
channel,
|