You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
6.6 KiB
194 lines
6.6 KiB
/**
|
|
* Created by PengLing on 2017/12/25.
|
|
* 文件中心支持两种存储方式:
|
|
* 1. 七牛云存储 (默认)
|
|
* 2. 本地服务器存储
|
|
*/
|
|
'use strict';
|
|
|
|
const path = require('path');
|
|
const fs = require('fs-extra');
|
|
const uuidv4 = require('uuid/v4');
|
|
const qiniu = require('qiniu');
|
|
|
|
class Attachment {
|
|
constructor(opts) {
|
|
if (opts.qiniu) {
|
|
this.attachment = new QiniuAttachment(opts);
|
|
} else {
|
|
this.attachment = new LocalAttachment(opts);
|
|
}
|
|
}
|
|
|
|
async upload(file, opts) {
|
|
const rslt = await this.attachment.upload(file, opts)
|
|
|
|
return Promise.resolve(rslt);
|
|
}
|
|
|
|
async download(key) {
|
|
const url = await this.attachment.download(key)
|
|
|
|
return Promise.resolve(url)
|
|
}
|
|
|
|
async remove(key) {
|
|
const res = await this.attachment.remove(key);
|
|
|
|
return Promise.resolve(res);
|
|
}
|
|
}
|
|
|
|
class LocalAttachment {
|
|
constructor(opts = {}) {
|
|
this.origin = opts.local && opts.local.origin || 'localhost:8080';
|
|
this.rootPath = opts.local && opts.local.rootPath || 'static';
|
|
this.childPath = opts.local && opts.local.childPath || 'upload';
|
|
this.uploadPath = opts.uploadPath || 'other';
|
|
this.maxSize = opts.maxSize || '2097152'; // 2M = 2097152
|
|
}
|
|
|
|
async upload(file, opts = {}) {
|
|
let filename = file.filename || path.win32.basename(file);
|
|
|
|
let stats = fs.statSync(typeof file === 'string' ? file : file.path);
|
|
if (stats.size > this.maxSize) {
|
|
return Promise.reject(`file size exceeded: received ${stats.size} bytes of file data, allowed max size is ${this.maxSize} bytes`);
|
|
}
|
|
|
|
let childPath = `${this.childPath}/${opts.uploadPath || this.uploadPath}`;
|
|
|
|
// uploadDir: the directory for placing file uploads in.
|
|
let uploadDir = path.posix.join(this.rootPath, childPath);
|
|
|
|
fs.ensureDirSync(uploadDir);
|
|
|
|
let fprops = path.parse(filename),
|
|
basename = `${fprops.name}_${uuidv4()}${fprops.ext}`;
|
|
let key = path.posix.join(childPath, basename);
|
|
|
|
// 数据流上传
|
|
let destFilename = path.posix.join(this.rootPath, key);
|
|
let writableStream = fs.createWriteStream(destFilename);
|
|
file.pipe(writableStream);
|
|
|
|
return Promise.resolve({ key, url: `${this.origin}/${key}` });
|
|
}
|
|
|
|
async download(key) {
|
|
try {
|
|
let pth = path.posix.join(this.rootPath, key);
|
|
if (!fs.existsSync(pth)) throw 'file does not exist.';
|
|
|
|
let publicDownloadUrl = /^https?:/.test(key) ? key : `${this.origin}/${key}`;
|
|
|
|
return Promise.resolve(encodeURI(publicDownloadUrl));
|
|
} catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
}
|
|
|
|
async remove(key) {
|
|
try {
|
|
let pth = path.posix.join(this.rootPath, key);
|
|
if (!fs.existsSync(pth)) throw 'file does not exist.';
|
|
await fs.remove(pth);
|
|
return Promise.resolve(204);
|
|
} catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
class QiniuAttachment {
|
|
constructor(opts) {
|
|
this.uploadPath = opts.uploadPath || 'other';
|
|
this.maxSize = opts.maxSize || '2097152'; // 2M = 2097152
|
|
|
|
const { bucket, domain, accessKey, secretKey } = opts.qiniu;
|
|
this.bucket = bucket;
|
|
this.domain = domain;
|
|
this.accessKey = accessKey;
|
|
this.secretKey = secretKey;
|
|
}
|
|
|
|
upload(file, opts) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let uploadPath = opts && opts.uploadPath ? opts.uploadPath : this.uploadPath;
|
|
const domain = this.domain;
|
|
let filename = file.filename || path.win32.basename(file);
|
|
|
|
let stats = fs.statSync(typeof file === 'string' ? file : file.path);
|
|
if (stats.size > this.maxSize) {
|
|
reject(`file size exceeded: received ${stats.size} bytes of file data, allowed max size is ${this.maxSize} bytes`);
|
|
return;
|
|
}
|
|
|
|
let mac = new qiniu.auth.digest.Mac(this.accessKey, this.secretKey);
|
|
let putPolicy = new qiniu.rs.PutPolicy({
|
|
scope: this.bucket
|
|
});
|
|
let uploadToken = putPolicy.uploadToken(mac);
|
|
let key = path.posix.join(uploadPath, uuidv4(), filename);
|
|
let config = new qiniu.conf.Config();
|
|
let formUploader = new qiniu.form_up.FormUploader(config);
|
|
let putExtra = new qiniu.form_up.PutExtra();
|
|
// 文件上传 or 数据流上传
|
|
let fn = typeof file === 'string' ? "putFile" : "putStream";
|
|
formUploader[fn](uploadToken, key, file, putExtra, function (respErr, respBody, respInfo) {
|
|
if (respErr) {
|
|
reject(respErr);
|
|
return;
|
|
}
|
|
if (respInfo.statusCode == 200) {
|
|
let qnkey = respBody.key;
|
|
resolve({ key: qnkey, url: `${domain}/${qnkey}` });
|
|
} else {
|
|
reject(new Error('failed to upload.'));
|
|
}
|
|
});
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
download(key) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let mac = new qiniu.auth.digest.Mac(this.accessKey, this.secretKey);
|
|
let config = new qiniu.conf.Config();
|
|
let bucketManager = new qiniu.rs.BucketManager(mac, config);
|
|
let publicBucketDomain = this.domain;
|
|
// 公开空间访问链接
|
|
let publicDownloadUrl = bucketManager.publicDownloadUrl(publicBucketDomain, key);
|
|
resolve(publicDownloadUrl);
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
remove(key) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
let mac = new qiniu.auth.digest.Mac(this.accessKey, this.secretKey);
|
|
let config = new qiniu.conf.Config();
|
|
let bucketManager = new qiniu.rs.BucketManager(mac, config);
|
|
bucketManager.delete(this.bucket, key, function (respErr, respBody, respInfo) {
|
|
if (respErr) {
|
|
reject(respErr);
|
|
return;
|
|
} else {
|
|
resolve(respInfo.statusCode);
|
|
}
|
|
});
|
|
} catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = Attachment;
|
|
|