From a7136f321e2a697f735ce205941556bac5411da9 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween <5454374+emcsween@users.noreply.github.com> Date: Fri, 26 Sep 2025 11:10:36 -0400 Subject: [PATCH] Merge pull request #28656 from overleaf/em-restore-optimize-file-download File restore: optimize file download from history GitOrigin-RevId: c32afe7d2ede2372e95490f62e79266f5f6d58da --- .../src/Features/History/RestoreManager.mjs | 24 +++++++++++++++---- .../unit/src/History/RestoreManager.test.mjs | 15 ++++++++---- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/services/web/app/src/Features/History/RestoreManager.mjs b/services/web/app/src/Features/History/RestoreManager.mjs index 7153b13263..cda61dd9e0 100644 --- a/services/web/app/src/Features/History/RestoreManager.mjs +++ b/services/web/app/src/Features/History/RestoreManager.mjs @@ -114,6 +114,7 @@ const RestoreManager = { if (!project?.overleaf?.history?.rangesSupportEnabled) { throw new OError('project does not have ranges support', { projectId }) } + const historyId = project.overleaf.history.id const basename = Path.basename(pathname) let dirname = Path.dirname(pathname) @@ -179,10 +180,9 @@ const RestoreManager = { filename: pathname, }) ) { - const fsPath = await RestoreManager._writeFileVersionToDisk( - projectId, - version, - pathname + const fsPath = await RestoreManager._writeSnapshotFileToDisk( + historyId, + snapshotFile ) const newFile = await EditorController.promises.upsertFile( projectId, @@ -426,6 +426,22 @@ const RestoreManager = { }/project/${projectId}/version/${version}/${encodeURIComponent(pathname)}` return await FileWriter.promises.writeUrlToDisk(projectId, url) }, + + async _writeSnapshotFileToDisk(historyId, file) { + if (file.isEditable()) { + return await FileWriter.promises.writeContentToDisk( + historyId, + file.getContent() + ) + } else { + const hash = file.getHash() + const { stream } = await HistoryManager.promises.requestBlob( + historyId, + hash + ) + return await FileWriter.promises.writeStreamToDisk(historyId, stream) + } + }, } export default { ...callbackifyAll(RestoreManager), promises: RestoreManager } diff --git a/services/web/test/unit/src/History/RestoreManager.test.mjs b/services/web/test/unit/src/History/RestoreManager.test.mjs index 43b9057e5c..4aeb1baf0a 100644 --- a/services/web/test/unit/src/History/RestoreManager.test.mjs +++ b/services/web/test/unit/src/History/RestoreManager.test.mjs @@ -16,6 +16,9 @@ describe('RestoreManager', function () { beforeEach(async function (ctx) { tk.freeze(Date.now()) // freeze the time for these tests + ctx.fsPath = '/tmp/path/on/disk' + ctx.blobStream = 'blob-stream' + vi.doMock('../../../../app/src/Features/Errors/Errors.js', () => ({ default: Errors, })) @@ -71,6 +74,7 @@ describe('RestoreManager', function () { }, timestamp: new Date().toISOString(), }), + requestBlob: sinon.stub().resolves({ stream: ctx.blobStream }), }, }), })) @@ -91,7 +95,12 @@ describe('RestoreManager', function () { })) vi.doMock('../../../../app/src/infrastructure/FileWriter', () => ({ - default: (ctx.FileWriter = { promises: {} }), + default: (ctx.FileWriter = { + promises: { + writeStreamToDisk: sinon.stub().resolves(ctx.fsPath), + writeContentToDisk: sinon.stub().resolves(ctx.fsPath), + }, + }), })) vi.doMock( @@ -167,6 +176,7 @@ describe('RestoreManager', function () { getMetadata: sinon .stub() .returns(snapshotData?.files?.[pathname]?.metadata), + getHash: sinon.stub().returns((ctx.hash = 'somehash')), }), getFilePathnames: sinon .stub() @@ -380,9 +390,6 @@ describe('RestoreManager', function () { overleaf: { history: { rangesSupportEnabled: true } }, rootDoc_id: 'root-doc-id', }) - ctx.RestoreManager.promises._writeFileVersionToDisk = sinon - .stub() - .resolves((ctx.fsPath = '/tmp/path/on/disk')) ctx.RestoreManager.promises._findOrCreateFolder = sinon .stub() .resolves((ctx.folder_id = 'mock-folder-id'))