mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-09 14:42:32 +00:00
Rework sync so uploading multiple files at once or several moderators uploading files simultaneously doesn't break synchronization. The current room metadata plugin operates on <key,value> pairs and we were using a generic "files" key and using a nested object as our value. Since with every operation the entire object is replaced it's easy to get out of sync because one needs to be sure to have the full state before overwriting it. This is not realistic. We'll look into making the metadata plugin more flexible in order to support add / delete operations also on nested objects, but for the time being the following will suffice: Use a key prefix, so each file has en entry in the room metadata, like so: "files.<the file ID> -> file metadata". This means that when a file is deleted we just empty the metadata. The metadata plugin doesn't currently support removing existing keys.
97 lines
2.3 KiB
TypeScript
97 lines
2.3 KiB
TypeScript
import { isEqual } from 'lodash-es';
|
|
|
|
import { UPDATE_CONFERENCE_METADATA } from '../base/conference/actionTypes';
|
|
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
|
import {
|
|
ADD_FILE,
|
|
REMOVE_FILE,
|
|
UPDATE_FILE_UPLOAD_PROGRESS
|
|
} from './actionTypes';
|
|
import { FILE_SHARING_PREFIX } from './constants';
|
|
import { IFileMetadata } from './types';
|
|
|
|
export interface IFileSharingState {
|
|
files: Map<string, IFileMetadata>;
|
|
}
|
|
|
|
const DEFAULT_STATE = {
|
|
files: new Map<string, IFileMetadata>()
|
|
};
|
|
|
|
ReducerRegistry.register<IFileSharingState>('features/file-sharing',
|
|
(state = DEFAULT_STATE, action): IFileSharingState => {
|
|
switch (action.type) {
|
|
case ADD_FILE: {
|
|
const newFiles = new Map(state.files);
|
|
|
|
newFiles.set(action.file.fileId, action.file);
|
|
|
|
return {
|
|
files: newFiles
|
|
};
|
|
}
|
|
|
|
case REMOVE_FILE: {
|
|
const newFiles = new Map(state.files);
|
|
|
|
newFiles.delete(action.fileId);
|
|
|
|
return {
|
|
files: newFiles
|
|
};
|
|
}
|
|
|
|
case UPDATE_FILE_UPLOAD_PROGRESS: {
|
|
const newFiles = new Map(state.files);
|
|
const file = newFiles.get(action.fileId);
|
|
|
|
if (file) {
|
|
newFiles.set(action.fileId, { ...file, progress: action.progress });
|
|
}
|
|
|
|
return {
|
|
files: newFiles
|
|
};
|
|
}
|
|
|
|
case UPDATE_CONFERENCE_METADATA: {
|
|
const { metadata } = action;
|
|
const files = new Map();
|
|
|
|
for (const [ key, value ] of Object.entries(metadata)) {
|
|
if (key.startsWith(FILE_SHARING_PREFIX)) {
|
|
const fileId = key.substring(FILE_SHARING_PREFIX.length + 1);
|
|
|
|
files.set(fileId, value);
|
|
}
|
|
}
|
|
|
|
if (files.size === 0) {
|
|
return state;
|
|
}
|
|
|
|
const newFiles: Map<string, IFileMetadata> = new Map(state.files);
|
|
|
|
for (const [ key, value ] of files) {
|
|
// Deleted files will not have fileId.
|
|
if (!value.fileId) {
|
|
newFiles.delete(key);
|
|
} else {
|
|
newFiles.set(key, value);
|
|
}
|
|
}
|
|
|
|
if (isEqual(newFiles, state.files)) {
|
|
return state;
|
|
}
|
|
|
|
return {
|
|
files: newFiles
|
|
};
|
|
}
|
|
|
|
default:
|
|
return state;
|
|
}
|
|
});
|