UNPKG

@yuntools/ali-oss

Version:

阿里云 OSS 命令行工具 ossutil 封装,支持 ESM,CJS 导入,提供 TypeScript 类型定义

259 lines 9.11 kB
import assert from 'node:assert/strict'; import { statSync } from 'node:fs'; import { rm } from 'node:fs/promises'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { run } from 'rxrunscript'; import { cpKeys, downloadKeys } from './config.js'; import { combineProcessRet, genParams, parseRespStdout, processResp, } from './helper.js'; import { processInputFnMap } from './process-input.js'; import { regxStat } from './rule.js'; import { CmdKey, DataKey, FnKey, Msg, } from './types.js'; /** * 阿里云 OSS 服务接口, * 基于命令行工具 ossutil 封装 */ export class OssClient { configInput; cmd; debug = false; configPath = ''; config = void 0; constructor( /** * 配置参数或者配置文件路径 * @default ~/.ossutilconfig */ configInput, cmd = 'ossutil') { this.configInput = configInput; this.cmd = cmd; if (typeof configInput === 'string') { this.configPath = configInput; const pathExists = statSync(this.configPath).isFile(); assert(pathExists, `${Msg.cloudConfigFileNotExists}: ${this.configPath}`); } else if (typeof configInput === 'object') { this.config = configInput; } else { this.configPath = join(homedir(), '.ossutilconfig'); const pathExists = statSync(this.configPath).isFile(); assert(pathExists, `${Msg.cloudConfigFileNotExists}: ${this.configPath}`); } } /** * 删除 OSS 配置文件 */ async destroy() { const { configPath } = this; await rm(configPath); } /** * 在远程之间拷贝文件。 * 若 force 为空或者 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @note 下载文件使用 `download()` * @link https://help.aliyun.com/document_detail/120057.html */ async cp(options) { if (!options.force) { const statRet = await this.stat(options); if (!statRet.exitCode) { const ret = { exitCode: 1, exitSignal: '', stdout: '', stderr: `${Msg.cloudFileAlreadyExists}: "${options.target}"`, data: void 0, }; return ret; } } const ret = await this.runner(options, FnKey.cp, cpKeys); return ret; } /** * 创建软链接 * @link https://help.aliyun.com/document_detail/120059.html */ async createSymlink(options) { const keys = [DataKey.elapsed]; const ret = await this.runner(options, FnKey.link, keys); return ret; } /** * 下载远程文件到本地 * 若 force 为空或者 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @link https://help.aliyun.com/document_detail/120057.html */ async download(options) { const ret = await this.runner(options, FnKey.download, downloadKeys); return ret; } /** * 创建目录 * @link https://help.aliyun.com/document_detail/120062.html */ async mkdir(options) { const keys = [DataKey.elapsed]; const ret = await this.runner(options, FnKey.mkdir, keys); return ret; } /** * 移动云端的 OSS 对象 * 流程为先 `cp()` 然后 `rm()` */ async mv(options) { const opts = { ...options, encodeSource: true, }; const cp = await this.cp(opts); if (cp.exitCode) { return cp; } const opts2 = { ...options, target: options.src, }; const remove = await this.rm(opts2); if (remove.exitCode) { return remove; } const statRet = await this.stat(opts); return statRet; } /** * OSS 远程路径是否存在 */ async pathExists(options) { const statRet = await this.stat(options); const exists = !!(statRet.exitCode === 0 && statRet.data); return exists; } /** * 探测上传状态 * @link https://help.aliyun.com/document_detail/120061.html */ async probeUpload(options) { const keys = [DataKey.elapsed]; const ret = await this.runner(options, FnKey.probeUpload, keys); return ret; } /** * 删除云对象,不支持删除 bucket 本身 * 如果在 recusive 为 false 时删除目录,则目录参数值必须以 '/' 结尾,否则不会删除成功 * @link https://help.aliyun.com/document_detail/120053.html */ async rm(options) { const keys = [DataKey.elapsed, DataKey.averageSpeed]; const ret = await this.runner(options, FnKey.rm, keys); return ret; } /** * 递归删除,相当于 `rm -rf` * @link https://help.aliyun.com/document_detail/120053.html */ async rmrf(options) { const keys = [DataKey.elapsed, DataKey.averageSpeed]; const ret = await this.runner(options, FnKey.rmrf, keys); return ret; } /** * sign(生成签名URL) * @link https://help.aliyun.com/document_detail/120064.html */ async sign(options) { const keys = [DataKey.elapsed, DataKey.httpUrl, DataKey.httpShareUrl]; const ret = await this.runner(options, FnKey.sign, keys); if (ret.data?.httpUrl) { ret.data.link = options.disableEncodeSlash ? ret.data.httpUrl : decodeURIComponent(ret.data.httpUrl); } return ret; } /** * 查看 Bucket 和 Object 信息 * @link https://help.aliyun.com/document_detail/120054.html */ async stat(options) { const keys = [DataKey.elapsed].concat(Array.from(regxStat.keys())); const ret = await this.runner(options, FnKey.stat, keys); return ret; } /** * 在 OSS 之间同步文件 * - force 参数默认 true * - 若 force 为 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @link https://help.aliyun.com/document_detail/256354.html */ async syncCloud(options) { const ret = await this.runner(options, FnKey.syncCloud, cpKeys); return ret; } /** * 同步 OSS 文件到本地 * - force 参数默认 true * - 若 force 为 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @link https://help.aliyun.com/document_detail/256352.html */ async syncLocal(options) { const ret = await this.runner(options, FnKey.syncLocal, cpKeys); return ret; } /** * 同步本地文件到 OSS * - force 参数默认 true * - 若 force 为 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @link https://help.aliyun.com/document_detail/193394.html */ async syncRemote(options) { const ret = await this.runner(options, FnKey.syncRemote, cpKeys); return ret; } /** * 上传本地文件到 OSS * 若 force 为空或者 false,且目标文件存在时会卡在命令行提示输入阶段(无显示)最后导致超时异常 * @link https://help.aliyun.com/document_detail/120057.html */ async upload(options) { if (!options.force) { const statRet = await this.stat(options); if (!statRet.exitCode) { const ret = { exitCode: 1, exitSignal: '', stdout: '', stderr: `${Msg.cloudFileAlreadyExists}: "${options.target}"`, data: void 0, }; return ret; } } const ret = await this.runner(options, FnKey.upload, cpKeys); return ret; } async runner(options, fnKey, retKeys) { assert(fnKey, 'fnKey is required'); assert(retKeys, 'retKeys is required'); assert(retKeys.length, 'retKeys must be an array'); // @ts-ignore const cmdKey = CmdKey[fnKey]; assert(cmdKey, 'cmdKey is required'); const ps = await this.genCliParams(fnKey, options); const resp$ = run(`${this.cmd} ${cmdKey} ${ps.join(' ')} `); const res = await processResp(resp$, this.debug); const data = parseRespStdout(res, retKeys, this.debug); const ret = combineProcessRet(res, data); return ret; } async genCliParams(fnKey, options) { const func = processInputFnMap.get(fnKey); assert(typeof func === 'function', `${fnKey} is not a function`); const map = await func(options, this.config); assert(map); const ret = genParams(this.configPath, map); return ret; } } //# sourceMappingURL=oss.js.map