UNPKG

@licq/cos

Version:

封装腾讯cos上传相关的方法

224 lines (204 loc) 6.89 kB
const fs = require("fs"); const COS = require("cos-nodejs-sdk-v5"); const fileUtils = require("@licq/file"); const _ = require("lodash"); const path = require("path"); /** * 腾讯云对象存储cos上传 * @name Cos * @param {Object} Config 对象存储参数 参考:<https://cloud.tencent.com/document/product/436/8629#.E9.85.8D.E7.BD.AE.E9.A1.B9> * @param {String} Config.SecretId 必填 * @param {String} Config.SecretKey 必填 * * @param {Object} Config.CosObjectConfig 参见 <https://cloud.tencent.com/document/product/436/64980#.E7.AE.80.E5.8D.95.E4.B8.8A.E4.BC.A0.E5.AF.B9.E8.B1.A1> 中的参数说明 * @param {String} Config.CosObjectConfig.Bucket 必填 * @param {String} Config.CosObjectConfig.Region 必填 * @param {String} Config.CosObjectConfig.ACL 可选 默认:'public-read' * * @param {Object} Config.ExtConfig 可选 本工具自定义参数 * @param {String} Config.ExtConfig.Domain 可选 上传后的域名 默认:https://{Bucket}.cos.{Region}.myqcloud.com * @since v2.0.0 * @returns instanceof COS * @example * const Cos = require('@licq/cos'); * const cos = new Cos({ * SecretId: "SECRET_ID", * SecretKey: "SECRET_KEY", * CosObjectConfig: { * Bucket: "test-12345678", * Region: "ap-guangzhou", * ACL: 'default' * }, * ExtConfig: { * Domain: 'https://demos.gtimg.cn/', * } * }); * * await cos.uploadFiles(__dirname, 'ost/cos/demo'); * */ class Cos { constructor(params) { this.checkParams(params); _.merge(this.defaultParams, params); // console.log(`this.defaultParams: ${JSON.stringify(this.defaultParams)}`); this.cos = new COS(this.defaultParams); } // cos官方配置项:https://cloud.tencent.com/document/product/436/8629#.E9.85.8D.E7.BD.AE.E9.A1.B9 defaultParams = { SecretId: "", //must SecretKey: "", //must // 控制文件上传并发数 FileParallelLimit: 60, // 控制单个文件下分片上传并发数,在同园区上传可以设置较大的并发数 ChunkParallelLimit: 60, // 控制分片大小,单位 B,在同园区上传可以设置较大的分片大小 ChunkSize: 1024 * 1024 * 5, CosObjectConfig: { Bucket: "", //must Region: "", //must ACL: "public-read", }, // 本工具自定义参数 ExtConfig: { Domain: "", // 对外的url前缀 默认:`https://${Bucket}.cos.${Region}.myqcloud.com/` }, }; //获取对外的url前缀 //默认:https://{Bucket}.cos.{Region}.myqcloud.com getHost = (cosPath) => { let { ExtConfig: { Domain }, CosObjectConfig: { Bucket, Region }, } = this.defaultParams; return ( (Domain || `https://${Bucket}.cos.${Region}.myqcloud.com/`) + cosPath ).replace(/(?<!:)(\/+)/g, "/"); // 替换https://xxx.xxx//xx///xx.js -> https://xxx.xxx/xx/xx.js }; checkParams(params) { try { if (!params) throw `need params!`; if (!params.SecretId) throw `need params SecretId!`; if (!params.SecretKey) throw `need params SecretKey!`; if (!params.CosObjectConfig.Bucket) throw `need params CosObjectConfig.Bucket!`; if (!params.CosObjectConfig.Region) throw `need params CosObjectConfig.Region!`; } catch (error) { console.log(`\n-----> ${error}\n`); //process.exit(-1) } } // 组装cos对象数组 async assemblyFiles(localPath, cosPath) { if (!fs.existsSync(localPath)) { throw new Error(`文件或目录不存在:${localPath}`); } if (fs.statSync(localPath).isFile()) { // 支持单个文件上传 const Key = (cosPath + '/' + path.basename(localPath)).replace(/\/+/g, '/'); let files = this.assemblyFile(Key, localPath); return [files]; } else { let files = await fileUtils.listFiles(localPath); // 组装files的cos数组 files = files .filter((file) => !file.isDir) .map((file) => { const Key = (cosPath + '/' + path.relative(localPath, file.path)).replace(/\/+/g, "/"); return this.assemblyFile(Key, file.path); }); return files; } } assemblyFile(Key, FilePath) { return { ...this.defaultParams.CosObjectConfig, Key, FilePath, }; } /** * 批量上传 * @param {String} localPath 本地文件/目录的绝对路径 * @param {String} cosPath cos的path * @returns Promise */ async uploadFiles(localPath, cosPath) { if (!localPath || !cosPath) { throw new Error(`缺少参数 localPath 或 cosPath`); } const getHost = this.getHost; const startTime = Date.now(); const files = await this.assemblyFiles(localPath, cosPath); return new Promise((resolve, reject) => { this.cos.uploadFiles( { files, SliceSize: 1024 * 1024, onProgress: function (info) {}, onFileFinish: function (err, data, options) { const file = getHost(options.Key); if (err) { console.log(`${file} 上传失败`); console.log(`error msg: ${err.message}\n`); } else { console.log(`${file} 上传成功`); } }, }, //data.files {options, error, data} function (err, data) { if (err) { console.log("\n-----上传失败------\n"); console.log(err); reject(); } else { console.log("\n-----上传结束------\n"); const totalTime = ((Date.now() - startTime) / 1000).toFixed(2); let errNum = 0; for (let file of data.files) { if (file.error) errNum += 1; } console.log(`\n本次上传共${data.files.length}个文件\n`); console.log(`成功:${data.files.length - errNum}`); console.log(`失败:${errNum}`); console.log(`用时:${totalTime} s`); console.log("\n-------------------\n"); resolve(); } } ); }); // return new Promise((resolve, reject) => { // }); } /** * 通过文件数据上传 * @param {String} cosPath cos路径 * @param {Buffer | String | Stream} fileData 文件数据 * @since v2.1.3 * @returns Promise<> */ async uploadFileByData(cosPath, fileData) { return new Promise((resolve, reject) => { this.cos.putObject( { ...this.defaultParams.CosObjectConfig, Key: cosPath, Body: fileData, }, (err, data) => { if (err) { console.error("\n@licq上传文件失败:", err); reject(err); } else { console.error("\n@licq上传文件成功:", data.Location); resolve(data); } } ); }); } } module.exports = Cos;