diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/hooks/index.ts b/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/hooks/index.ts index 84c90676db..5f9653654f 100644 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/hooks/index.ts +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/hooks/index.ts @@ -1,4 +1,9 @@ -import { useCallback, useEffect, useState } from 'react'; +import { + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; import { useSubscription, useReactiveVar, @@ -25,14 +30,14 @@ import { import { OWN_VIDEO_STREAMS_QUERY, VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION, - VIDEO_STREAMS_USERS_SUBSCRIPTION, + GRID_USERS_SUBSCRIPTION, VIEWERS_IN_WEBCAM_COUNT_SUBSCRIPTION, VideoStreamsUsersResponse, OwnVideoStreamsResponse, } from '../queries'; import videoService from '../service'; import { CAMERA_BROADCAST_STOP } from '../mutations'; -import { GridItem, StreamItem } from '../types'; +import { StreamItem } from '../types'; import { DesktopPageSizes, MobilePageSizes } from '/imports/ui/Types/meetingClientSettings'; import logger from '/imports/startup/client/logger'; @@ -240,43 +245,76 @@ type StreamUser = VideoStreamsUsersResponse['user'][number] & { sortName: string; }; +type GridUser = StreamUser & { type: 'grid' }; + export const useStreamUsers = (isGridEnabled: boolean) => { const { streams } = useStreams(); - const subscription = isGridEnabled - ? VIDEO_STREAMS_USERS_SUBSCRIPTION - : VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION; - const variables = isGridEnabled - ? {} - : { userIds: streams.map((s) => s.userId) }; - const { data, loading, error } = useSubscription( - subscription, - { variables }, - ); + const gridSize = useGridSize(); const [users, setUsers] = useState([]); + const [gridUsers, setGridUsers] = useState([]); + const userIds = useMemo(() => streams.map((s) => s.userId), [streams]); + const streamCount = streams.length; + const { data, loading, error } = useSubscription( + VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION, + { variables: { userIds } }, + ); + const { + data: gridData, + loading: gridLoading, + error: gridError, + } = useSubscription( + GRID_USERS_SUBSCRIPTION, + { + variables: { exceptUserIds: userIds, limit: Math.max(gridSize - streamCount, 0) }, + skip: !isGridEnabled, + }, + ); useEffect(() => { if (loading) return; if (error) { - logger.error(`Error on load stream users. name=${error.name}`, error); + logger.error(`Stream users subscription failed. name=${error.name}`, error); } if (data) { - const newData = data.user.map((user) => ({ + const newUsers = data.user.map((user) => ({ ...user, pin: user.pinned, sortName: user.nameSortable, })); - setUsers(newData); + setUsers(newUsers); } else { setUsers([]); } }, [data]); + useEffect(() => { + if (gridLoading) return; + + if (gridError) { + logger.error(`Grid users subscription failed. name=${gridError.name}`, gridError); + } + + if (gridData) { + const newGridUsers = gridData.user.map((user) => ({ + ...user, + pin: user.pinned, + sortName: user.nameSortable, + type: 'grid' as const, + })); + setGridUsers(newGridUsers); + } else { + setGridUsers([]); + } + }, [gridData]); + return { + streams, users, - loading, - error, + gridUsers, + loading: loading || gridLoading, + error: error || gridError, }; }; @@ -325,14 +363,11 @@ export const useVideoStreams = ( ) => { const [state] = useVideoState(); const { currentVideoPageIndex, numberOfPages } = state; - const { users } = useStreamUsers(isGridEnabled); - const { streams: videoStreams } = useStreams(); + const { users, gridUsers, streams: videoStreams } = useStreamUsers(isGridEnabled); const connectingStream = useConnectingStream(videoStreams); - const gridSize = useGridSize(); const myPageSize = useMyPageSize(); const isPaginationEnabled = useIsPaginationEnabled(paginationEnabled); let streams: StreamItem[] = [...videoStreams]; - let gridUsers: GridItem[] = []; if (connectingStream) streams.push(connectingStream); @@ -386,20 +421,6 @@ export const useVideoStreams = ( streams = sortVideoStreams(streams, DEFAULT_SORTING); } - if (isGridEnabled) { - const streamUsers = streams.map((stream) => stream.userId); - - gridUsers = users - .filter( - (user) => !user.loggedOut && !user.left && !streamUsers.includes(user.userId), - ) - .map((user) => ({ - type: 'grid' as const, - ...user, - })) - .slice(0, gridSize - streams.length); - } - return { streams, gridUsers, diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/queries.ts b/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/queries.ts index c2d8e660c2..b0e726f367 100644 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/queries.ts +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-provider-graphql/queries.ts @@ -23,7 +23,6 @@ export interface VideoStreamsUsersResponse { pinned: boolean; nameSortable: string; name: string; - loggedOut: boolean; away: boolean; disconnected: boolean; emoji: string; @@ -34,7 +33,6 @@ export interface VideoStreamsUsersResponse { clientType: string; raiseHand: boolean; isModerator: boolean; - left: boolean; reaction: { reactionEmoji: string; }; @@ -90,14 +88,24 @@ export const VIEWERS_IN_WEBCAM_COUNT_SUBSCRIPTION = gql` } `; -export const VIDEO_STREAMS_USERS_SUBSCRIPTION = gql` - subscription VideoStreamsUsers { - user { +export const GRID_USERS_SUBSCRIPTION = gql` + subscription GridUsers($exceptUserIds: [String]!, $limit: Int!) { + user( + where: { + userId: { + _nin: $exceptUserIds, + }, + }, + limit: $limit, + order_by: { + nameSortable: asc, + userId: asc, + }, + ) { name userId nameSortable pinned - loggedOut away disconnected emoji @@ -129,7 +137,6 @@ export const VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION = gql` userId nameSortable pinned - loggedOut away disconnected emoji @@ -152,5 +159,6 @@ export default { OWN_VIDEO_STREAMS_QUERY, VIDEO_STREAMS_SUBSCRIPTION, VIEWERS_IN_WEBCAM_COUNT_SUBSCRIPTION, - VIDEO_STREAMS_USERS_SUBSCRIPTION, + GRID_USERS_SUBSCRIPTION, + VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION, };