* Added Cloudflare purge cache support. Check configuration sample at config.sample.js.
When it's enabled, whenever files are being deleted, it will send a POST request to Cloudflare's API to purge cache of the deleted files.
This adds a new dependency called "snekfetch". It's lightweight though.

* uploadsController.delete() will now wrap uploadsController.bulkDelete() instead.
This commit is contained in:
Bobby Wibowo 2018-05-09 16:53:27 +07:00
parent 7991a63315
commit f043f65ca1
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
6 changed files with 56 additions and 36 deletions

View File

@ -153,7 +153,17 @@ module.exports = {
Cloudflare will not cache files bigger than 512MB.
NOTE: Set to falsy value (false, null, etc.) to disable.
*/
zipMaxTotalSize: '512MB'
zipMaxTotalSize: '512MB',
/*
If you want to make it automatically calls Cloudflare's API to purge cache on file delete,
fill your api key, email and your site's zone id below, then set "purgeCache" to true.
This will only purge cache of the deleted file and its associated thumb.
*/
apiKey: '',
email: '',
zoneId: '',
purgeCache: false
},
/*

View File

@ -22,9 +22,7 @@ class ZipEmitter extends EventEmitter {
constructor (identifier) {
super()
this.identifier = identifier
this.once('done', () => {
albumsController.zipEmitters.delete(this.identifier)
})
this.once('done', () => albumsController.zipEmitters.delete(this.identifier))
}
}

View File

@ -448,38 +448,10 @@ uploadsController.processFilesForDisplay = async (req, res, files, existingFiles
}
uploadsController.delete = async (req, res) => {
// TODO: Wrap utils.bulkDeleteFiles() instead
const user = await utils.authorize(req, res)
if (!user) { return }
const id = req.body.id
if (id === undefined || id === '') {
return res.json({ success: false, description: 'No file specified.' })
}
const file = await db.table('files')
.where('id', id)
.where(function () {
if (user.username !== 'root') {
this.where('userid', user.id)
}
})
.first()
const deleteFile = await utils.deleteFile(file.name).catch(console.error)
if (!deleteFile) { return }
await db.table('files')
.where('id', id)
.del()
if (file.albumid) {
await db.table('albums')
.where('id', file.albumid)
.update('editedAt', Math.floor(Date.now() / 1000))
}
return res.json({ success: true })
req.body.field = 'id'
req.body.values = [req.body.id]
delete req.body.id
return uploadsController.bulkDelete(req, res)
}
uploadsController.bulkDelete = async (req, res) => {

View File

@ -4,12 +4,14 @@ const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const gm = require('gm')
const path = require('path')
const snekfetch = require('snekfetch')
const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const utilsController = {}
const uploadsDir = path.join(__dirname, '..', config.uploads.folder)
const thumbsDir = path.join(uploadsDir, 'thumbs')
const cloudflareAuth = config.cloudflare.apiKey && config.cloudflare.email && config.cloudflare.zoneId
utilsController.imageExtensions = ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png']
utilsController.videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv']
@ -179,7 +181,40 @@ utilsController.bulkDeleteFiles = async (field, values, user) => {
}))
}
if (config.cloudflare.purgeCache) {
// purgeCloudflareCache() is an async function, but let us not wait for it
const names = files.filter(file => !failed.includes(file[field])).map(file => file.name)
utilsController.purgeCloudflareCache(names)
}
return failed
}
utilsController.purgeCloudflareCache = async names => {
if (!cloudflareAuth) { return }
const thumbs = []
names = names.map(name => {
const url = `${config.domain}/${name}`
const extname = path.extname(name).toLowerCase()
if (utilsController.mayGenerateThumb(extname)) {
thumbs.push(`${config.domain}/thumbs/${name.slice(0, -extname.length)}.png`)
}
return url
})
const purge = await snekfetch
.post(`https://api.cloudflare.com/client/v4/zones/${config.cloudflare.zoneId}/purge_cache`)
.set({
'X-Auth-Email': config.cloudflare.email,
'X-Auth-Key': config.cloudflare.apiKey
})
.send({ files: names.concat(thumbs) })
.catch(error => error)
if (purge.body && !purge.body.success) {
purge.body.errors.forEach(error => console.error(`CF: ${error.code}: ${error.message}`))
}
}
module.exports = utilsController

View File

@ -31,6 +31,7 @@
"multer": "^1.3.0",
"nunjucks": "^3.1.2",
"randomstring": "^1.1.5",
"snekfetch": "^3.6.4",
"sqlite3": "^4.0.0"
},
"devDependencies": {

View File

@ -2440,6 +2440,10 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
snekfetch@^3.6.4:
version "3.6.4"
resolved "https://registry.yarnpkg.com/snekfetch/-/snekfetch-3.6.4.tgz#d13e80a616d892f3d38daae4289f4d258a645120"
source-map-resolve@^0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a"