Use collab server for image storage as well

This commit is contained in:
Tims777 2024-09-28 13:31:17 +02:00
parent a7c8fab8c9
commit e405ddcbda
3 changed files with 18 additions and 91 deletions

View File

@ -29,8 +29,8 @@ export enum WS_SUBTYPES {
} }
export const FIREBASE_STORAGE_PREFIXES = { export const FIREBASE_STORAGE_PREFIXES = {
shareLinkFiles: `/files/shareLinks`, shareLinkFiles: `shareLinks`,
collabFiles: `/files/rooms`, collabFiles: `rooms`,
}; };
export const ROOM_ID_BYTES = 10; export const ROOM_ID_BYTES = 10;

View File

@ -29,7 +29,6 @@ import {
import { import {
CURSOR_SYNC_TIMEOUT, CURSOR_SYNC_TIMEOUT,
FILE_UPLOAD_MAX_BYTES, FILE_UPLOAD_MAX_BYTES,
FIREBASE_STORAGE_PREFIXES,
INITIAL_SCENE_UPDATE_TIMEOUT, INITIAL_SCENE_UPDATE_TIMEOUT,
LOAD_IMAGES_TIMEOUT, LOAD_IMAGES_TIMEOUT,
WS_SUBTYPES, WS_SUBTYPES,
@ -149,7 +148,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
throw new AbortError(); throw new AbortError();
} }
return loadFilesFromFirebase(`files/rooms/${roomId}`, roomKey, fileIds); return loadFilesFromFirebase(roomId, roomKey, fileIds);
}, },
saveFiles: async ({ addedFiles }) => { saveFiles: async ({ addedFiles }) => {
const { roomId, roomKey } = this.portal; const { roomId, roomKey } = this.portal;
@ -158,7 +157,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
} }
return saveFilesToFirebase({ return saveFilesToFirebase({
prefix: `${FIREBASE_STORAGE_PREFIXES.collabFiles}/${roomId}`, prefix: roomId,
files: await encodeFilesForUpload({ files: await encodeFilesForUpload({
files: addedFiles, files: addedFiles,
encryptionKey: roomKey, encryptionKey: roomKey,

View File

@ -13,7 +13,6 @@ import type {
BinaryFileMetadata, BinaryFileMetadata,
DataURL, DataURL,
} from "../../packages/excalidraw/types"; } from "../../packages/excalidraw/types";
import { FILE_CACHE_MAX_AGE_SEC } from "../app_constants";
import { decompressData } from "../../packages/excalidraw/data/encode"; import { decompressData } from "../../packages/excalidraw/data/encode";
import { import {
encryptData, encryptData,
@ -31,72 +30,8 @@ import type { RemoteExcalidrawElement } from "../../packages/excalidraw/data/rec
const STORAGE_SERVER_URL = import.meta.env.VITE_APP_WS_SERVER_URL; const STORAGE_SERVER_URL = import.meta.env.VITE_APP_WS_SERVER_URL;
let FIREBASE_CONFIG: Record<string, any>;
try {
FIREBASE_CONFIG = JSON.parse(import.meta.env.VITE_APP_FIREBASE_CONFIG);
} catch (error: any) {
console.warn(
`Error JSON parsing firebase config. Supplied value: ${
import.meta.env.VITE_APP_FIREBASE_CONFIG
}`,
);
FIREBASE_CONFIG = {};
}
let firebasePromise: Promise<typeof import("firebase/app").default> | null =
null;
let firebaseStoragePromise: Promise<any> | null | true = null;
let isFirebaseInitialized = false;
const _loadFirebase = async () => {
const firebase = (
await import(/* webpackChunkName: "firebase" */ "firebase/app")
).default;
if (!isFirebaseInitialized) {
try {
firebase.initializeApp(FIREBASE_CONFIG);
} catch (error: any) {
// trying initialize again throws. Usually this is harmless, and happens
// mainly in dev (HMR)
if (error.code === "app/duplicate-app") {
console.warn(error.name, error.code);
} else {
throw error;
}
}
isFirebaseInitialized = true;
}
return firebase;
};
const _getFirebase = async (): Promise<
typeof import("firebase/app").default
> => {
if (!firebasePromise) {
firebasePromise = _loadFirebase();
}
return firebasePromise;
};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
export const loadFirebaseStorage = async () => {
const firebase = await _getFirebase();
if (!firebaseStoragePromise) {
firebaseStoragePromise = import(
/* webpackChunkName: "storage" */ "firebase/storage"
);
}
if (firebaseStoragePromise !== true) {
await firebaseStoragePromise;
firebaseStoragePromise = true;
}
return firebase;
};
interface StoredScene { interface StoredScene {
sceneVersion: number; sceneVersion: number;
iv: ArrayBuffer; iv: ArrayBuffer;
@ -162,25 +97,21 @@ export const saveFilesToFirebase = async ({
prefix: string; prefix: string;
files: { id: FileId; buffer: Uint8Array }[]; files: { id: FileId; buffer: Uint8Array }[];
}) => { }) => {
const firebase = await loadFirebaseStorage();
const erroredFiles = new Map<FileId, true>(); const erroredFiles = new Map<FileId, true>();
const savedFiles = new Map<FileId, true>(); const savedFiles = new Map<FileId, true>();
await Promise.all( await Promise.all(
files.map(async ({ id, buffer }) => { files.map(async ({ id, buffer }) => {
try { try {
await firebase await fetch(`${STORAGE_SERVER_URL}/file/${prefix}/${id}`, {
.storage() method: "PUT",
.ref(`${prefix}/${id}`) headers: {
.put( ETag: id,
new Blob([buffer], { // "If-Match": id,
type: MIME_TYPES.binary, "Content-Type": MIME_TYPES.binary,
}),
{
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
}, },
); body: buffer,
});
savedFiles.set(id, true); savedFiles.set(id, true);
} catch (error: any) { } catch (error: any) {
erroredFiles.set(id, true); erroredFiles.set(id, true);
@ -248,7 +179,7 @@ export const saveToFirebase = async (
headers: { headers: {
ETag: storedScene.sceneVersion.toString(), ETag: storedScene.sceneVersion.toString(),
"If-Match": prevHash.toString(), "If-Match": prevHash.toString(),
"Content-Type": "application/octet-stream", "Content-Type": MIME_TYPES.binary,
}, },
body, body,
}); });
@ -268,9 +199,7 @@ export const loadFromFirebase = async (
roomKey: string, roomKey: string,
socket: Socket | null, socket: Socket | null,
): Promise<SyncableExcalidrawElement[] | null> => { ): Promise<SyncableExcalidrawElement[] | null> => {
const resp = await fetch(`${STORAGE_SERVER_URL}/scene/${roomId}`, { const resp = await fetch(`${STORAGE_SERVER_URL}/scene/${roomId}`);
method: "GET",
});
if (resp.status === 404) { if (resp.status === 404) {
return null; return null;
@ -305,10 +234,9 @@ export const loadFilesFromFirebase = async (
await Promise.all( await Promise.all(
[...new Set(filesIds)].map(async (id) => { [...new Set(filesIds)].map(async (id) => {
try { try {
const url = `https://firebasestorage.googleapis.com/v0/b/${ const response = await fetch(
FIREBASE_CONFIG.storageBucket `${STORAGE_SERVER_URL}/file/${prefix}/${id}`,
}/o/${encodeURIComponent(prefix.replace(/^\//, ""))}%2F${id}`; );
const response = await fetch(`${url}?alt=media`);
if (response.status < 400) { if (response.status < 400) {
const arrayBuffer = await response.arrayBuffer(); const arrayBuffer = await response.arrayBuffer();