diff --git a/config.sample.js b/config.sample.js index 375404b..48de3d3 100644 --- a/config.sample.js +++ b/config.sample.js @@ -415,6 +415,20 @@ module.exports = { */ cacheFileIdentifiers: true, + /* + An alternative to caching file identifiers. + + Basically the service will instead query the database for stricter collision checks. + Right off the bat this has the disadvantage of adding one or more SQL queries on every + new uploads, but it has the advantage of not having to pre-cache anything. + Essentially this reduces the service's startup time and memory usage, but slows down new uploads. + + As this is an alternative, you need to disable cacheFileIdentifiers to use this. + + You'll have to figure out which method suits your use case best. + */ + queryDbForFileCollisions: true, + /* The length of the randomly generated identifier for albums. */ diff --git a/controllers/uploadController.js b/controllers/uploadController.js index ef8ebfb..c50e745 100644 --- a/controllers/uploadController.js +++ b/controllers/uploadController.js @@ -13,7 +13,9 @@ const config = require('./../config') const logger = require('./../logger') const db = require('knex')(config.database) -const self = {} +const self = { + onHold: new Set() +} const fileIdentifierLengthFallback = 32 const fileIdentifierLengthChangeable = !config.uploads.fileIdentifierLength.force && @@ -191,6 +193,22 @@ self.getUniqueRandomName = async (length, extension) => { } utils.idSet.add(identifier) // logger.log(`Added ${identifier} to identifiers cache`) + } else if (config.uploads.queryDbForFileCollisions) { + if (self.onHold.has(identifier)) + continue + + // Put token on-hold (wait for it to be inserted to DB) + self.onHold.add(identifier) + + const file = await db.table('files') + .where('name', 'like', 'identifier.%') + .select('id') + .first() + if (file) { + self.onHold.delete(identifier) + logger.log(`Identifier ${identifier} is already in use (${i + 1}/${utils.idMaxTries}).`) + continue + } } else { try { await paths.access(path.join(paths.uploads, name)) @@ -721,6 +739,13 @@ self.storeFilesToDb = async (req, res, user, infoMap) => { await db.table('files').insert(files) utils.invalidateStatsCache('uploads') + if (config.uploads.queryDbForFileCollisions) + for (const file of files) { + const extname = utils.extname(file.name) + const identifier = file.name.slice(0, -(extname.length)) + self.onHold.delete(identifier) + } + // Update albums' timestamp if (authorizedIds.length) { await db.table('albums')