四好公路
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

/**
* 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;