|
|
|
@ -3,6 +3,14 @@ |
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later |
|
|
|
*/ |
|
|
|
|
|
|
|
import type { |
|
|
|
Conversation, |
|
|
|
Participant, |
|
|
|
SignalingSessionPayload, |
|
|
|
StandaloneSignalingLeaveSession, |
|
|
|
StandaloneSignalingUpdateSession, |
|
|
|
} from '../types/index.ts' |
|
|
|
|
|
|
|
import { createSharedComposable } from '@vueuse/core' |
|
|
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue' |
|
|
|
import { CONFIG, CONVERSATION } from '../constants.ts' |
|
|
|
@ -17,6 +25,12 @@ import { useStore } from './useStore.js' |
|
|
|
|
|
|
|
const experimentalUpdateParticipants = (getTalkConfig('local', 'experiments', 'enabled') ?? 0) & CONFIG.EXPERIMENTAL.UPDATE_PARTICIPANTS |
|
|
|
|
|
|
|
let fetchingParticipants = false |
|
|
|
let pendingChanges = true |
|
|
|
let throttleFastUpdateTimeout: NodeJS.Timeout | undefined |
|
|
|
let throttleSlowUpdateTimeout: NodeJS.Timeout | undefined |
|
|
|
let throttleLongUpdateTimeout: NodeJS.Timeout | undefined |
|
|
|
|
|
|
|
/** |
|
|
|
* Composable to control logic for fetching participants list |
|
|
|
* |
|
|
|
@ -31,16 +45,11 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
|
|
|
|
const isActive = computed(() => activeTab.value === 'participants') |
|
|
|
const token = useGetToken() |
|
|
|
const conversation = computed(() => store.getters.conversation(token.value)) |
|
|
|
const isInLobby = computed(() => store.getters.isInLobby) |
|
|
|
const isModeratorOrUser = computed(() => store.getters.isModeratorOrUser) |
|
|
|
const conversation = computed<Conversation | undefined>(() => store.getters.conversation(token.value)) |
|
|
|
const isInLobby = computed<boolean>(() => store.getters.isInLobby) |
|
|
|
const isModeratorOrUser = computed<boolean>(() => store.getters.isModeratorOrUser) |
|
|
|
const isOneToOneConversation = computed(() => conversation.value?.type === CONVERSATION.TYPE.ONE_TO_ONE |
|
|
|
|| conversation.value?.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER) |
|
|
|
let fetchingParticipants = false |
|
|
|
let pendingChanges = true |
|
|
|
let throttleFastUpdateTimeout = null |
|
|
|
let throttleSlowUpdateTimeout = null |
|
|
|
let throttleLongUpdateTimeout = null |
|
|
|
|
|
|
|
/** |
|
|
|
* Initialise the get participants listeners |
|
|
|
@ -64,7 +73,10 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
EventBus.on('signaling-users-changed', checkCurrentUserPermissions) |
|
|
|
} |
|
|
|
|
|
|
|
const handleUsersUpdated = async ([users]) => { |
|
|
|
/** |
|
|
|
* Patch participants list from signaling messages (joined/changed) |
|
|
|
*/ |
|
|
|
function handleUsersUpdated([users]: [SignalingSessionPayload[]]) { |
|
|
|
if (sessionStore.updateSessions(token.value, users)) { |
|
|
|
throttleUpdateParticipants() |
|
|
|
} else { |
|
|
|
@ -72,7 +84,10 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const checkCurrentUserPermissions = async ([users]) => { |
|
|
|
/** |
|
|
|
* Check if current user permission has been changed from signaling messages |
|
|
|
*/ |
|
|
|
async function checkCurrentUserPermissions([users]: [StandaloneSignalingUpdateSession[]]) { |
|
|
|
// TODO: move logic to sessionStore once experimental flag is dropped
|
|
|
|
const currentUser = users.find((user) => { |
|
|
|
return user.userId ? user.userId === actorStore.userId : user.actorId === actorStore.actorId |
|
|
|
@ -91,14 +106,22 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const handleUsersLeft = ([sessionIds]) => { |
|
|
|
/** |
|
|
|
* Patch participants list from signaling messages (left) |
|
|
|
*/ |
|
|
|
function handleUsersLeft([sessionIds]: [StandaloneSignalingLeaveSession[]]) { |
|
|
|
sessionStore.updateSessionsLeft(token.value, sessionIds) |
|
|
|
throttleLongUpdate() |
|
|
|
} |
|
|
|
const handleUsersDisconnected = () => { |
|
|
|
|
|
|
|
/** |
|
|
|
* Patch participants list from signaling messages (end call for everyone) |
|
|
|
*/ |
|
|
|
function handleUsersDisconnected() { |
|
|
|
sessionStore.updateParticipantsDisconnectedFromStandaloneSignaling(token.value) |
|
|
|
throttleLongUpdate() |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Stop the get participants listeners |
|
|
|
* |
|
|
|
@ -115,7 +138,10 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
EventBus.off('signaling-users-changed', checkCurrentUserPermissions) |
|
|
|
} |
|
|
|
|
|
|
|
const onJoinedConversation = () => { |
|
|
|
/** |
|
|
|
* Trigger participants list update upon joining |
|
|
|
*/ |
|
|
|
async function onJoinedConversation() { |
|
|
|
if (isOneToOneConversation.value || experimentalUpdateParticipants) { |
|
|
|
cancelableGetParticipants() |
|
|
|
} else { |
|
|
|
@ -123,7 +149,12 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const throttleUpdateParticipants = () => { |
|
|
|
/** |
|
|
|
* Schedule a participants list update depending on conditions: |
|
|
|
* - participant list is visible - fast update |
|
|
|
* - chat is open, tab is in background, user is not in the current call - slow update |
|
|
|
*/ |
|
|
|
function throttleUpdateParticipants() { |
|
|
|
if (!isActive.value && !isInCall.value) { |
|
|
|
// Update is ignored but there is a flag to force the participants update
|
|
|
|
pendingChanges = true |
|
|
|
@ -138,7 +169,10 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
pendingChanges = false |
|
|
|
} |
|
|
|
|
|
|
|
const cancelableGetParticipants = async () => { |
|
|
|
/** |
|
|
|
* Update participants list |
|
|
|
*/ |
|
|
|
async function cancelableGetParticipants() { |
|
|
|
if (fetchingParticipants || token.value === '' || isInLobby.value || !isModeratorOrUser.value) { |
|
|
|
return |
|
|
|
} |
|
|
|
@ -150,17 +184,28 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
fetchingParticipants = false |
|
|
|
} |
|
|
|
|
|
|
|
const throttleFastUpdate = () => { |
|
|
|
/** |
|
|
|
* Schedule a participants list update (in 3 seconds) |
|
|
|
*/ |
|
|
|
function throttleFastUpdate() { |
|
|
|
if (!fetchingParticipants && !throttleFastUpdateTimeout) { |
|
|
|
throttleFastUpdateTimeout = setTimeout(cancelableGetParticipants, 3_000) |
|
|
|
} |
|
|
|
} |
|
|
|
const throttleSlowUpdate = () => { |
|
|
|
|
|
|
|
/** |
|
|
|
* Schedule a participants list update (in 15 seconds) |
|
|
|
*/ |
|
|
|
function throttleSlowUpdate() { |
|
|
|
if (!fetchingParticipants && !throttleSlowUpdateTimeout) { |
|
|
|
throttleSlowUpdateTimeout = setTimeout(cancelableGetParticipants, 15_000) |
|
|
|
} |
|
|
|
} |
|
|
|
const throttleLongUpdate = () => { |
|
|
|
|
|
|
|
/** |
|
|
|
* Schedule a participants list update (in 60 seconds) |
|
|
|
*/ |
|
|
|
function throttleLongUpdate() { |
|
|
|
if (!fetchingParticipants && !throttleLongUpdateTimeout) { |
|
|
|
throttleLongUpdateTimeout = setTimeout(cancelableGetParticipants, 60_000) |
|
|
|
} |
|
|
|
@ -196,11 +241,11 @@ function useGetParticipantsComposable(activeTab = ref('participants')) { |
|
|
|
*/ |
|
|
|
function cancelPendingUpdates() { |
|
|
|
clearTimeout(throttleFastUpdateTimeout) |
|
|
|
throttleFastUpdateTimeout = null |
|
|
|
throttleFastUpdateTimeout = undefined |
|
|
|
clearTimeout(throttleSlowUpdateTimeout) |
|
|
|
throttleSlowUpdateTimeout = null |
|
|
|
throttleSlowUpdateTimeout = undefined |
|
|
|
clearTimeout(throttleLongUpdateTimeout) |
|
|
|
throttleLongUpdateTimeout = null |
|
|
|
throttleLongUpdateTimeout = undefined |
|
|
|
} |
|
|
|
|
|
|
|
return { |