Merge pull request #20168 from JoVictorNunes/grid-user-limit

fix: limit grid users at the data access level
This commit is contained in:
Gustavo Trott 2024-05-07 09:16:42 -03:00 committed by GitHub
commit 4b91675658
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 73 additions and 44 deletions

View File

@ -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<VideoStreamsUsersResponse>(
subscription,
{ variables },
);
const gridSize = useGridSize();
const [users, setUsers] = useState<StreamUser[]>([]);
const [gridUsers, setGridUsers] = useState<GridUser[]>([]);
const userIds = useMemo(() => streams.map((s) => s.userId), [streams]);
const streamCount = streams.length;
const { data, loading, error } = useSubscription<VideoStreamsUsersResponse>(
VIDEO_STREAMS_USERS_FILTERED_SUBSCRIPTION,
{ variables: { userIds } },
);
const {
data: gridData,
loading: gridLoading,
error: gridError,
} = useSubscription<VideoStreamsUsersResponse>(
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,

View File

@ -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,
};