@yuntools/ali-oss
Version:
阿里云 OSS 命令行工具 ossutil 封装,支持 ESM,CJS 导入,提供 TypeScript 类型定义
259 lines • 9.11 kB
JavaScript
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