You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
2.3 KiB
JavaScript

const router = require('express-promise-router')()
const db = require('../db')
const ensureAdmin = require('./middleware/ensureAdmin')
const fs = require('fs');
const path = require('path');
const cacheRoot = path.join(__dirname, '../cache/images')
fs.promises.mkdir(cacheRoot, {recursive: true})
.catch(() => console.error("Could not create image cache dir: " + cacheRoot));
const memCache = {};
async function writeImageFile(uuid, size, data) {
if(size !== 'thumb' && size !== 'large')
throw new Error(`Unknown image size ${size}`);
await fs.promises.writeFile(path.join(cacheRoot, `${uuid}-${size}`), data);
}
async function getImage(uuid, size) {
// If we've already stored a mime type, that means we've written the file to disk
if(memCache[`${uuid}-${size}`]?.mime_type) {
return {
file: fs.createReadStream(path.join(cacheRoot, `${uuid}-${size}`)),
mime_type: memCache[`${uuid}-${size}`].mime_type
}
}
// If we've stored a promise, that means we're currently retrieving it from the db
if(memCache[`${uuid}-${size}`]?.dbPromise) {
return await memCache[`${uuid}-${size}`]?.dbPromise;
}
// Otherwise, retrieve it from the DB, and then write it to disk
const record = memCache[`${uuid}-${size}`] = {};
record.dbPromise = db.item.getImage(uuid, size);
const image = await record.dbPromise;
await writeImageFile(uuid, size, image.file);
record.mime_type = image.mime_type;
delete record.dbPromise;
return image;
}
router.get('/:uuid/:size', async (req, res) => {
if(req.params.size.includes('.')) {
req.params.size = req.params.size.split('.')[0];
}
const image = await getImage(req.params.uuid, req.params.size)
const cacheSeconds = 60 * 60 * 24;
res.set('Cache-Control', cacheSeconds);
res.set('Content-Type', image.mime_type)
if(Buffer.isBuffer(image.file))
res.end(image.file)
else if (typeof image.file.pipe === 'function')
image.file.pipe(res)
else
throw new Error("Unable to send file to user");
})
router.post('/:uuid/featured', ensureAdmin, async (req, res) => {
const item = await db.item.setFeatured(req.params.uuid)
res.json(item)
})
router.delete('/:uuid', ensureAdmin, async (req, res) => {
const item = await db.item.removeImage(req.params.uuid)
res.json(item)
})
module.exports = router