Remove: presentation upload token subscription

This commit is contained in:
Tainan Felipe 2024-04-23 16:51:08 -03:00
parent db3e46b711
commit f5fdc915cf
17 changed files with 82 additions and 289 deletions

View File

@ -1,7 +1,6 @@
import AbstractCollection from '/imports/ui/services/LocalCollectionSynchronizer/LocalCollectionSynchronizer';
// Collections
import PresentationUploadToken from '/imports/api/presentation-upload-token';
import Screenshare from '/imports/api/screenshare';
import UserInfos from '/imports/api/users-infos';
import UserSettings from '/imports/api/users-settings';
@ -17,10 +16,6 @@ import Users from '/imports/api/users';
// Custom Publishers
export const localCollectionRegistry = {
localPresentationUploadTokenSync: new AbstractCollection(
PresentationUploadToken,
PresentationUploadToken,
),
localScreenshareSync: new AbstractCollection(Screenshare, Screenshare),
localUserInfosSync: new AbstractCollection(UserInfos, UserInfos),
localUserSettingsSync: new AbstractCollection(UserSettings, UserSettings),

View File

@ -1,7 +0,0 @@
const collectionOptions = Meteor.isClient ? {
connection: null,
} : {};
const PresentationUploadToken = new Mongo.Collection('presentation-upload-token', collectionOptions);
export default PresentationUploadToken;

View File

@ -1,8 +0,0 @@
import RedisPubSub from '/imports/startup/server/redis';
import { processForHTML5ServerOnly } from '/imports/api/common/server/helpers';
import handlePresentationUploadTokenPass from './handlers/presentationUploadTokenPass';
import handlePresentationUploadTokenFail from './handlers/presentationUploadTokenFail';
RedisPubSub.on('PresentationUploadTokenPassRespMsg', processForHTML5ServerOnly(handlePresentationUploadTokenPass));
RedisPubSub.on('PresentationUploadTokenFailRespMsg', processForHTML5ServerOnly(handlePresentationUploadTokenFail));

View File

@ -1,32 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import PresentationUploadToken from '/imports/api/presentation-upload-token';
export default async function handlePresentationUploadTokenFail({ body, header }, meetingId) {
check(body, Object);
const { userId } = header;
const { podId, filename } = body;
check(userId, String);
check(podId, String);
check(filename, String);
const selector = {
meetingId,
userId,
podId,
filename,
};
try {
const { numberAffected } = await PresentationUploadToken
.upsertAsync(selector, { failed: true, authzToken: null });
if (numberAffected) {
Logger.info(`Removing presentationToken filename=${filename} podId=${podId} meeting=${meetingId}`);
}
} catch (err) {
Logger.error(`Removing presentationToken from collection: ${err}`);
}
}

View File

@ -1,45 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import PresentationUploadToken from '/imports/api/presentation-upload-token';
export default async function handlePresentationUploadTokenPass({ body, header }, meetingId) {
check(body, Object);
const { userId } = header;
const { podId, authzToken, filename, temporaryPresentationId } = body;
check(userId, String);
check(podId, String);
check(authzToken, String);
check(filename, String);
check(temporaryPresentationId, String)
const selector = {
meetingId,
podId,
userId,
filename,
temporaryPresentationId,
};
const modifier = {
meetingId,
podId,
userId,
filename,
authzToken,
temporaryPresentationId,
failed: false,
used: false,
};
try {
const { insertedId } = await PresentationUploadToken.upsertAsync(selector, modifier);
if (insertedId) {
Logger.info(`Inserting presentationToken filename=${filename} podId=${podId} meeting=${meetingId}`);
}
} catch (err) {
Logger.error(`Inserting presentationToken from collection: ${err}`);
}
}

View File

@ -1,3 +0,0 @@
import './eventHandlers';
import './methods';
import './publishers';

View File

@ -1,8 +0,0 @@
import { Meteor } from 'meteor/meteor';
import requestPresentationUploadToken from './methods/requestPresentationUploadToken';
import setUsedToken from './methods/setUsedToken';
Meteor.methods({
requestPresentationUploadToken,
setUsedToken,
});

View File

@ -1,34 +0,0 @@
import RedisPubSub from '/imports/startup/server/redis';
import { check } from 'meteor/check';
import { extractCredentials } from '/imports/api/common/server/helpers';
import Logger from '/imports/startup/server/logger';
export default async function requestPresentationUploadToken(
podId,
filename,
temporaryPresentationId,
) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
const EVENT_NAME = 'PresentationUploadTokenReqMsg';
try {
const { meetingId, requesterUserId } = extractCredentials(this.userId);
check(meetingId, String);
check(requesterUserId, String);
check(podId, String);
check(filename, String);
check(temporaryPresentationId, String);
const payload = {
podId,
filename,
uploadTemporaryId: temporaryPresentationId,
};
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
} catch (err) {
Logger.error(`Exception while invoking method requestPresentationUploadToken ${err.stack}`);
}
}

View File

@ -1,32 +0,0 @@
import PresentationUploadToken from '/imports/api/presentation-upload-token';
import Logger from '/imports/startup/server/logger';
import { extractCredentials } from '/imports/api/common/server/helpers';
import { check } from 'meteor/check';
export default async function setUsedToken(authzToken) {
try {
const { meetingId, requesterUserId } = extractCredentials(this.userId);
check(meetingId, String);
check(requesterUserId, String);
check(authzToken, String);
const payload = {
$set: {
used: true,
},
};
const numberAffected = await PresentationUploadToken.updateAsync({
meetingId,
userId: requesterUserId,
authzToken,
}, payload);
if (numberAffected) {
Logger.info(`Token: ${authzToken} has been set as used in meeting=${meetingId}`);
}
} catch (err) {
Logger.error(`Exception while invoking method setUsedToken ${err.stack}`);
}
}

View File

@ -1,44 +0,0 @@
import PresentationUploadToken from '/imports/api/presentation-upload-token';
import Logger from '/imports/startup/server/logger';
export default async function clearPresentationUploadToken(
meetingId,
podId,
) {
if (meetingId && podId) {
try {
const numberAffected = await PresentationUploadToken.removeAsync({ meetingId, podId });
if (numberAffected) {
Logger.info(`Cleared Presentations Upload Token (${meetingId}, ${podId})`);
return true;
}
} catch (err) {
Logger.info(`Error on clearing Presentations Upload Token (${meetingId}, ${podId}). ${err}`);
return false;
}
}
if (meetingId) {
try {
const numberAffected = await PresentationUploadToken.removeAsync({ meetingId });
if (numberAffected) {
Logger.info(`Cleared Presentations Upload Token (${meetingId})`);
}
} catch (err) {
Logger.info(`Error on clearing Presentations Upload Token (${meetingId}). ${err}`);
}
} else {
try {
// clearing presentations for the whole server
const numberAffected = await PresentationUploadToken.removeAsync({});
if (numberAffected) {
Logger.info('Cleared Presentations Upload Token (all)');
}
} catch (err) {
Logger.info(`Error on clearing Presentations Upload Token (all). ${err}`);
}
}
}

View File

@ -1,40 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import PresentationUploadToken from '/imports/api/presentation-upload-token';
import Logger from '/imports/startup/server/logger';
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
async function presentationUploadToken(podId, filename, temporaryPresentationId) {
const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing PresentationUploadToken was requested by unauth connection ${this.connection.id}`);
return PresentationUploadToken.find({ meetingId: '' });
}
const { meetingId, userId } = tokenValidation;
check(podId, String);
check(filename, String);
check(temporaryPresentationId, String);
const selector = {
meetingId,
podId,
userId,
filename,
temporaryPresentationId,
};
Logger.debug('Publishing PresentationUploadToken', { meetingId, userId });
return PresentationUploadToken.find(selector);
}
function publish(...args) {
const boundPresentationUploadToken = presentationUploadToken.bind(this);
return boundPresentationUploadToken(...args);
}
Meteor.publish('presentation-upload-token', publish);

View File

@ -6,6 +6,7 @@ import { SubscriptionClient } from 'subscriptions-transport-ws';
import React, { useContext, useEffect } from 'react';
import { LoadingContext } from '/imports/ui/components/common/loading-screen/loading-screen-HOC/component';
import logger from '/imports/startup/client/logger';
import apolloContextHolder from '../../core/graphql/apolloContextHolder/apolloContextHolder';
interface ConnectionManagerProps {
children: React.ReactNode;
@ -115,6 +116,7 @@ const ConnectionManager: React.FC<ConnectionManagerProps> = ({ children }): Reac
connectToDevTools: true,
});
setApolloClient(client);
apolloContextHolder.setClient(client);
} catch (error) {
loadingContextInfo.setLoading(false, '');
throw new Error('Error creating Apollo Client: '.concat(JSON.stringify(error) || ''));

View File

@ -0,0 +1,15 @@
import { gql } from '@apollo/client';
export const requestPresentationUploadTokenMutation = gql`
mutation RequestPresentationUploadToken($podId: String!, $filename: String!, $uploadTemporaryId: String!) {
presentationRequestUploadToken(
podId: $podId,
filename: $filename,
uploadTemporaryId: $uploadTemporaryId,
)
}
`;
export default {
requestPresentationUploadTokenMutation,
};

View File

@ -0,0 +1,15 @@
import { gql } from '@apollo/client';
export const getPresentationUploadToken = gql`
query getPresentationUploadToken ($uploadTemporaryId: String!){
pres_presentation_uploadToken(where: {uploadTemporaryId: {_eq: $uploadTemporaryId}}) {
presentationId
uploadTemporaryId
uploadToken
}
}
`;
export default {
getPresentationUploadToken,
};

View File

@ -1,8 +1,5 @@
import { UploadingPresentations } from '/imports/api/presentations';
import PresentationUploadToken from '/imports/api/presentation-upload-token';
import Auth from '/imports/ui/services/auth';
import { Meteor } from 'meteor/meteor';
import { makeCall } from '/imports/ui/services/api';
import logger from '/imports/startup/client/logger';
import { partition } from '/imports/utils/array-utils';
import update from 'immutability-helper';
@ -11,8 +8,10 @@ import Meetings from '/imports/api/meetings';
import { uniqueId } from '/imports/utils/string-utils';
import { isPresentationEnabled } from '/imports/ui/services/features';
import { notify } from '/imports/ui/services/notification';
import apolloContextHolder from '/imports/ui/core/graphql/apolloContextHolder/apolloContextHolder';
import { getPresentationUploadToken } from './queries';
import { requestPresentationUploadTokenMutation } from './mutation';
const CONVERSION_TIMEOUT = 300000;
const TOKEN_TIMEOUT = 5000;
const PRESENTATION_CONFIG = window.meetingClientSettings.public.presentation;
@ -46,37 +45,41 @@ const requestPresentationUploadToken = (
meetingId,
filename,
) => new Promise((resolve, reject) => {
makeCall('requestPresentationUploadToken', POD_ID, filename, temporaryPresentationId);
const client = apolloContextHolder.getClient();
client.mutate({
mutation: requestPresentationUploadTokenMutation,
variables: {
podId: POD_ID,
filename,
uploadTemporaryId: temporaryPresentationId,
},
});
let computation = null;
const timeout = setTimeout(() => {
computation.stop();
reject(new Error({ code: 408, message: 'requestPresentationUploadToken timeout' }));
}, TOKEN_TIMEOUT);
Tracker.autorun((c) => {
computation = c;
const sub = Meteor.subscribe('presentation-upload-token', POD_ID, filename, temporaryPresentationId);
if (!sub.ready()) return;
const PresentationToken = PresentationUploadToken.findOne({
podId: POD_ID,
meetingId,
temporaryPresentationId,
used: false,
const getData = (n = 0) => {
if (n > 10) return;
let recursiveTimeout = null;
client.query({
query: getPresentationUploadToken,
variables: {
uploadTemporaryId: temporaryPresentationId,
},
fetchPolicy: 'network-only',
}).then((result) => {
if (result.data.pres_presentation_uploadToken.length > 0) {
clearTimeout(recursiveTimeout);
clearTimeout(timeout);
resolve(result.data.pres_presentation_uploadToken[0].uploadToken);
}
});
if (!PresentationToken || !('failed' in PresentationToken)) return;
if (!PresentationToken.failed) {
clearTimeout(timeout);
resolve(PresentationToken.authzToken);
}
if (PresentationToken.failed) {
reject(new Error({ code: 401, message: `requestPresentationUploadToken token ${PresentationToken.authzToken} failed` }));
}
});
recursiveTimeout = setTimeout(() => {
getData(n + 1);
}, 1000);
};
setTimeout(getData, 100);
});
const uploadAndConvertPresentation = (
@ -131,7 +134,6 @@ const uploadAndConvertPresentation = (
return requestPresentationUploadToken(temporaryPresentationId, meetingId, file.name)
.then((token) => {
makeCall('setUsedToken', token);
UploadingPresentations.upsert({
temporaryPresentationId,
}, {

View File

@ -0,0 +1,18 @@
import { ApolloClient, NormalizedCacheObject } from '@apollo/client';
class ApolloContextHolder {
private client: ApolloClient<NormalizedCacheObject> | null = null;
public setClient(client: ApolloClient<NormalizedCacheObject>): void {
this.client = client;
}
public getClient(): ApolloClient<NormalizedCacheObject> {
if (!this.client) {
throw new Error('ApolloClient has not been initialized yet');
}
return this.client;
}
}
export default new ApolloContextHolder();

View File

@ -3,7 +3,6 @@ import '/imports/startup/server';
// 2x
import '/imports/api/meetings/server';
import '/imports/api/users/server';
import '/imports/api/presentation-upload-token/server';
import '/imports/api/breakouts/server';
import '/imports/api/screenshare/server';
import '/imports/api/users-settings/server';