feat: clean unused images only after 24hrs (local-only) (#5839)
* feat: clean unused images only after 24hrs (local-only) * fix test * make optional for now
This commit is contained in:
parent
938ce241ff
commit
b91158198e
@ -5243,6 +5243,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
id: fileId,
|
id: fileId,
|
||||||
dataURL,
|
dataURL,
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
lastRetrieved: Date.now(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const cachedImageData = this.imageCache.get(fileId);
|
const cachedImageData = this.imageCache.get(fileId);
|
||||||
|
@ -195,6 +195,7 @@ export const encodeFilesForUpload = async ({
|
|||||||
id,
|
id,
|
||||||
mimeType: fileData.mimeType,
|
mimeType: fileData.mimeType,
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
lastRetrieved: Date.now(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* (localStorage, indexedDB).
|
* (localStorage, indexedDB).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createStore, keys, del, getMany, set } from "idb-keyval";
|
import { createStore, entries, del, getMany, set, setMany } from "idb-keyval";
|
||||||
import { clearAppStateForLocalStorage } from "../../appState";
|
import { clearAppStateForLocalStorage } from "../../appState";
|
||||||
import { clearElementsForLocalStorage } from "../../element";
|
import { clearElementsForLocalStorage } from "../../element";
|
||||||
import { ExcalidrawElement, FileId } from "../../element/types";
|
import { ExcalidrawElement, FileId } from "../../element/types";
|
||||||
@ -25,12 +25,21 @@ const filesStore = createStore("files-db", "files-store");
|
|||||||
|
|
||||||
class LocalFileManager extends FileManager {
|
class LocalFileManager extends FileManager {
|
||||||
clearObsoleteFiles = async (opts: { currentFileIds: FileId[] }) => {
|
clearObsoleteFiles = async (opts: { currentFileIds: FileId[] }) => {
|
||||||
const allIds = await keys(filesStore);
|
await entries(filesStore).then((entries) => {
|
||||||
for (const id of allIds) {
|
for (const [id, imageData] of entries as [FileId, BinaryFileData][]) {
|
||||||
if (!opts.currentFileIds.includes(id as FileId)) {
|
// if image is unused (not on canvas) & is older than 1 day, delete it
|
||||||
|
// from storage. We check `lastRetrieved` we care about the last time
|
||||||
|
// the image was used (loaded on canvas), not when it was initially
|
||||||
|
// created.
|
||||||
|
if (
|
||||||
|
(!imageData.lastRetrieved ||
|
||||||
|
Date.now() - imageData.lastRetrieved > 24 * 3600 * 1000) &&
|
||||||
|
!opts.currentFileIds.includes(id as FileId)
|
||||||
|
) {
|
||||||
del(id, filesStore);
|
del(id, filesStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,18 +120,33 @@ export class LocalData {
|
|||||||
static fileStorage = new LocalFileManager({
|
static fileStorage = new LocalFileManager({
|
||||||
getFiles(ids) {
|
getFiles(ids) {
|
||||||
return getMany(ids, filesStore).then(
|
return getMany(ids, filesStore).then(
|
||||||
(filesData: (BinaryFileData | undefined)[]) => {
|
async (filesData: (BinaryFileData | undefined)[]) => {
|
||||||
const loadedFiles: BinaryFileData[] = [];
|
const loadedFiles: BinaryFileData[] = [];
|
||||||
const erroredFiles = new Map<FileId, true>();
|
const erroredFiles = new Map<FileId, true>();
|
||||||
|
|
||||||
|
const filesToSave: [FileId, BinaryFileData][] = [];
|
||||||
|
|
||||||
filesData.forEach((data, index) => {
|
filesData.forEach((data, index) => {
|
||||||
const id = ids[index];
|
const id = ids[index];
|
||||||
if (data) {
|
if (data) {
|
||||||
loadedFiles.push(data);
|
const _data: BinaryFileData = {
|
||||||
|
...data,
|
||||||
|
lastRetrieved: Date.now(),
|
||||||
|
};
|
||||||
|
filesToSave.push([id, _data]);
|
||||||
|
loadedFiles.push(_data);
|
||||||
} else {
|
} else {
|
||||||
erroredFiles.set(id, true);
|
erroredFiles.set(id, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// save loaded files back to storage with updated `lastRetrieved`
|
||||||
|
setMany(filesToSave, filesStore);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
}
|
||||||
|
|
||||||
return { loadedFiles, erroredFiles };
|
return { loadedFiles, erroredFiles };
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -330,6 +330,7 @@ export const loadFilesFromFirebase = async (
|
|||||||
id,
|
id,
|
||||||
dataURL,
|
dataURL,
|
||||||
created: metadata?.created || Date.now(),
|
created: metadata?.created || Date.now(),
|
||||||
|
lastRetrieved: metadata?.created || Date.now(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
erroredFiles.set(id, true);
|
erroredFiles.set(id, true);
|
||||||
|
@ -148,6 +148,7 @@ export default function App() {
|
|||||||
dataURL: reader.result as BinaryFileData["dataURL"],
|
dataURL: reader.result as BinaryFileData["dataURL"],
|
||||||
mimeType: MIME_TYPES.jpg,
|
mimeType: MIME_TYPES.jpg,
|
||||||
created: 1644915140367,
|
created: 1644915140367,
|
||||||
|
lastRetrieved: 1644915140367,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ describe("export", () => {
|
|||||||
dataURL: await getDataURL(await API.loadFile("./fixtures/deer.png")),
|
dataURL: await getDataURL(await API.loadFile("./fixtures/deer.png")),
|
||||||
mimeType: "image/png",
|
mimeType: "image/png",
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
|
lastRetrieved: Date.now(),
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
11
src/types.ts
11
src/types.ts
@ -61,7 +61,18 @@ export type BinaryFileData = {
|
|||||||
| typeof MIME_TYPES.binary;
|
| typeof MIME_TYPES.binary;
|
||||||
id: FileId;
|
id: FileId;
|
||||||
dataURL: DataURL;
|
dataURL: DataURL;
|
||||||
|
/**
|
||||||
|
* Epoch timestamp in milliseconds
|
||||||
|
*/
|
||||||
created: number;
|
created: number;
|
||||||
|
/**
|
||||||
|
* Indicates when the file was last retrieved from storage to be loaded
|
||||||
|
* onto the scene. We use this flag to determine whether to delete unused
|
||||||
|
* files from storage.
|
||||||
|
*
|
||||||
|
* Epoch timestamp in milliseconds.
|
||||||
|
*/
|
||||||
|
lastRetrieved?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BinaryFileMetadata = Omit<BinaryFileData, "dataURL">;
|
export type BinaryFileMetadata = Omit<BinaryFileData, "dataURL">;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user