UNPKG

multer-cos

Version:

Streaming multer storage engine for QCloud COS

214 lines (168 loc) 6.32 kB
let fs = require('fs'); let os = require('os'); let path = require('path'); let crypto = require('crypto'); let mkdirp = require('mkdirp'); let COS = require('cos-nodejs-sdk-v5'); function getFilename (req, file, cb) { let ext =(file.originalname).split('.').pop(); crypto.pseudoRandomBytes(16, function (err, raw) { cb(err, err ? undefined : raw.toString('hex')+'.'+ext); }); } function getDestination (req, file, cb) { cb(null, os.tmpdir()); } function COSStorage (opts={}) { if (!(this instanceof COSStorage)){ return new COSStorage(opts); } if(opts.filename==='auto'||!opts.filename){ this.getFilename=getFilename; }else{ this.getFilename=opts.filename; } if (typeof opts.destination === 'string') { mkdirp.sync(opts.destination); this.getDestination = function ($0, $1, cb) { cb(null, opts.destination); }; } else { this.getDestination = (opts.destination || getDestination); } //如果有cos选项将使用cos服务 if(opts.cos){ opts.cos.SecretId = opts.cos.SecretId || process.env.SecretId || null ; opts.cos.SecretKey = opts.cos.SecretKey || process.env.SecretKey || null; opts.cos.Bucket=opts.cos.Bucket || process.env.Bucket || null; opts.cos.Region=opts.cos.Region || process.env.Region || null; opts.cos.domain = opts.cos.domain || process.env.domain || null; opts.cos.dir= opts.cos.dir || process.env.dir || ''; opts.cos.dir=opts.cos.dir==''?opts.cos.dir:opts.cos.dir+'/'; //验证cos服务 if ( ! opts.cos.SecretId ) { throw new Error( 'You have to specify qcloud api SecretId !' ); } if ( ! opts.cos.SecretKey ) { throw new Error( 'You have to specify qcloud api SecretKey .' ); } //cos运行实例 this.cos=new COS({ // 必选参数 SecretId: opts.cos.SecretId, SecretKey: opts.cos.SecretKey, // 可选参数 FileParallelLimit: 3, // 控制文件上传并发数 ChunkParallelLimit: 3, // 控制单个文件下分片上传并发数 ChunkSize: 1024 * 1024, // 控制分片大小,单位 B }); //cos运行时候的配置 this.cosRun={ domain: opts.cos.domain, // //域名 Bucket: opts.cos.Bucket, // Bucket 格式:test-1250000000 Region: opts.cos.Region, //区域 dir:opts.cos.dir, taskId:null, onProgress:opts.cos.onProgress||function(){} }; } } COSStorage.prototype.test=function(){ this.cos.getService(function (err, data) { if(err){ console.log('\x1B[31m%s\x1B[39m', 'qcloud test failed'); console.error(err); }else{ console.log('\x1B[32m%s\x1B[39m', 'qcloud test success'); console.log(data); } }); }; //取消任务 COSStorage.prototype.cancelTask=function(TaskId){ var TaskId=TaskId||this.cosRun.taskId; this.cos.cancelTask(TaskId); console.log('canceled'); }; //暂停任务 COSStorage.prototype.pauseTask=function(TaskId) { var TaskId=TaskId||this.cosRun.taskId; this.cos.pauseTask(TaskId); console.log('paused'); }; //从新开始任务 COSStorage.prototype.restartTask=function(TaskId) { var TaskId=TaskId||this.cosRun.taskId; this.cos.restartTask(TaskId); console.log('restart'); }; //分片上传 //COSStorage.prototype.sliceUploadFile= function(){ // cos.sliceUploadFile({ // Bucket: xxxx, // Region: xxx, // Key: xxxxx', // FilePath: path.resolve(__dirname , xxxx) // }, function (err, data) { // console.log(err, data); // }); //} COSStorage.prototype._handleFile = function _handleFile (req, file, cb) { let that = this; that.getDestination(req, file, function (err, destination) { if (err) {return cb(err);} file.destination=destination; that.getFilename(req, file, function (err, filename) { if (err) {return cb(err);} file.filename=that.cosRun.dir+filename; file.tmpPath = path.join(destination, filename); //制造1个temp文件 let tmp = fs.createWriteStream(file.tmpPath); file.stream.pipe(tmp); tmp.on('finish', function () { //注意:,Key(文件名)不能以 / 结尾,否则会被识别为文件夹 。 that.cos.putObject({ Bucket: that.cosRun.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 Region: that.cosRun.Region, Key: file.filename, /* 必须 */ TaskReady: function (tid) { that.cosRun.taskId = tid; }, onProgress: function (progressData) { that.cosRun.onProgress(progressData); }, // ContentType:'text/plain',cos 已经帮我们定义好了 Body: fs.createReadStream(file.tmpPath), ContentLength:tmp.bytesWritten, }, function (err, data) { if(err){ that._removeFile(req,file,function(){ cb(err.error); }); } else { if (that.cosRun.domain) { data.Location = `http://${that.cosRun.domain}/${file.filename}`; } file.url=data.Location; that._removeFile(req,file,function(){ cb(); }); } }); }); tmp.on('error', function(err){ that._removeFile(req,file,cb(err.error)); }); }); }); }; COSStorage.prototype._removeFile = function _removeFile (req, file, cb) { let path = file.tmpPath; this.cosRun.taskId=null; delete file.destination; delete file.filename; delete file.tmpPath; fs.unlink(path,cb); }; module.exports = function( opts ) { return new COSStorage( opts ); };