salix/back/methods/image/scrub.js

138 lines
4.6 KiB
JavaScript

const fs = require('fs-extra');
const path = require('path');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('scrub', {
description: 'Deletes images without database reference',
accessType: 'WRITE',
accepts: [
{
arg: 'collection',
type: 'string',
description: 'The collection name',
required: true
}, {
arg: 'remove',
type: 'boolean',
description: 'Delete instead of move images to trash'
}, {
arg: 'limit',
type: 'integer',
description: 'Maximum number of images to clean'
}, {
arg: 'dryRun',
type: 'boolean',
description: 'Simulate actions'
}
],
returns: {
type: 'integer',
root: true
},
http: {
path: `/scrub`,
verb: 'POST'
}
});
Self.scrub = async function(collection, remove, limit, dryRun) {
const $ = Self.app.models;
const env = process.env.NODE_ENV;
dryRun = dryRun || (env && env !== 'production');
const instance = await $.ImageCollection.findOne({
fields: ['id'],
where: {name: collection}
});
if (!instance)
throw new UserError('Collection does not exist');
const container = await $.ImageContainer.container(collection);
const rootPath = container.client.root;
const conn = await getConnection();
const lockName = 'salix.Image.scrub';
let lockObtained;
try {
const [row] = await query(conn,
`SELECT GET_LOCK(?, 0) hasLock`,
[lockName]
);
lockObtained = !!row.hasLock;
if (!lockObtained)
throw new UserError('Cannot obtain exclusive lock');
const now = Date.vnNew().toJSON();
const scrubDir = path.join(rootPath, '.scrub', now);
const collectionDir = path.join(rootPath, collection);
const sizes = await fs.readdir(collectionDir);
let cleanCount = 0;
mainLoop: for (const size of sizes) {
const sizeDir = path.join(collectionDir, size);
const scrubSizeDir = path.join(scrubDir, collection, size);
const images = await fs.readdir(sizeDir);
for (const image of images) {
const imageName = path.parse(image).name;
const count = await Self.count({
collectionFk: collection,
name: imageName
});
const exists = count > 0;
let scrubDirCreated = false;
if (!exists) {
const srcFile = path.join(sizeDir, image);
if (remove !== true) {
if (!scrubDirCreated) {
if (!dryRun)
await fs.mkdir(scrubSizeDir, {recursive: true});
scrubDirCreated = true;
}
const dstFile = path.join(scrubSizeDir, image);
if (!dryRun)
await fs.rename(srcFile, dstFile);
} else {
if (!dryRun)
await fs.unlink(srcFile);
}
cleanCount++;
if (limit && cleanCount == limit)
break mainLoop;
}
}
}
return cleanCount;
} finally {
if (lockObtained)
await query(conn, `DO RELEASE_LOCK(?)`, [lockName]);
conn.release();
}
// Promisified datasource functions
function getConnection() {
return new Promise((resolve, reject) => {
Self.dataSource.connector.client.getConnection((err, conn) => {
if (err) return reject(err);
resolve(conn);
});
});
}
function query(conn, sql, params) {
return new Promise((resolve, reject) => {
conn.query(sql, params, (err, res) => {
if (err) return reject(err);
resolve(res);
});
});
}
};
};