t-comm
Version:
专业、稳定、纯粹的工具库
227 lines (224 loc) • 7.62 kB
JavaScript
import _regeneratorRuntime from '@babel/runtime/regenerator';
import { _ as __awaiter } from '../../tslib.es6-848120af.js';
import { getLocalFileMd5, getLocalFileSize } from '../../fs/fs.mjs';
import { getCOSInstance } from './helper.mjs';
import '../../nodejs/crypto.mjs';
import '../../nodejs/fs.mjs';
import '../../nodejs/os.mjs';
import '../../bite/format-bite.mjs';
import '../../third-party/cos-nodejs-sdk-v5.mjs';
/**
* 获取腾讯云COS对象的元数据信息(不返回对象内容)
*
* @param secretId - 腾讯云API密钥ID
* @param secretKey - 腾讯云API密钥Key
* @param bucket - COS存储桶名称
* @param region - COS存储桶所在区域
* @param key - 对象键(Object Key),对象在存储桶中的唯一标识
* @returns Promise对象,成功时返回对象的元数据信息(如大小、修改时间等),失败时返回错误信息
* @throws 当参数不全时会抛出错误
* @example
* ```typescript
* getCosHeadObject({
* secretId: 'your-secret-id',
* secretKey: 'your-secret-key',
* bucket: 'test-bucket',
* region: 'ap-beijing',
* key: 'path/to/file.txt'
* })
* .then(data => console.log(data))
* .catch(err => console.error(err));
* ```
*/
function getCosHeadObject(_ref) {
var secretId = _ref.secretId,
secretKey = _ref.secretKey,
bucket = _ref.bucket,
region = _ref.region,
key = _ref.key;
return new Promise(function (resolve, reject) {
if (!secretId || !secretKey || !bucket || !region) {
reject('[Upload COS Error] 参数不全');
return;
}
var cos = getCOSInstance(secretId, secretKey);
cos.headObject({
Bucket: bucket,
Region: region,
Key: key
}, function (err, data) {
if (data) {
resolve(data);
return;
}
reject(err || data);
});
});
}
/**
* 下载腾讯云COS对象内容
*
* @param secretId - 腾讯云API密钥ID
* @param secretKey - 腾讯云API密钥Key
* @param bucket - COS存储桶名称
* @param region - COS存储桶所在区域
* @param key - 对象键(Object Key),对象在存储桶中的唯一标识
* @param output - 输出路径或输出流,可选参数。如果指定,对象内容将写入该路径或流
* @returns Promise对象,成功时返回对象内容数据,失败时返回错误信息
* @throws 当参数不全时会抛出错误
* @example
* ```typescript
* // 下载到内存
* downloadCosObject({
* secretId: 'your-secret-id',
* secretKey: 'your-secret-key',
* bucket: 'test-bucket',
* region: 'ap-beijing',
* key: 'path/to/file.txt'
* })
* .then(data => console.log(data))
* .catch(err => console.error(err));
*
* // 下载到文件
* downloadCosObject({
* secretId: 'your-secret-id',
* secretKey: 'your-secret-key',
* bucket: 'test-bucket',
* region: 'ap-beijing',
* key: 'path/to/file.txt',
* output: './local/file.txt'
* })
* .then(data => console.log('下载成功'))
* .catch(err => console.error(err));
* ```
*/
function downloadCosObject(_ref2) {
var secretId = _ref2.secretId,
secretKey = _ref2.secretKey,
bucket = _ref2.bucket,
region = _ref2.region,
key = _ref2.key,
output = _ref2.output;
return new Promise(function (resolve, reject) {
if (!secretId || !secretKey || !bucket || !region) {
reject('[Upload COS Error] 参数不全');
return;
}
var cos = getCOSInstance(secretId, secretKey);
cos.getObject({
Bucket: bucket,
Region: region,
Key: key,
Output: output
}, function (err, data) {
if (data) {
resolve(data);
return;
}
reject(err || data);
});
});
}
/**
* 判断 COS 对象与本地文件是否一致(基于 size 与 ETag/MD5)
*
* 实现说明:
* 1. 先比较文件大小(HEAD 返回的 Content-Length 与本地 stat().size);不一致直接判定为不同。
* 2. 大小一致时,再比较 MD5:
* - 优先使用 COS 的 `x-cos-meta-md5`(上传时显式设置的元数据,最可靠);
* - 否则使用 ETag(仅当对象为简单上传,即 ETag 不含连字符 `-` 时才视为整体 MD5;分块上传 ETag 不可用于直接比较)。
*
* @param secretId - 腾讯云 API 密钥 ID
* @param secretKey - 腾讯云 API 密钥 Key
* @param bucket - COS 存储桶名称
* @param region - COS 存储桶所在区域
* @param key - 对象键
* @param localFilePath - 本地文件路径
* @returns {Promise<boolean>} 一致返回 true,否则 false(本地文件不存在或对象不存在也返回 false)
*
* @example
* ```typescript
* const same = await isCosObjectSameAsLocal({
* secretId, secretKey,
* bucket: 'test-bucket', region: 'ap-beijing',
* key: 'path/to/file.txt',
* localFilePath: './local/file.txt',
* });
* if (!same) {
* // 重新上传
* }
* ```
*/
function isCosObjectSameAsLocal(_ref3) {
var secretId = _ref3.secretId,
secretKey = _ref3.secretKey,
bucket = _ref3.bucket,
region = _ref3.region,
key = _ref3.key,
localFilePath = _ref3.localFilePath;
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var localSize, head, headers, remoteSize, remoteMetaMd5, localMd5, rawETag, etag, _localMd;
return _regeneratorRuntime.wrap(function (_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
localSize = getLocalFileSize(localFilePath);
if (!(localSize === null)) {
_context.next = 1;
break;
}
return _context.abrupt("return", false);
case 1:
_context.prev = 1;
_context.next = 2;
return getCosHeadObject({
secretId: secretId,
secretKey: secretKey,
bucket: bucket,
region: region,
key: key
});
case 2:
head = _context.sent;
_context.next = 4;
break;
case 3:
_context.prev = 3;
_context["catch"](1);
return _context.abrupt("return", false);
case 4:
headers = (head === null || head === void 0 ? void 0 : head.headers) || {};
remoteSize = Number(headers['content-length']);
if (!(!Number.isFinite(remoteSize) || remoteSize !== localSize)) {
_context.next = 5;
break;
}
return _context.abrupt("return", false);
case 5:
// 1. 优先使用 x-cos-meta-md5
remoteMetaMd5 = headers['x-cos-meta-md5'] || '';
if (!remoteMetaMd5) {
_context.next = 6;
break;
}
localMd5 = getLocalFileMd5(localFilePath);
return _context.abrupt("return", !!localMd5 && localMd5.toLowerCase() === remoteMetaMd5.toLowerCase());
case 6:
// 2. 退化到 ETag(仅简单上传可作为 MD5 使用)
rawETag = (head === null || head === void 0 ? void 0 : head.ETag) || headers.etag || '';
etag = rawETag.replace(/"/g, '');
if (!(etag && !etag.includes('-'))) {
_context.next = 7;
break;
}
_localMd = getLocalFileMd5(localFilePath);
return _context.abrupt("return", !!_localMd && _localMd.toLowerCase() === etag.toLowerCase());
case 7:
return _context.abrupt("return", false);
case 8:
case "end":
return _context.stop();
}
}, _callee, null, [[1, 3]]);
}));
}
export { downloadCosObject, getCosHeadObject, isCosObjectSameAsLocal };