Skip to content

Commit

Permalink
feat(participants): update participants changed data from standalone …
Browse files Browse the repository at this point in the history
…signaling

Signed-off-by: Maksim Sukharev <[email protected]>
  • Loading branch information
Antreesy committed Jun 25, 2024
1 parent e79dabb commit 957461b
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/composables/useGetParticipants.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export function useGetParticipants(isActive = ref(true), isTopBar = true) {
EventBus.on('signaling-users-in-room', updateUsersFromInternalSignaling)
EventBus.on('signaling-users-joined', updateUsersJoinedFromStandaloneSignaling)
EventBus.on('signaling-users-left', updateUsersLeftFromStandaloneSignaling)
EventBus.on('signaling-users-changed', updateUsersChangedFromStandaloneSignaling)
EventBus.on('signaling-all-users-changed-in-call-to-disconnected', updateUsersCallDisconnectedFromStandaloneSignaling)
// FIXME this works only temporary until signaling is fixed to be only on the calls
// Then we have to search for another solution. Maybe the room list which we update
// periodically gets a hash of all online sessions?
Expand All @@ -63,6 +65,14 @@ export function useGetParticipants(isActive = ref(true), isTopBar = true) {
const signalingStore = useSignalingStore()
signalingStore.updateParticipantsLeftFromStandaloneSignaling(signalingSessionIds)
}
const updateUsersChangedFromStandaloneSignaling = ([participants]) => {
const signalingStore = useSignalingStore()
signalingStore.updateParticipantsChangedFromStandaloneSignaling(token.value, participants)
}
const updateUsersCallDisconnectedFromStandaloneSignaling = () => {
const signalingStore = useSignalingStore()
signalingStore.updateParticipantsCallDisconnectedFromStandaloneSignaling(token.value)
}
/**
* Stop the get participants listeners
*
Expand All @@ -72,6 +82,8 @@ export function useGetParticipants(isActive = ref(true), isTopBar = true) {
EventBus.off('signaling-users-in-room', updateUsersFromInternalSignaling)
EventBus.off('signaling-users-joined', updateUsersJoinedFromStandaloneSignaling)
EventBus.off('signaling-users-left', updateUsersLeftFromStandaloneSignaling)
EventBus.off('signaling-users-changed', updateUsersChangedFromStandaloneSignaling)
EventBus.off('signaling-all-users-changed-in-call-to-disconnected', updateUsersCallDisconnectedFromStandaloneSignaling)
EventBus.off('signaling-participant-list-changed', debounceUpdateParticipants)
unsubscribe('guest-promoted', onJoinedConversation)
}
Expand Down
46 changes: 46 additions & 0 deletions src/stores/__tests__/signaling.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ describe('signalingStore', () => {
{ userid: '', user: { displayname: 'Guest' }, sessionid: 'signaling-id-4', roomsessionid: 'session-id-4' },
]

const participantsChangedPayload = [
{ userId: 'user1', sessionId: 'signaling-id-1', inCall: 7, participantType: 1, lastPing: 1717192800, participantPermissions: 254 },
{ userId: 'user2', sessionId: 'signaling-id-2', inCall: 7, participantType: 3, lastPing: 1717192800, participantPermissions: 254 },
{ userId: 'user2', sessionId: 'signaling-id-3', inCall: 0, participantType: 3, lastPing: 1717192800, participantPermissions: 254 },
{ userId: '', displayName: 'Guest New', sessionId: 'signaling-id-4', inCall: 7, participantType: 6, lastPing: 1717192800, participantPermissions: 254 },
{ userId: '', sessionId: 'signaling-id-unknown', inCall: 7, participantType: 3, lastPing: 1717192800, participantPermissions: 254 },
]

it('should return a mapped object for a known session', () => {
// Arrange
populateParticipantsStore()
Expand Down Expand Up @@ -216,5 +224,43 @@ describe('signalingStore', () => {
{ token: TOKEN, attendeeId: 3, updatedData: { inCall: 0, sessionIds: [] } })

})

it('should update participant objects for a known session on change', () => {
// Arrange
jest.spyOn(vuexStore, 'commit')
populateParticipantsStore()
signalingStore.updateParticipantsJoinedFromStandaloneSignaling(TOKEN, participantsJoinedPayload)

// Act
signalingStore.updateParticipantsChangedFromStandaloneSignaling(TOKEN, participantsChangedPayload)

// Assert
expect(vuexStore.commit).toHaveBeenCalledTimes(6)
expect(vuexStore.commit).toHaveBeenNthCalledWith(4, 'updateParticipant',
{ token: TOKEN, attendeeId: 1, updatedData: { inCall: 7, participantType: 1, lastPing: 1717192800, permissions: 254 } })
expect(vuexStore.commit).toHaveBeenNthCalledWith(5, 'updateParticipant',
{ token: TOKEN, attendeeId: 2, updatedData: { inCall: 7, participantType: 3, lastPing: 1717192800, permissions: 254 } })
expect(vuexStore.commit).toHaveBeenNthCalledWith(6, 'updateParticipant',
{ token: TOKEN, attendeeId: 3, updatedData: { displayName: 'Guest New', inCall: 7, participantType: 6, lastPing: 1717192800, permissions: 254 } })
})

it('should update participant objects for a known session on call disconnect', () => {
// Arrange
jest.spyOn(vuexStore, 'commit')
populateParticipantsStore()
signalingStore.updateParticipantsJoinedFromStandaloneSignaling(TOKEN, participantsJoinedPayload)

// Act
signalingStore.updateParticipantsCallDisconnectedFromStandaloneSignaling(TOKEN)

// Assert
expect(vuexStore.commit).toHaveBeenCalledTimes(6)
expect(vuexStore.commit).toHaveBeenNthCalledWith(4, 'updateParticipant',
{ token: TOKEN, attendeeId: 1, updatedData: { inCall: 0 } })
expect(vuexStore.commit).toHaveBeenNthCalledWith(5, 'updateParticipant',
{ token: TOKEN, attendeeId: 2, updatedData: { inCall: 0 } })
expect(vuexStore.commit).toHaveBeenNthCalledWith(6, 'updateParticipant',
{ token: TOKEN, attendeeId: 3, updatedData: { inCall: 0 } })
})
})
})
89 changes: 89 additions & 0 deletions src/stores/signaling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import Hex from 'crypto-js/enc-hex.js'
import SHA1 from 'crypto-js/sha1.js'
import { defineStore } from 'pinia'
import Vue from 'vue'

import { useGuestNameStore } from './guestName.js'
import { ATTENDEE, PARTICIPANT } from '../constants.js'
import store from '../store/index.js'
import type { Participant } from '../types'
Expand Down Expand Up @@ -36,6 +39,23 @@ type StandaloneSignalingJoinPayload = {
sessionid: string, // Standalone signaling id
roomsessionid: string, // Nextcloud id
}
type StandaloneSignalingChangePayload = {
sessionId: string, // Standalone signaling id
participantType: number,
participantPermissions: number,
inCall: number,
lastPing: number,
nextcloudSessionId?: string, // Nextcloud id
userId?: string, // For registered users only
displayName?: string,
}
type StandaloneUpdatePayload = Record<string, {
inCall: number,
lastPing: number,
permissions: number,
participantType: number,
displayName?: string,
}>

type State = {
sessions: Record<string, Session>,
Expand Down Expand Up @@ -223,5 +243,74 @@ export const useSignalingStore = defineStore('signaling', {
}
},

/**
* Update participants changed in store according to data from standalone signaling server
*
* @param token the conversation token;
* @param participants the changed participant objects;
*/
updateParticipantsChangedFromStandaloneSignaling(token: string, participants: StandaloneSignalingChangePayload[]) {
const guestNameStore = useGuestNameStore()
const attendeeUsersToUpdate: StandaloneUpdatePayload = {}

for (const participant of participants) {
const session = this.getSignalingSession(participant.sessionId)
if (!session?.attendeeId) {
continue
}
const { token, attendeeId } = session

if (!attendeeUsersToUpdate[attendeeId]) {
attendeeUsersToUpdate[attendeeId] = {
participantType: participant.participantType,
permissions: participant.participantPermissions,
inCall: participant.inCall,
lastPing: participant.lastPing,
}
} else {
// Participant might join from several devices
attendeeUsersToUpdate[attendeeId].inCall
= Math.max(attendeeUsersToUpdate[attendeeId].inCall, participant.inCall)
}
if (participant.displayName) {
attendeeUsersToUpdate[attendeeId].displayName = participant.displayName
const attendee = store.getters.getParticipant(token, attendeeId) as Participant

if (attendee.displayName !== participant.displayName
&& (participant.participantType === PARTICIPANT.TYPE.GUEST
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR)) {
guestNameStore.addGuestName({
token,
actorId: Hex.stringify(SHA1(attendee.sessionIds[0])),
actorDisplayName: participant.displayName,
}, { noUpdate: false })
}
}
}

for (const [attendeeId, updatedData] of Object.entries(attendeeUsersToUpdate)) {
store.commit('updateParticipant', {
token,
attendeeId: +attendeeId,
updatedData,
})
}
},

/**
* Update participants (end call for everyone) in store according to data from standalone signaling server
*
* @param token conversation token;
*/
updateParticipantsCallDisconnectedFromStandaloneSignaling(token: string) {
const attendeeUsers = store.getters.participantsList(token) as Participant[]
for (const attendee of attendeeUsers) {
store.commit('updateParticipant', {
token,
attendeeId: attendee.attendeeId,
updatedData: { inCall: PARTICIPANT.CALL_FLAG.DISCONNECTED }
})
}
},
},
})

0 comments on commit 957461b

Please sign in to comment.