Files
Verso/services/web/app/src/Features/FileStore/FileStoreHandler.mjs
T
Copilot 55c3b6b7ea Replace promisifyAll with individual promisify calls in web service (#30931)
* Initial plan

* Replace promisifyAll with individual promisify calls in all 8 files

Co-authored-by: Seinzu <194547+Seinzu@users.noreply.github.com>

* Remove unused promisify imports from V1Api and FileStoreHandler

Co-authored-by: Seinzu <194547+Seinzu@users.noreply.github.com>

* Fix formatting and remove unnecessary .bind() calls

Co-authored-by: Seinzu <194547+Seinzu@users.noreply.github.com>

* Fix formatting: collapse multi-line promisify calls to single lines

Co-authored-by: Seinzu <194547+Seinzu@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Seinzu <194547+Seinzu@users.noreply.github.com>
GitOrigin-RevId: c16a3f3ea48c93c2f62ad32c1f4512cd237882bf
2026-02-12 09:05:28 +00:00

130 lines
3.7 KiB
JavaScript

import logger from '@overleaf/logger'
import fs from 'node:fs'
import Async from 'async'
import FileHashManager from './FileHashManager.mjs'
import HistoryManager from '../History/HistoryManager.mjs'
import ProjectDetailsHandler from '../Project/ProjectDetailsHandler.mjs'
import { File } from '../../models/File.mjs'
import OError from '@overleaf/o-error'
import { promisifyMultiResult } from '@overleaf/promise-utils'
import Modules from '../../infrastructure/Modules.mjs'
const FileStoreHandler = {
RETRY_ATTEMPTS: 3,
uploadFileFromDisk(projectId, fileArgs, fsPath, callback) {
// Look up the history id for the project if we don't have it already
ProjectDetailsHandler.getDetails(projectId, function (err, project) {
if (err) {
return callback(err)
}
const historyId = project.overleaf?.history?.id
if (!historyId) {
return callback(new OError('missing history id'))
}
FileStoreHandler.uploadFileFromDiskWithHistoryId(
projectId,
historyId,
fileArgs,
fsPath,
callback
)
})
},
_uploadToHistory(historyId, hash, size, fsPath, callback) {
Async.retry(
FileStoreHandler.RETRY_ATTEMPTS,
cb =>
HistoryManager.uploadBlobFromDisk(historyId, hash, size, fsPath, cb),
error => {
if (error) return callback(error, false)
callback(null, true)
}
)
},
uploadFileFromDiskWithHistoryId(
projectId,
historyId,
fileArgs,
fsPath,
callback
) {
fs.lstat(fsPath, function (err, stat) {
if (err) {
logger.warn({ err, projectId, fileArgs, fsPath }, 'error stating file')
callback(err)
}
if (!stat) {
logger.warn(
{ projectId, fileArgs, fsPath },
'stat is not available, can not check file from disk'
)
return callback(new Error('error getting stat, not available'))
}
if (!stat.isFile()) {
logger.debug(
{ projectId, fileArgs, fsPath },
'tried to upload symlink, not continuing'
)
return callback(new Error('can not upload symlink'))
}
const size = stat.size
Modules.hooks.fire(
'preUploadFile',
{ projectId, historyId, fileArgs, fsPath, size },
preUploadErr => {
if (preUploadErr) {
return callback(preUploadErr)
}
FileHashManager.computeHash(fsPath, function (err, hash) {
if (err) {
return callback(err)
}
FileStoreHandler._uploadToHistory(
historyId,
hash,
stat.size,
fsPath,
function (err) {
if (err) {
return callback(err)
}
const fileRef = new File({ ...fileArgs, hash })
Modules.hooks.fire(
'postUploadFile',
{
projectId,
fileRef,
size,
},
postUploadErr => {
if (postUploadErr) {
return callback(postUploadErr)
}
callback(err, fileRef, true, size)
}
)
}
)
})
}
)
})
},
}
FileStoreHandler.promises = {
uploadFileFromDisk: promisifyMultiResult(
FileStoreHandler.uploadFileFromDisk,
['fileRef', 'createdBlob', 'size']
),
uploadFileFromDiskWithHistoryId: promisifyMultiResult(
FileStoreHandler.uploadFileFromDiskWithHistoryId,
['fileRef', 'createdBlob', 'size']
),
}
export default FileStoreHandler