Use collab server for image storage as well
This commit is contained in:
parent
a7c8fab8c9
commit
e405ddcbda
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
}),
|
},
|
||||||
{
|
body: buffer,
|
||||||
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
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();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user