const { ForbiddenError } = require('../error'); const db = require('../service/db'); const fs = require('../service/gridfs'); const hash = require('../lib/hash.hydro'); const coll = db.collection('file'); async function add(stream, filename, meta = {}) { const file = await coll.insertOne(meta); const w = fs.openUploadStreamWithId(file.insertedId, filename); await new Promise((resolve, reject) => { stream.on('end', resolve); stream.on('error', reject); stream.pipe(w); }); const c = await fs.find({ _id: file.insertedId }).toArray(); await coll.updateOne({ _id: file.insertedId }, { $set: { md5: c[0].md5, size: c[0].size } }); return file.insertedId; } function del(_id) { return Promise.all([ coll.deleteOne({ _id }), fs.delete(_id), ]); } async function inc(_id) { const file = await coll.findOne({ _id }); file.count++; } async function dec(_id) { const file = await coll.findOneAndUpdate( { _id }, { $inc: { count: -1 } }, { returnOriginal: false }, ); if (!file.count) await del(_id); return file.count; } async function get(_id, secret = null) { const file = await coll.findOne({ _id }); if (typeof secret !== 'undefined') { const timestamp = Math.floor(Number(new Date())).toString(); if (!( hash.check(file.secret, timestamp, secret) || hash.check(file.secret, timestamp - 1, secret))) { throw new ForbiddenError(); } } return fs.openDownloadStream(_id); } function getMeta(_id) { return coll.findOne({ _id }); } async function url(_id, name) { const file = await coll.findOne({ _id }); const secret = hash.hash(file.secret, Math.floor(Number(new Date())).toString()); if (name) return `/fs/${_id}/${secret}?name=${Buffer.from(name).toString('base64')}`; return `/fs/${_id}/${secret}`; } global.Hydro.model.blacklist = module.exports = { add, get, del, inc, dec, getMeta, url, };