anear-js-api 0.3.30 → 0.3.32

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.
@@ -155,11 +155,11 @@ class AnearMessaging {
155
155
  }
156
156
 
157
157
  async getAnearEventFromStorage(eventId) {
158
- return await this.AnearEventClass.getFromStorage(eventId, this)
158
+ return await this.AnearEventClass.getFromStorage(eventId, this.AnearParticipantClass, this)
159
159
  }
160
160
 
161
- async getAnearParticipantFromStorage(participantId) {
162
- return await this.AnearParticipantClass.getFromStorage(participantId)
161
+ async getAnearParticipantFromStorage(participantId, anearEvent) {
162
+ return await this.AnearParticipantClass.getFromStorage(participantId, anearEvent)
163
163
  }
164
164
 
165
165
  async initEventRealtimeMessaging(anearEvent) {
@@ -194,7 +194,7 @@ class AnearMessaging {
194
194
 
195
195
  try {
196
196
  const eventJson = JSON.parse(message.data)
197
- const anearEvent = new this.AnearEventClass(eventJson, this)
197
+ const anearEvent = new this.AnearEventClass(eventJson, this.AnearParticipantClass, this)
198
198
 
199
199
  //
200
200
  // if we are getting this event create message from history after a quick restart,
@@ -246,12 +246,13 @@ class AnearMessaging {
246
246
 
247
247
  for (const eventData of events) {
248
248
  const eventJson = await this.api.getEvent(eventData.id)
249
- const anearEvent = new this.AnearEventClass(eventJson, this)
250
- // THIS does NOT work yet. This is logic that restarte events in progress
251
- // if the nodeJS process crahsed during play
249
+ const anearEvent = new this.AnearEventClass(eventJson, this.AnearParticipantClass, this)
250
+ // This needs work!!
251
+ // loadedEvent = await this.getAnearEventFromStorage(anearEvent.id)
252
+ // await this.refreshActiveParticipants(loadedEvent)
253
+ // await this.initEventRealtimeMessaging(loadedEvent)
254
+ // loadedEvent.startStateMachine()
252
255
  //
253
- // const loadedEvent = await this.loadOrPersistEventAndInitialize(anearEvent)
254
- // await this.refreshActiveParticipants(loadedEvent) DOES NOT WORK YET
255
256
  }
256
257
  }
257
258
  } catch (err) {
@@ -260,16 +261,8 @@ class AnearMessaging {
260
261
  }
261
262
 
262
263
  async refreshActiveParticipants(anearEvent) {
263
- const allParticipants = anearEvent.participants.active
264
-
265
- return Promise.all(
266
- allParticipants.map(
267
- participant => this.processParticipantEnter(
268
- anearEvent,
269
- participant.id,
270
- participant.geoLocation
271
- )
272
- )
264
+ await this.participants.reloadFromStorage(
265
+ p => this.processParticipantEnter(anearEvent, p.id, p.geoLocation)
273
266
  )
274
267
  }
275
268
 
@@ -416,11 +409,11 @@ class AnearMessaging {
416
409
  //
417
410
  try {
418
411
  const participantJson = await this.api.getEventParticipantJson(participantId)
419
- const participant = new this.AnearParticipantClass(participantJson)
412
+ const participant = new this.AnearParticipantClass(participantJson, anearEvent)
420
413
 
421
414
  participant.geoLocation = geoLocation
422
415
 
423
- const persistedAnearParticipant = await this.AnearParticipantClass.getFromStorage(participantId)
416
+ const persistedAnearParticipant = await this.getAnearParticipantFromStorage(participantId, anearEvent)
424
417
 
425
418
  if (persistedAnearParticipant) {
426
419
  participant.context = persistedAnearParticipant.context
@@ -471,7 +464,7 @@ class AnearMessaging {
471
464
 
472
465
  this.destroyParticipantTimer(participantId)
473
466
 
474
- const participant = await this.getAnearParticipantFromStorage(participantId)
467
+ const participant = await this.getAnearParticipantFromStorage(participantId, anearEvent)
475
468
 
476
469
  if (participant) {
477
470
  await this.detachParticipantPrivateChannel(anearEvent.id, participant)
@@ -515,7 +508,7 @@ class AnearMessaging {
515
508
  const actionJSON = JSON.parse(payload)
516
509
  const [actionEventName, actionPayload] = Object.entries(actionJSON)[0]
517
510
 
518
- const participant = await this.getAnearParticipantFromStorage(participantId)
511
+ const participant = await this.getAnearParticipantFromStorage(participantId, anearEvent)
519
512
 
520
513
  await this.runExclusive("participantActionCallback", async () => {
521
514
  await anearEvent.participantAction(participant, actionEventName, actionPayload)
@@ -11,21 +11,21 @@ const PrivateDisplayMessageType = 'private_display'
11
11
 
12
12
  class AnearEvent extends JsonApiResource {
13
13
 
14
- constructor(json, messaging) {
14
+ constructor(json, anearParticipantClass, messaging) {
15
15
  super(json)
16
-
17
- this.messaging = messaging
18
16
  this.zone = this.findIncluded(this.relationships.zone)
19
17
  this.app = this.findIncluded(this.zone.relationships.app)
20
- this.participants = new Participants(json.participants)
18
+ this.anearParticipantClass = anearParticipantClass
19
+ this.messaging = messaging
21
20
  this.anearStateMachine = this.initStateMachine(json.previousState)
21
+ this.participants = new Participants(this, json.participants)
22
22
  }
23
23
 
24
24
  toJSON() {
25
25
  return {
26
26
  ...super.toJSON(),
27
- context: this.stateMachineContext,
28
27
  participants: this.participants.toJSON(),
28
+ context: this.stateMachineContext,
29
29
  previousState: this.anearStateMachine.currentState
30
30
  }
31
31
  }
@@ -207,13 +207,13 @@ class AnearEvent extends JsonApiResource {
207
207
  if (this.participants.exists(participant)) {
208
208
  logger.info(`AnearEvent: participant ${participant.id} exists. Refreshing...`)
209
209
 
210
- this.participants.add(this, participant) // update the participants entry
210
+ this.participants.add(participant) // update the participants entry
211
211
 
212
212
  this.anearStateMachine.sendRefreshEvent({ participant })
213
213
 
214
214
  await participant.update()
215
215
  } else {
216
- this.participants.add(this, participant) // add the participants entry
216
+ this.participants.add(participant) // add the participants entry
217
217
 
218
218
  this.anearStateMachine.sendJoinEvent({ participant })
219
219
 
@@ -301,7 +301,7 @@ class AnearEvent extends JsonApiResource {
301
301
  return Promise.all(
302
302
  this.participants.all.map(
303
303
  async p => {
304
- const participant = await this.getAnearParticipantFromStorage(p.id)
304
+ const participant = await this.messaging.getAnearParticipantFromStorage(p.id)
305
305
  await this.messaging.closeParticipant(
306
306
  this,
307
307
  participant.id,
@@ -314,6 +314,24 @@ class AnearEvent extends JsonApiResource {
314
314
  )
315
315
  }
316
316
 
317
+ async purgeParticipants() {
318
+ // remove participants from Participants class and from Storage
319
+ const all = this.participants.all
320
+ if (this.participants.host) all.push(this.participants.host)
321
+
322
+ await Promise.all(
323
+ all.map(p => this.participantPurge(p))
324
+ )
325
+ }
326
+
327
+ async reloadParticipantsFromStorage() {
328
+ // rehydrate the anearEvent participants and host from storage
329
+ const participants = await Promise.all(
330
+ this.participants.ids.map(pid => this.anearParticipantClass.getFromStorage(pid, this))
331
+ )
332
+ this.participants.load(participants)
333
+ }
334
+
317
335
  eventChannelName () {
318
336
  return this.getChannelName('event')
319
337
  }
@@ -3,13 +3,38 @@ const JsonApiResource = require('./JsonApiResource')
3
3
  const HostUserType = "host"
4
4
 
5
5
  class AnearParticipant extends JsonApiResource {
6
+ constructor(json, anearEvent) {
7
+ super(json)
8
+ this.anearEvent = anearEvent
9
+ this._state = json.state
10
+ this._timestamp = json.timestamp
11
+ }
12
+
6
13
  toJSON() {
7
14
  return {
8
15
  ...super.toJSON(),
9
16
  geoLocation: this._geoLocation || null,
17
+ state: this.state,
18
+ timestamp: this.timestamp
10
19
  }
11
20
  }
12
21
 
22
+ get state() {
23
+ return this._state
24
+ }
25
+
26
+ set state(s) {
27
+ this._state = s
28
+ }
29
+
30
+ get timestamp() {
31
+ return this._timestamp
32
+ }
33
+
34
+ set timestamp(t) {
35
+ this._timestamp = t
36
+ }
37
+
13
38
  set geoLocation(loc) {
14
39
  this._geoLocation = loc
15
40
  }
@@ -18,10 +43,6 @@ class AnearParticipant extends JsonApiResource {
18
43
  return this._geoLocation
19
44
  }
20
45
 
21
- get identity() {
22
- return (({ id, userId, name, avatarUrl, geoLocation}) => ({ id, userId, name, avatarUrl, geoLocation}))(this)
23
- }
24
-
25
46
  get userId() {
26
47
  return this.relationships.user.data.id
27
48
  }
@@ -6,41 +6,44 @@ const IdleState = "idle"
6
6
  const MINUTES = (60 * 1000)
7
7
  const HOURS = (60 * MINUTES)
8
8
  const DefaultIdleMsecs = (30 * MINUTES)
9
- const DefaultPurgeMsecs = (2 * HOURS)
10
-
11
- const DefaultSettings = {
12
- participants: {},
13
- host: {},
14
- idleMsecs: DefaultIdleMsecs,
15
- purgeMsecs: DefaultPurgeMsecs
16
- }
9
+ const DefaultPurgeMsecs = (2 * HOURS) // after Idle
17
10
 
18
11
  class Participants {
19
12
 
20
- constructor(json) {
21
- const init = json || JSON.parse(JSON.stringify(DefaultSettings))
22
- this._participants = init.participants
23
- this._host = init.host
24
- this.idleMsecs = init.idleMsecs // how long Active participants
25
- this.purgeMsecs = init.purgeMsecs
13
+ constructor(anearEvent, {idleMsecs = DefaultIdleMsecs, purgeMsecs = DefaultPurgeMsecs, ids = []} = {}) {
14
+ this.anearEvent = anearEvent
15
+ this.idleMsecs = idleMsecs
16
+ this.purgeMsecs = purgeMsecs
17
+ this._participants = {}
18
+ for (const id of ids) {
19
+ // app restart logic ...
20
+ // seeds from ids with empty objects awaiting full
21
+ // anearParticipant rehydration from redis
22
+ this._participants[id] = {}
23
+ }
24
+ this._host = null
26
25
  }
27
26
 
28
27
  toJSON() {
29
28
  return {
30
- participants: this._participants,
31
- host: this._host,
29
+ // only output the active participant ids.
30
+ ids: this.all.map(p => p.id),
32
31
  idleMsecs: this.idleMsecs,
33
32
  purgeMsecs: this.purgeMsecs
34
33
  }
35
34
  }
36
35
 
36
+ get ids() {
37
+ return Object.keys(this._participants)
38
+ }
39
+
37
40
  indexedById() {
38
41
  // returns an object that has AnearParticipant.id as key
39
42
  return this._participants
40
43
  }
41
44
 
42
- getById(anearParticipantId) {
43
- return this._participants[anearParticipantId]
45
+ getById(participantId) {
46
+ return this._participants[participantId]
44
47
  }
45
48
 
46
49
  exists({id}) {
@@ -55,29 +58,33 @@ class Participants {
55
58
  return this._host
56
59
  }
57
60
 
61
+ set host(h) {
62
+ this._host = h
63
+ }
64
+
58
65
  get all() {
59
66
  return Object.values(this._participants).
60
67
  sort((ca, cb) => ca.timestamp - cb.timestamp)
61
68
  }
62
69
 
63
- active() {
70
+ get active() {
64
71
  return Object.values(this._participants).filter(c => c.state === ActiveState)
65
72
  }
66
73
 
67
- idle() {
74
+ get idle() {
68
75
  return Object.values(this._participants).filter(c => c.state === IdleState)
69
76
  }
70
77
 
71
78
  get count() {
72
- return Object.keys(this._participants).length
79
+ return this.ids.length
73
80
  }
74
81
 
75
- numActive() {
76
- return this.active().length
82
+ get numActive() {
83
+ return this.active.length
77
84
  }
78
85
 
79
- numIdle() {
80
- return this.idle().length
86
+ get numIdle() {
87
+ return this.idle.length
81
88
  }
82
89
 
83
90
  isIdle(c, currentTimestamp) {
@@ -108,8 +115,7 @@ class Participants {
108
115
  }
109
116
  }
110
117
 
111
- const keys = Object.keys(this._participants)
112
- keys.forEach(
118
+ this.ids.forEach(
113
119
  k => {
114
120
  const c = this._participants[k]
115
121
  sweeper(c)
@@ -117,34 +123,33 @@ class Participants {
117
123
  )
118
124
  }
119
125
 
120
- add(anearEvent, anearParticipant) {
121
- const rec = this.participantRec(anearParticipant)
122
-
123
- if (anearParticipant.isHost() && anearEvent.hosted) {
126
+ add(anearParticipant, withTimestamp = this.currentTimestamp) {
127
+ if (anearParticipant.isHost() && this.anearEvent.hosted) {
124
128
  // the host is not an eligible participant and isn't active nor idle
125
- this._host = rec
129
+ this.host = anearParticipant
126
130
  } else {
127
- this.markActive(anearParticipant)
131
+ this._participants[anearParticipant.id] = anearParticipant
132
+ this.markActive(anearParticipant, withTimestamp)
128
133
  }
129
- return rec
134
+ return anearParticipant
130
135
  }
131
136
 
132
- markActive(anearParticipant) {
133
- // anearParticipant has shown activity in the event (e.g. Action)
134
- const participant = this.get(anearParticipant)
135
- if (participant) {
136
- participant.timestamp = this.currentTimestamp
137
- participant.state = ActiveState
138
- } else {
139
- this._participants[anearParticipant.id] = this.participantRec(anearParticipant)
140
- }
137
+ markActive(anearParticipant, withTimestamp = this.currentTimestamp) {
138
+ anearParticipant.timestamp = withTimestamp
139
+ anearParticipant.state = ActiveState
141
140
  }
142
141
 
143
- purge({id}) {
144
- if (id === this.host.id) {
145
- this._host = JSON.parse(JSON.stringify(DefaultSettings)).host
142
+ purge(participant) {
143
+ if (!participant) return
144
+
145
+ const {id} = participant
146
+
147
+ if (this.host && (id === this.host.id)) {
148
+ this.host = null
146
149
  } else {
147
- if (this._participants[id]) delete this._participants[id]
150
+ if (this._participants[id]) {
151
+ delete this._participants[id]
152
+ }
148
153
  }
149
154
  }
150
155
 
@@ -152,12 +157,17 @@ class Participants {
152
157
  return new Date().getTime()
153
158
  }
154
159
 
155
- participantRec(anearParticipant, state = ActiveState) {
156
- return {
157
- ...anearParticipant.identity,
158
- state,
159
- timestamp: this.currentTimestamp
160
- }
160
+ load(anearParticipants) {
161
+ // used for tests only
162
+ anearParticipants.forEach(
163
+ p => {
164
+ if (p.isHost() && this.anearEvent.hosted) {
165
+ this.host = p
166
+ } else {
167
+ this._participants[p.id] = p
168
+ }
169
+ }
170
+ )
161
171
  }
162
172
  }
163
173
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anear-js-api",
3
- "version": "0.3.30",
3
+ "version": "0.3.32",
4
4
  "description": "Javascript Developer API for Anear Apps",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -142,14 +142,14 @@ afterAll(async () => await TestEvent.close())
142
142
  afterEach(() => {jest.clearAllMocks()})
143
143
 
144
144
  const newTestEvent = (hosted = false) => {
145
- const t = new TestEvent(chatEvent, MessagingStub)
145
+ const t = new TestEvent(chatEvent, TestPlayer, MessagingStub)
146
146
  t.attributes.hosted = hosted
147
147
  t.startStateMachine()
148
148
  return t
149
149
  }
150
150
 
151
151
  const newTestEventWithDefaultXState = testEvent => {
152
- const t = new TestEventWithDefaultXState(testEvent, MessagingStub)
152
+ const t = new TestEventWithDefaultXState(testEvent, TestPlayer, MessagingStub)
153
153
  t.startStateMachine()
154
154
  return t
155
155
  }
@@ -162,7 +162,7 @@ test('participant enter with Default Xstate Config', async () => {
162
162
  expect(t.relationships.user.data.type).toBe("users")
163
163
  expect(t.anearStateMachine.currentState.value).toBe("eventActive")
164
164
  expect(t.stateMachineContext.playerScores[0]).toBe(83)
165
- const p1 = new TestPlayer(chatParticipant1)
165
+ const p1 = new TestPlayer(chatParticipant1, t)
166
166
 
167
167
  await t.participantEnter(p1)
168
168
  await t.persist()
@@ -171,7 +171,7 @@ test('participant enter with Default Xstate Config', async () => {
171
171
  expect(p1.userType).toBe("participant")
172
172
  expect(mockParticipantEnterHandler).toHaveBeenCalledTimes(1)
173
173
  expect(mockParticipantEnterHandler).toHaveBeenCalledWith(p1)
174
- expect(t.participants.numActive(false)).toBe(1)
174
+ expect(t.participants.numActive).toBe(1)
175
175
 
176
176
  await p1.remove()
177
177
  })
@@ -179,21 +179,21 @@ test('participant enter with Default Xstate Config', async () => {
179
179
  test('participant close with Default Xstate Config', async () => {
180
180
  const t = newTestEventWithDefaultXState(chatEvent)
181
181
 
182
- const p1 = new TestPlayer(chatParticipant1)
182
+ const p1 = new TestPlayer(chatParticipant1, t)
183
183
 
184
184
  await t.participantExit(p1)
185
185
  await t.update()
186
186
 
187
187
  expect(mockParticipantExitHandler).toHaveBeenCalledWith(p1)
188
188
  expect(mockParticipantExitHandler).toHaveBeenCalledTimes(1)
189
- expect(t.participants.numActive(false)).toBe(0)
189
+ expect(t.participants.numActive).toBe(0)
190
190
 
191
191
  await t.remove()
192
192
  })
193
193
 
194
194
  test('participant refresh with Default Xstate Config', async () => {
195
195
  const t = newTestEventWithDefaultXState(chatEvent)
196
- const p1 = new TestPlayer(chatParticipant1)
196
+ const p1 = new TestPlayer(chatParticipant1, t)
197
197
 
198
198
  await t.refreshParticipant(p1)
199
199
  await t.update()
@@ -206,7 +206,7 @@ test('participant refresh with Default Xstate Config', async () => {
206
206
 
207
207
  test('participant action with Default Xstate Config', async () => {
208
208
  const t = newTestEventWithDefaultXState(chatEvent)
209
- const p1 = new TestPlayer(chatParticipant1)
209
+ const p1 = new TestPlayer(chatParticipant1, t)
210
210
  const eventName = "TEST_ACTION"
211
211
  const payload = {x: 1, y: 99}
212
212
 
@@ -230,8 +230,8 @@ test('can be persisted and removed repeatedly in storage', async () => {
230
230
 
231
231
  test('can add participants, not hosted', async () => {
232
232
  let t = newTestEvent(false)
233
- const p1 = new TestPlayer(chatParticipant1)
234
- const p2 = new TestPlayer(chatParticipant2)
233
+ const p1 = new TestPlayer(chatParticipant1, t)
234
+ const p2 = new TestPlayer(chatParticipant2, t)
235
235
  const id = t.id
236
236
 
237
237
  await t.participantEnter(p1)
@@ -240,15 +240,15 @@ test('can add participants, not hosted', async () => {
240
240
  expect(p1.userType).toBe("participant")
241
241
  expect(mockParticipantEnterHandler).toHaveBeenCalledTimes(1)
242
242
  expect(mockParticipantEnterHandler).toHaveBeenCalledWith(p1)
243
- expect(t.participants.numActive(false)).toBe(1)
244
- expect(t.participants.host).toStrictEqual({})
243
+ expect(t.participants.numActive).toBe(1)
244
+ expect(t.participants.host).toBe(null)
245
245
 
246
246
  await t.participantEnter(p2)
247
247
  await t.update()
248
248
 
249
249
  expect(mockParticipantEnterHandler).toHaveBeenCalledTimes(2)
250
250
  expect(mockParticipantEnterHandler).toHaveBeenCalledWith(p2)
251
- expect(t.participants.numActive(false)).toBe(2)
251
+ expect(t.participants.numActive).toBe(2)
252
252
  expect(t.participants.get(p2).name).toBe("bbondfl93")
253
253
  expect(p2.userType).toBe("participant")
254
254
 
@@ -260,7 +260,27 @@ test('can add participants, not hosted', async () => {
260
260
  expect(mockParticipantExitHandler).toHaveBeenCalledWith(p1)
261
261
  expect(mockParticipantExitHandler).toHaveBeenCalledWith(p2)
262
262
  expect(mockParticipantExitHandler).toHaveBeenCalledTimes(2)
263
- expect(t.participants.numActive(false)).toBe(0)
263
+ expect(t.participants.numActive).toBe(0)
264
+ })
265
+
266
+ test('purge all participants', async () => {
267
+ let t = newTestEvent(true)
268
+ const host = new TestPlayer(chatHost, t)
269
+ const p1 = new TestPlayer(chatParticipant1, t)
270
+ const p2 = new TestPlayer(chatParticipant2, t)
271
+ await t.participantEnter(host)
272
+ await t.participantEnter(p1)
273
+ await t.participantEnter(p2)
274
+ await t.update()
275
+
276
+ expect(t.participants.host).toBe(host)
277
+ expect(t.participants.ids).toStrictEqual([p1.id, p2.id])
278
+
279
+ await t.purgeParticipants()
280
+
281
+ expect(t.participants.all).toHaveLength(0)
282
+
283
+ await t.remove()
264
284
  })
265
285
 
266
286
 
@@ -268,10 +288,10 @@ test('can add participant, hosted', async () => {
268
288
  let t = newTestEvent(true)
269
289
 
270
290
  expect(t.hosted).toBe(true)
271
- expect(t.participants.numActive(false)).toBe(0)
291
+ expect(t.participants.numActive).toBe(0)
272
292
 
273
- const host = new TestPlayer(chatHost)
274
- const p2 = new TestPlayer(chatParticipant2)
293
+ const host = new TestPlayer(chatHost, t)
294
+ const p2 = new TestPlayer(chatParticipant2, t)
275
295
  const id = t.id
276
296
 
277
297
  await t.participantEnter(host)
@@ -281,14 +301,14 @@ test('can add participant, hosted', async () => {
281
301
  expect(mockParticipantEnterHandler).toHaveBeenCalledTimes(1)
282
302
  expect(mockParticipantEnterHandler).toHaveBeenCalledWith(host)
283
303
  expect(t.participants.host.name).toBe('foxhole_host')
284
- expect(t.participants.numActive(false)).toBe(0) // event creator when hosted isn't active participant
304
+ expect(t.participants.numActive).toBe(0) // event creator when hosted isn't active participant
285
305
 
286
306
  await t.participantEnter(p2)
287
307
  await t.update()
288
308
 
289
309
  expect(mockParticipantEnterHandler).toHaveBeenCalledTimes(2)
290
310
  expect(mockParticipantEnterHandler).toHaveBeenCalledWith(p2)
291
- expect(t.participants.numActive(false)).toBe(1)
311
+ expect(t.participants.numActive).toBe(1)
292
312
  expect(t.participants.get(p2).name).toBe('bbondfl93')
293
313
 
294
314
  await t.participantExit(host)
@@ -299,43 +319,46 @@ test('can add participant, hosted', async () => {
299
319
  expect(mockParticipantExitHandler).toHaveBeenCalledWith(host)
300
320
  expect(mockParticipantExitHandler).toHaveBeenCalledWith(p2)
301
321
  expect(mockParticipantExitHandler).toHaveBeenCalledTimes(2)
302
- expect(t.participants.numActive(false)).toBe(0)
322
+ expect(t.participants.numActive).toBe(0)
303
323
  })
304
324
 
305
325
  test('can be retrieved back from storage with participants, not hosted', async () => {
306
326
  const testEvent = newTestEvent(false)
307
- const p1 = new TestPlayer(chatParticipant1)
308
- const p2 = new TestPlayer(chatParticipant2)
327
+ const p1 = new TestPlayer(chatParticipant1, testEvent)
328
+ const p2 = new TestPlayer(chatParticipant2, testEvent)
309
329
 
310
330
  await testEvent.participantEnter(p1)
311
331
  await testEvent.participantEnter(p2)
312
332
  await testEvent.persist()
313
333
 
314
- const rehydratedTestEvent = await TestEvent.getFromStorage(testEvent.id, MessagingStub)
315
- const rehydratedPlayer1 = await TestPlayer.getFromStorage(p1.id)
316
- const rehydratedPlayer2 = await TestPlayer.getFromStorage(p2.id)
334
+ const rehydratedTestEvent = await TestEvent.getFromStorage(testEvent.id, TestPlayer, MessagingStub)
335
+ await rehydratedTestEvent.reloadParticipantsFromStorage()
317
336
 
318
337
  rehydratedTestEvent.startStateMachine()
319
338
 
320
- expect(rehydratedTestEvent.participants.numActive(false)).toBe(2)
339
+ expect(rehydratedTestEvent.participants.numActive).toBe(2)
321
340
  expect(rehydratedTestEvent.id).toBe(testEvent.id)
322
341
  expect(rehydratedTestEvent.relationships['user'].data.type).toBe("users")
323
342
  expect(rehydratedTestEvent.relationships['zone'].data.type).toBe("zones")
324
343
  expect(rehydratedTestEvent.participantTimeout).toBe(32000)
325
344
  expect(rehydratedTestEvent.stateMachineContext.score).toBe(90)
326
345
  expect(rehydratedTestEvent.included[0].relationships.app.data.id).toBe("5b9d9838-17de-4a80-8a64-744c222ba722")
327
- expect(rehydratedPlayer1.context.name).toBe('machvee')
328
- expect(rehydratedPlayer2.context.name).toBe('bbondfl93')
329
346
 
330
- await rehydratedTestEvent.participantExit(rehydratedPlayer1)
331
- await rehydratedTestEvent.participantExit(rehydratedPlayer2)
347
+ const rp1 = rehydratedTestEvent.participants.getById(p1.id)
348
+ const rp2 = rehydratedTestEvent.participants.getById(p2.id)
349
+
350
+ expect(rehydratedTestEvent.participants.getById(rp1.id).context.name).toBe('machvee')
351
+ expect(rehydratedTestEvent.participants.getById(rp2.id).context.name).toBe('bbondfl93')
352
+
353
+ await rehydratedTestEvent.participantExit(rp1)
354
+ await rehydratedTestEvent.participantExit(rp2)
332
355
  await rehydratedTestEvent.remove()
333
356
  })
334
357
 
335
358
  test('can update state machine context via Action events', async () => {
336
359
  const t = newTestEvent(false)
337
- const p1 = new TestPlayer(chatParticipant1)
338
- const p2 = new TestPlayer(chatParticipant2)
360
+ const p1 = new TestPlayer(chatParticipant1, t)
361
+ const p2 = new TestPlayer(chatParticipant2, t)
339
362
 
340
363
  await t.participantEnter(p1)
341
364
  await t.participantEnter(p2)
@@ -362,8 +385,8 @@ test('can update state machine context via Action events', async () => {
362
385
 
363
386
  test('can reset All ParticipantTimers', async () => {
364
387
  const t = newTestEvent(false)
365
- const p1 = new TestPlayer(chatParticipant1)
366
- const p2 = new TestPlayer(chatParticipant2)
388
+ const p1 = new TestPlayer(chatParticipant1, t)
389
+ const p2 = new TestPlayer(chatParticipant2, t)
367
390
 
368
391
  const resetMock = jest.spyOn(MessagingStub, "resetAllParticipantTimers");
369
392
 
@@ -2,6 +2,8 @@ const AnearParticipant = require('../lib/models/AnearParticipant')
2
2
 
3
3
  const { AnearParticipantFixture1: player1 } = require('./fixtures')
4
4
 
5
+ const MockEvent = {}
6
+
5
7
  class TestParticipant extends AnearParticipant {
6
8
  initContext() {
7
9
  return {score: 97, responses: ['A', 'C', 'D', 'A']}
@@ -11,26 +13,29 @@ class TestParticipant extends AnearParticipant {
11
13
  afterAll(async () => await TestParticipant.close())
12
14
 
13
15
  test('constructor', () => {
14
- const t = new TestParticipant(player1)
16
+ const t = new TestParticipant(player1, MockEvent)
15
17
  expect(t.id).toBe(player1.data.id)
16
18
  expect(t.relationships.user.data.type).toBe("users")
17
19
  expect(t.context.score).toBe(97)
20
+ expect(t.anearEvent).toBe(MockEvent)
18
21
  })
19
22
 
20
23
  test('participant can be repeatedly rehydrated and updated', async () => {
21
24
  try {
22
- const participant = new TestParticipant(player1)
25
+ const participant = new TestParticipant(player1, MockEvent)
23
26
  await participant.persist()
24
27
 
25
- let p = await TestParticipant.getFromStorage(player1.data.id)
28
+ let p = await TestParticipant.getFromStorage(player1.data.id, MockEvent)
26
29
 
27
30
  expect(p.context.responses).toStrictEqual(['A', 'C', 'D', 'A'])
31
+ expect(p.anearEvent).toBe(MockEvent)
28
32
  p.context.responses.push('B')
29
33
 
30
34
  await p.update()
31
35
 
32
- p = await TestParticipant.getFromStorage(player1.data.id)
36
+ p = await TestParticipant.getFromStorage(player1.data.id, MockEvent)
33
37
  expect(p.context.responses[4]).toBe('B')
38
+ expect(p.anearEvent).toBe(MockEvent)
34
39
 
35
40
  await p.remove()
36
41
 
@@ -5,6 +5,7 @@ const { ParticipantsFixture: participantsJSON,
5
5
  AnearParticipantFixture2: visitor2JSON,
6
6
  AnearHostFixture: hostJSON } = require('./fixtures')
7
7
  const AnearParticipant = require('../lib/models/AnearParticipant')
8
+ const AnearParticipantJSONBuilder = require('./utils/AnearParticipantJSONBuilder')
8
9
 
9
10
  const user1Id = "e053977c-dcb6-40e0-b7b8-e3dbd70ec8fd"
10
11
  const idleId = "f1056e6c-c393-4617-8a06-67ba9d2f4b8a"
@@ -12,61 +13,80 @@ const activeId = user1Id
12
13
  const hours24 = (24 * 60 * 60 * 1000)
13
14
  const GeoLocation = {lat: 25.8348343, lng: -80.38438434}
14
15
 
15
- const MockHostedEvent = {hosted: true}
16
- const MockNonHostedEvent = {hosted: false}
17
-
18
- const newActiveParticipants = (timestamp, json = participantsJSON) => {
19
- const copy = JSON.parse(JSON.stringify(json))
20
- const keys = Object.keys(copy.participants)
21
- keys.forEach(
22
- (k,i) => {
23
- const p = copy.participants[k]
24
- p.timestamp = timestamp - (i*2000)
25
- p.state = 'active'
16
+ const MockHostedEvent = {hosted: true, anearParticipantClass: AnearParticipant}
17
+ const MockNonHostedEvent = {hosted: false, anearParticipantClass: AnearParticipant}
18
+
19
+ const newActiveParticipants = (timestamp, args = {}) => {
20
+ const copyParticipantsFixture = JSON.parse(JSON.stringify(participantsJSON))
21
+ const activeParticipants = Object.values(copyParticipantsFixture).filter(p => !p.isHost)
22
+
23
+ const participants = new Participants(MockHostedEvent, args)
24
+
25
+ activeParticipants.forEach(
26
+ (attrs, i) => {
27
+ const participant = new AnearParticipant(AnearParticipantJSONBuilder(attrs), MockHostedEvent)
28
+ participant.host = attrs.isHost
29
+ participants.add(participant, timestamp - (i*2000))
26
30
  }
27
31
  )
28
- return new Participants(copy)
32
+ return participants
29
33
  }
30
34
 
31
- const newCurrentParticipants = (timestamp, json = participantsJSON) => {
32
- const copy = JSON.parse(JSON.stringify(json))
33
- const keys = Object.keys(copy.participants)
34
- keys.forEach(
35
- (k,i) => {
36
- const p = copy.participants[k]
37
- if (p.state === 'active') {
38
- p.timestamp = timestamp - (i*2000)
35
+ const newCurrentParticipants = (timestamp, anearEvent = MockHostedEvent) => {
36
+ const copyParticipantsFixture = JSON.parse(JSON.stringify(participantsJSON))
37
+ const currentParticipants= Object.values(copyParticipantsFixture).filter(p => !p.isHost)
38
+
39
+ const participants = new Participants(anearEvent)
40
+
41
+ const anearParticipants = currentParticipants.map(
42
+ (attrs, i) => {
43
+ const participant = new AnearParticipant(AnearParticipantJSONBuilder(attrs), anearEvent)
44
+
45
+ let withTimestamp
46
+ if (attrs.state === 'active') {
47
+ withTimestamp = timestamp - (i*2000)
39
48
  } else {
40
- // idle in the last 30 minutes
41
- p.timestamp = timestamp - copy.idleMsecs
49
+ withTimestamp = timestamp - participants.idleMsecs
42
50
  }
51
+
52
+ participant.state = attrs.state
53
+ participant.timestamp = withTimestamp
54
+ participant.host = attrs.isHost
55
+ return participant
43
56
  }
44
57
  )
45
- return new Participants(copy)
58
+
59
+ participants.load(anearParticipants)
60
+
61
+ return participants
46
62
  }
47
63
 
48
64
  const now = new Date().getTime()
49
65
 
50
66
  test('constructor with JSON provided', () => {
51
- const p = new Participants(participantsJSON)
67
+ const ids = ['123', '345', '456']
68
+ const args = {idleMsecs: 23400, purgeMsecs: 678900, ids}
69
+ const p = new Participants(MockHostedEvent, args)
52
70
  expect(p).toBeDefined()
53
- expect(p.idleMsecs).toBe(participantsJSON.idleMsecs)
71
+ expect(p.idleMsecs).toBe(args.idleMsecs)
72
+ expect(p.purgeMsecs).toBe(args.purgeMsecs)
73
+ expect(p.ids).toStrictEqual(ids)
54
74
  })
55
75
 
56
- test('constructor with NO JSON provided', () => {
57
- const p = new Participants()
76
+ test('constructor with NO JSON provided has default idle and purge Msecs', () => {
77
+ const p = new Participants(MockHostedEvent)
58
78
  expect(p).toBeDefined()
59
79
  expect(p.idleMsecs).toBe(1800000)
60
80
  expect(p.purgeMsecs).toBe(7200000)
61
81
  expect(p.all).toHaveLength(0)
62
82
  })
63
83
 
64
- test('constructor with null idle and purge msecs', () => {
65
- const p = newActiveParticipants(now, {...participantsJSON, idleMsecs: null, purgeMsecs: null})
84
+ test('constructor with null idle and purge msecs avoids idle purge', () => {
85
+ const p = newActiveParticipants(now, {idleMsecs: null, purgeMsecs: null})
66
86
  expect(p.idleMsecs).toBe(null)
67
87
  expect(p.purgeMsecs).toBe(null)
68
- expect(p.idle()).toHaveLength(0)
69
- expect(p.active()).toHaveLength(10)
88
+ expect(p.idle).toHaveLength(0)
89
+ expect(p.active).toHaveLength(10)
70
90
 
71
91
  const c = p.getById(idleId)
72
92
  expect(p.isIdle(c, now)).toBeFalsy()
@@ -99,23 +119,17 @@ test('getParticipant fail', () => {
99
119
  expect(p.get({id: "abcd"})).toBeUndefined()
100
120
  })
101
121
 
102
- test('host', () => {
103
- const p = newActiveParticipants(now)
104
- const host = p.host
105
- expect(host.name).toBe("the_host")
106
- })
107
-
108
122
  test('getParticipant success', () => {
109
123
  const p = newActiveParticipants(now)
110
124
  expect(p.get({id: user1Id}).name).toBe("user1")
111
125
  })
112
126
 
113
127
  test('add() participant user', async () => {
114
- const p = newCurrentParticipants(now)
115
- const participant = new AnearParticipant(visitor2JSON)
128
+ const p = newCurrentParticipants(now, MockNonHostedEvent)
129
+ const participant = new AnearParticipant(visitor2JSON, MockNonHostedEvent)
116
130
  participant.geoLocation = GeoLocation
117
131
 
118
- p.add(MockNonHostedEvent, participant)
132
+ p.add(participant)
119
133
  const part = p.get(participant)
120
134
  expect(part.name).toBe("bbondfl93")
121
135
  expect(part.avatarUrl).toBe("https://s3.amazonaws.com/anearassets/barbara_bond.png")
@@ -126,10 +140,10 @@ test('add() participant user', async () => {
126
140
 
127
141
  test('add() host user', async () => {
128
142
  const p = newCurrentParticipants(now)
129
- const host = new AnearParticipant(hostJSON)
143
+ const host = new AnearParticipant(hostJSON, MockNonHostedEvent)
130
144
  host.geoLocation = GeoLocation
131
145
 
132
- p.add(MockHostedEvent, host)
146
+ p.add(host)
133
147
  expect(p.get(host)).toBeUndefined()
134
148
  expect(p.host.name).toBe('foxhole_host')
135
149
  expect(p.host.avatarUrl).toBe("https://s3.amazonaws.com/anearassets/foxhole.png")
@@ -139,20 +153,24 @@ test('add() host user', async () => {
139
153
 
140
154
  test('active', () => {
141
155
  const p = newActiveParticipants(now)
142
- expect(p.active()).toHaveLength(10)
156
+ expect(p.active).toHaveLength(10)
143
157
  })
144
158
 
145
159
  test('idle', () => {
146
160
  const p = newCurrentParticipants(now)
147
- expect(p.idle()).toHaveLength(2)
161
+ expect(p.idle).toHaveLength(2)
148
162
  })
149
163
 
150
164
  test('toJSON', () => {
151
- const p = new Participants(participantsJSON)
165
+ const p = newActiveParticipants(now)
152
166
  const j = p.toJSON()
153
- expect(j).toHaveProperty("participants")
167
+ expect(j).toHaveProperty("ids")
154
168
  expect(j).toHaveProperty("idleMsecs")
155
169
  expect(j).toHaveProperty("purgeMsecs")
170
+ expect(j.ids.sort()).toEqual(p.ids.sort())
171
+ expect(j.ids.length).toBe(10)
172
+ expect(j.idleMsecs).toBe(1800000)
173
+ expect(j.purgeMsecs).toBe(7200000)
156
174
  })
157
175
 
158
176
  test('isIdle', () => {
@@ -185,22 +203,22 @@ test('purge host user-type', () => {
185
203
  const p = newActiveParticipants(now)
186
204
  const c = p.host
187
205
  p.purge(c)
188
- expect(p.host).toStrictEqual({})
206
+ expect(p.host).toStrictEqual(null)
189
207
  })
190
208
 
191
209
  test('updateState will leave state unchanged when timeout criteria not met', () => {
192
210
  const p = newCurrentParticipants(now)
193
211
  p.updateState(now)
194
- expect(p.active()).toHaveLength(8)
195
- expect(p.idle()).toHaveLength(2)
196
- expect(p.numActive()).toBe(8)
197
- expect(p.numIdle()).toBe(2)
212
+ expect(p.active).toHaveLength(8)
213
+ expect(p.idle).toHaveLength(2)
214
+ expect(p.numActive).toBe(8)
215
+ expect(p.numIdle).toBe(2)
198
216
  })
199
217
 
200
218
  test('updateState will mark active to idle when timeout reached', () => {
201
219
  const current = now
202
220
  const p = newCurrentParticipants(current)
203
- expect(p.active()).toHaveLength(8)
221
+ expect(p.active).toHaveLength(8)
204
222
  p.updateState(current + p.idleMsecs + 1000)
205
223
  expect(Object.values(p.all).
206
224
  filter(p => p.state === 'active')).toHaveLength(0)
@@ -209,7 +227,7 @@ test('updateState will mark active to idle when timeout reached', () => {
209
227
  test('updateState will purge idle participants', () => {
210
228
  const current = now
211
229
  const p = newCurrentParticipants(current)
212
- const idlers = p.idle()
230
+ const idlers = p.idle
213
231
  expect(idlers).toHaveLength(2)
214
232
  p.updateState(current + p.purgeMsecs + 1000)
215
233
  idlers.forEach(c => expect(p.getById(c.id)).toBeUndefined())
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
-
3
2
  module.exports = {
4
- host: {
3
+ "aa396e6c-2193-cd17-eea6-0413eefff893": {
5
4
  id: "aa396e6c-2193-cd17-eea6-0413eefff893",
6
5
  userId: "044f4dfc-c4d0-4c58-a2fa-9e1e43913dab",
7
6
  name: "the_host",
@@ -11,108 +10,104 @@ module.exports = {
11
10
  state: "active",
12
11
  isHost: true
13
12
  },
14
- participants: {
15
- "e053977c-dcb6-40e0-b7b8-e3dbd70ec8fd": {
16
- id: "e053977c-dcb6-40e0-b7b8-e3dbd70ec8fd",
17
- userId: "09f3cbf9-0c73-44c6-b6ad-a03b3607e66a",
18
- name: "user1",
19
- avatarUrl: "https://s3.amazonaws.com/path1",
20
- geoLocation: {},
21
- timestamp: 1615649132502,
22
- state: "active",
23
- isHost: false
24
- },
25
- "0f6ab786-fcae-4e81-87ac-a3930f496d71": {
26
- id: "0f6ab786-fcae-4e81-87ac-a3930f496d71",
27
- userId: "819635b2-c70d-474c-a0a6-88a420744cb6",
28
- name: "user2",
29
- avatarUrl: "https://s3.amazonaws.com/path2",
30
- geoLocation: {},
31
- timestamp: 1615649132502,
32
- state: "active",
33
- isHost: false
34
- },
35
- "af9c7ff6-c8c9-4f4a-ad04-bcf86ef57d15": {
36
- id: "af9c7ff6-c8c9-4f4a-ad04-bcf86ef57d15",
37
- userId: "7966b0b6-1c94-4f2d-abf0-857ccf91119e",
38
- name: "user3",
39
- avatarUrl: "https://s3.amazonaws.com/path3",
40
- geoLocation: {},
41
- timestamp: 1615649132502,
42
- state: "active",
43
- isHost: false
44
- },
45
- "777b11b5-2b3b-4420-93d2-eff65127c925": {
46
- id: "777b11b5-2b3b-4420-93d2-eff65127c925",
47
- userId: "0efde18e-39ff-4e26-9aa5-2f7b8d61b2f7",
48
- name: "user4",
49
- avatarUrl: "https://s3.amazonaws.com/path4",
50
- geoLocation: {},
51
- timestamp: 1615649132502,
52
- state: "active",
53
- isHost: false
54
- },
55
- "6405094a-0ac4-4476-9fd8-5d2edc6cf5a1": {
56
- id: "6405094a-0ac4-4476-9fd8-5d2edc6cf5a1",
57
- userId: "cdcbbb6a-0a3b-4222-bcde-4a626555f44d",
58
- name: "user5",
59
- avatarUrl: "https://s3.amazonaws.com/path5",
60
- geoLocation: {},
61
- timestamp: 1615649132502,
62
- state: "active",
63
- isHost: false
64
- },
65
- "dcaabc23-b7dc-47cd-ad11-43022750dc0e": {
66
- id: "dcaabc23-b7dc-47cd-ad11-43022750dc0e",
67
- userId: "ad6a1e91-6460-4eea-b215-4af4de4e021e",
68
- name: "user6",
69
- avatarUrl: "https://s3.amazonaws.com/path6",
70
- geoLocation: {},
71
- timestamp: 1615649132502,
72
- state: "active",
73
- isHost: false
74
- },
75
- "78127e6c-c1b8-490d-ace6-afc798fdf4f6": {
76
- id: "78127e6c-c1b8-490d-ace6-afc798fdf4f6",
77
- userId: "d8584429-4651-4d63-a886-1622941f9b87",
78
- name: "user7",
79
- avatarUrl: "https://s3.amazonaws.com/path7",
80
- geoLocation: {},
81
- timestamp: 1615649132502,
82
- state: "active",
83
- isHost: false
84
- },
85
- "7166a301-aad9-4bc9-b9f7-66f56bfb16d7": {
86
- id: "7166a301-aad9-4bc9-b9f7-66f56bfb16d7",
87
- userId: "0fe5311c-42c4-425b-b7a4-0338dc08048f",
88
- name: "user8",
89
- avatarUrl: "https://s3.amazonaws.com/path8",
90
- geoLocation: {},
91
- timestamp: 1615649132502,
92
- state: "active",
93
- isHost: false
94
- },
95
- "1e168941-4050-4731-8c27-f2464c717c4a": {
96
- id: "1e168941-4050-4731-8c27-f2464c717c4a",
97
- userId: "69308515-a3af-4ce6-b687-139ef0b87e74",
98
- name: "user9",
99
- avatarUrl: "https://s3.amazonaws.com/path9",
100
- geoLocation: {},
101
- timestamp: 1615642032502,
102
- state: "idle",
103
- isHost: false
104
- },
105
- "f1056e6c-c393-4617-8a06-67ba9d2f4b8a": {
106
- id: "f1056e6c-c393-4617-8a06-67ba9d2f4b8a",
107
- userId: "0cc39ce5-f00f-4b81-ab8b-40e630b3a58c",
108
- name: "user10",
109
- avatarUrl: "https://s3.amazonaws.com/path10",
110
- geoLocation: {},
111
- timestamp: 1615642032502,
112
- state: "idle",
113
- isHost: false
114
- },
13
+ "e053977c-dcb6-40e0-b7b8-e3dbd70ec8fd": {
14
+ id: "e053977c-dcb6-40e0-b7b8-e3dbd70ec8fd",
15
+ userId: "09f3cbf9-0c73-44c6-b6ad-a03b3607e66a",
16
+ name: "user1",
17
+ avatarUrl: "https://s3.amazonaws.com/path1",
18
+ geoLocation: {},
19
+ timestamp: 1615649132502,
20
+ state: "active",
21
+ isHost: false
22
+ },
23
+ "0f6ab786-fcae-4e81-87ac-a3930f496d71": {
24
+ id: "0f6ab786-fcae-4e81-87ac-a3930f496d71",
25
+ userId: "819635b2-c70d-474c-a0a6-88a420744cb6",
26
+ name: "user2",
27
+ avatarUrl: "https://s3.amazonaws.com/path2",
28
+ geoLocation: {},
29
+ timestamp: 1615649132502,
30
+ state: "active",
31
+ isHost: false
32
+ },
33
+ "af9c7ff6-c8c9-4f4a-ad04-bcf86ef57d15": {
34
+ id: "af9c7ff6-c8c9-4f4a-ad04-bcf86ef57d15",
35
+ userId: "7966b0b6-1c94-4f2d-abf0-857ccf91119e",
36
+ name: "user3",
37
+ avatarUrl: "https://s3.amazonaws.com/path3",
38
+ geoLocation: {},
39
+ timestamp: 1615649132502,
40
+ state: "active",
41
+ isHost: false
42
+ },
43
+ "777b11b5-2b3b-4420-93d2-eff65127c925": {
44
+ id: "777b11b5-2b3b-4420-93d2-eff65127c925",
45
+ userId: "0efde18e-39ff-4e26-9aa5-2f7b8d61b2f7",
46
+ name: "user4",
47
+ avatarUrl: "https://s3.amazonaws.com/path4",
48
+ geoLocation: {},
49
+ timestamp: 1615649132502,
50
+ state: "active",
51
+ isHost: false
52
+ },
53
+ "6405094a-0ac4-4476-9fd8-5d2edc6cf5a1": {
54
+ id: "6405094a-0ac4-4476-9fd8-5d2edc6cf5a1",
55
+ userId: "cdcbbb6a-0a3b-4222-bcde-4a626555f44d",
56
+ name: "user5",
57
+ avatarUrl: "https://s3.amazonaws.com/path5",
58
+ geoLocation: {},
59
+ timestamp: 1615649132502,
60
+ state: "active",
61
+ isHost: false
115
62
  },
116
- idleMsecs: 1800000,
117
- purgeMsecs: 7200000
63
+ "dcaabc23-b7dc-47cd-ad11-43022750dc0e": {
64
+ id: "dcaabc23-b7dc-47cd-ad11-43022750dc0e",
65
+ userId: "ad6a1e91-6460-4eea-b215-4af4de4e021e",
66
+ name: "user6",
67
+ avatarUrl: "https://s3.amazonaws.com/path6",
68
+ geoLocation: {},
69
+ timestamp: 1615649132502,
70
+ state: "active",
71
+ isHost: false
72
+ },
73
+ "78127e6c-c1b8-490d-ace6-afc798fdf4f6": {
74
+ id: "78127e6c-c1b8-490d-ace6-afc798fdf4f6",
75
+ userId: "d8584429-4651-4d63-a886-1622941f9b87",
76
+ name: "user7",
77
+ avatarUrl: "https://s3.amazonaws.com/path7",
78
+ geoLocation: {},
79
+ timestamp: 1615649132502,
80
+ state: "active",
81
+ isHost: false
82
+ },
83
+ "7166a301-aad9-4bc9-b9f7-66f56bfb16d7": {
84
+ id: "7166a301-aad9-4bc9-b9f7-66f56bfb16d7",
85
+ userId: "0fe5311c-42c4-425b-b7a4-0338dc08048f",
86
+ name: "user8",
87
+ avatarUrl: "https://s3.amazonaws.com/path8",
88
+ geoLocation: {},
89
+ timestamp: 1615649132502,
90
+ state: "active",
91
+ isHost: false
92
+ },
93
+ "1e168941-4050-4731-8c27-f2464c717c4a": {
94
+ id: "1e168941-4050-4731-8c27-f2464c717c4a",
95
+ userId: "69308515-a3af-4ce6-b687-139ef0b87e74",
96
+ name: "user9",
97
+ avatarUrl: "https://s3.amazonaws.com/path9",
98
+ geoLocation: {},
99
+ timestamp: 1615642032502,
100
+ state: "idle",
101
+ isHost: false
102
+ },
103
+ "f1056e6c-c393-4617-8a06-67ba9d2f4b8a": {
104
+ id: "f1056e6c-c393-4617-8a06-67ba9d2f4b8a",
105
+ userId: "0cc39ce5-f00f-4b81-ab8b-40e630b3a58c",
106
+ name: "user10",
107
+ avatarUrl: "https://s3.amazonaws.com/path10",
108
+ geoLocation: {},
109
+ timestamp: 1615642032502,
110
+ state: "idle",
111
+ isHost: false
112
+ }
118
113
  }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ const AnearParticipantJSONBuilder = ({eventId, id, userId, name, avatarUrl}) => {
3
+ return {
4
+ data: {
5
+ "id": id,
6
+ "type": "participants",
7
+ "attributes": {
8
+ "created-at": "2019-06-22T08:41:34.257Z",
9
+ "name": name,
10
+ "user-type": "participant",
11
+ "private-channel-name": "anear:a:6i4GPGg7YiE81jxE65vpov:e:51nriTFWJYwiZRVfhaTmOM:private:4aih3BnWiRXLHKupFFkKHO"
12
+ },
13
+ "relationships": {
14
+ "event": {
15
+ "data": {
16
+ "id": eventId,
17
+ "type": "events"
18
+ }
19
+ },
20
+ "user": {
21
+ "data": {
22
+ "id": "2d08adc7-b1af-4607-2a86-b45faa03eaa7",
23
+ "type": "users"
24
+ }
25
+ }
26
+ }
27
+ },
28
+ included: [
29
+ {
30
+ "id": userId,
31
+ "type": "users",
32
+ "attributes": {
33
+ "name": "dave_mcvicar",
34
+ "created-at": "2019-06-22T08:41:33.877Z"
35
+ },
36
+ "relationships": {
37
+ "profile": {
38
+ "data": {
39
+ "id": "a04976a9-1c08-4bc6-b381-7f0d0637b919",
40
+ "type": "profiles"
41
+ }
42
+ }
43
+ },
44
+ "links": {
45
+ "self": `/v1/users/${userId}`
46
+ }
47
+ },
48
+ {
49
+ "id": "a04976a9-1c08-4bc6-b381-7f0d0637b919",
50
+ "type": "profiles",
51
+ "attributes": {
52
+ "first-name": "Dave",
53
+ "last-name": "McVicar",
54
+ "bio": "Repellendus ut neque. Est autem cupiditate. In omnis dolore.",
55
+ "homepage": "http://hodkiewicz.name/frankie",
56
+ "avatar-url": avatarUrl
57
+ },
58
+ "links": {
59
+ "self": "/v1/profiles/b04976a9-1c08-4bc6-b381-7f0d0637b979"
60
+ }
61
+ }
62
+ ]
63
+ }
64
+ }
65
+
66
+ module.exports = AnearParticipantJSONBuilder