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