2019-03-26 20:17:43 +08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const GridFSBucket = require('mongodb').GridFSBucket;
|
|
|
|
const libbase64 = require('libbase64');
|
|
|
|
const libmime = require('libmime');
|
|
|
|
|
|
|
|
class StorageHandler {
|
|
|
|
constructor(options) {
|
|
|
|
this.database = options.database;
|
|
|
|
this.gridfs = options.gridfs || options.database;
|
|
|
|
this.users = options.users || options.database;
|
|
|
|
this.bucketName = 'storage';
|
|
|
|
|
|
|
|
this.gridstore = new GridFSBucket(this.gridfs, {
|
|
|
|
bucketName: this.bucketName,
|
|
|
|
chunkSizeBytes: 255 * 1024
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:56:52 +08:00
|
|
|
async add(user, options) {
|
|
|
|
let filename = options.filename;
|
|
|
|
let contentType = options.contentType;
|
|
|
|
|
|
|
|
let filebase = 'upload-' + new Date().toISOString().substr(0, 10);
|
|
|
|
if (!contentType && !filename) {
|
|
|
|
filename = filebase + '.bin';
|
|
|
|
contentType = 'application/octet-stream';
|
|
|
|
} else if (!contentType) {
|
|
|
|
contentType = libmime.detectMimeType(filename) || 'application/octet-stream';
|
2021-01-15 16:40:03 +08:00
|
|
|
} else if (!filename) {
|
2020-11-18 23:56:52 +08:00
|
|
|
filename = filebase + '.' + libmime.detectExtension(contentType);
|
|
|
|
}
|
2019-03-26 20:17:43 +08:00
|
|
|
|
2020-11-18 23:56:52 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
2019-03-26 20:17:43 +08:00
|
|
|
let store = this.gridstore.openUploadStream(filename, {
|
|
|
|
contentType,
|
|
|
|
metadata: {
|
|
|
|
user
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
store.on('error', err => {
|
|
|
|
reject(err);
|
|
|
|
});
|
|
|
|
|
|
|
|
store.once('finish', () => {
|
|
|
|
resolve(store.id);
|
|
|
|
});
|
|
|
|
|
2019-03-26 22:41:43 +08:00
|
|
|
if (!options.encoding) {
|
|
|
|
// content is not encoded, pass on as is
|
|
|
|
try {
|
|
|
|
store.end(options.content);
|
|
|
|
} catch (err) {
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-26 20:17:43 +08:00
|
|
|
let decoder = new libbase64.Decoder();
|
|
|
|
decoder.pipe(store);
|
|
|
|
|
|
|
|
decoder.once('error', err => {
|
|
|
|
// pass error forward
|
|
|
|
store.emit('error', err);
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
decoder.end(options.content);
|
|
|
|
} catch (err) {
|
|
|
|
return reject(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:56:52 +08:00
|
|
|
async get(user, file) {
|
|
|
|
let fileData = await this.gridfs.collection('storage.files').findOne({
|
|
|
|
_id: file,
|
|
|
|
'metadata.user': user
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!fileData) {
|
|
|
|
let err = new Error('This file does not exist');
|
2021-05-22 01:14:43 +08:00
|
|
|
err.responseCode = 404;
|
2020-11-18 23:56:52 +08:00
|
|
|
err.code = 'FileNotFound';
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
2019-03-26 20:17:43 +08:00
|
|
|
return new Promise((resolve, reject) => {
|
2020-11-18 23:56:52 +08:00
|
|
|
let stream = this.gridstore.openDownloadStream(file);
|
|
|
|
let chunks = [];
|
|
|
|
let chunklen = 0;
|
|
|
|
|
|
|
|
stream.once('error', err => {
|
|
|
|
reject(err);
|
|
|
|
});
|
|
|
|
|
|
|
|
stream.on('readable', () => {
|
|
|
|
let chunk;
|
|
|
|
while ((chunk = stream.read()) !== null) {
|
|
|
|
chunks.push(chunk);
|
|
|
|
chunklen += chunk.length;
|
2019-03-26 20:17:43 +08:00
|
|
|
}
|
2020-11-18 23:56:52 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
stream.once('end', () => {
|
|
|
|
resolve({
|
2021-01-07 15:41:48 +08:00
|
|
|
id: fileData._id.toString(),
|
2020-11-18 23:56:52 +08:00
|
|
|
filename: fileData.filename,
|
|
|
|
contentType: fileData.contentType,
|
|
|
|
size: fileData.length,
|
|
|
|
content: Buffer.concat(chunks, chunklen)
|
|
|
|
});
|
|
|
|
});
|
2019-03-26 20:17:43 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:56:52 +08:00
|
|
|
async delete(user, file) {
|
|
|
|
let fileData = await this.gridfs.collection('storage.files').findOne({
|
|
|
|
_id: file,
|
|
|
|
'metadata.user': user
|
2019-03-26 20:17:43 +08:00
|
|
|
});
|
2020-11-18 23:56:52 +08:00
|
|
|
|
|
|
|
if (!fileData) {
|
|
|
|
let err = new Error('This file does not exist');
|
2021-05-22 01:14:43 +08:00
|
|
|
err.responseCode = 404;
|
2020-11-18 23:56:52 +08:00
|
|
|
err.code = 'FileNotFound';
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.gridstore.delete(file);
|
2019-03-26 20:17:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = StorageHandler;
|