mirai-js
Version:
QQ robot development framework based on Mirai-api-http.
270 lines (241 loc) • 10.3 kB
JavaScript
const { isBrowserEnv } = require('./util/isBrowserEnv');
const fs = isBrowserEnv() ? null : require('fs');
const path = isBrowserEnv() ? null : require('path');
const { promisify } = isBrowserEnv() ? { promisify: null } : require('util');
class FileManager {
constructor({ bot, group }) {
const baseUrl = bot.getBaseUrl();
const sessionKey = bot.sessionKey();
// core 柯里化,为内部类 File Directory 提供包装的接口
this._getGroupFileList = ({ dir }) => require('./core/fs/getGroupFileList')({
baseUrl, sessionKey, target: group, dir
});
this._getGroupFileInfo = ({ id }) => require('./core/fs/getGroupFileInfo')({
baseUrl, sessionKey, target: group, id
});
this._uploadFileAndSend = ({ type, path, file }) => require('./core/fs/uploadGroupFIle')({
baseUrl, sessionKey, type, target: group, path, file
});
this._groupFileDelete = ({ id }) => require('./core/fs/deleteGroupFile')({
baseUrl, sessionKey, target: group, id
});
this._makeGroupDir = ({ dir }) => require('./core/fs/makeGroupDir')({
baseUrl, sessionKey, target: group, dir
});
this._groupFileRename = ({ id, rename }) => require('./core/fs/renameGroupFile')({
baseUrl, sessionKey, target: group, id, rename
});
this._groupFileMove = ({ id, movePath }) => require('./core/fs/moveGroupFile')({
baseUrl, sessionKey, target: group, id, movePath
});
// 外部类实例引用
let FileManager_this = this;
class File {
constructor(fileObj) {
// 将 GET /groupFileList 与 GET /groupFileInfo 的信息放一起
this._details = {
name: fileObj?.name,
id: fileObj?.id,
path: fileObj?.path,
isFile: fileObj?.isFile,
};
// 按需请求,延后求值
/*{
id: undefined,
path: undefined,
name: undefined,
length: undefined,
downloadTimes: undefined,
uploaderId: undefined,
uploadTime: undefined,
lastModifyTime: undefined,
downloadUrl: undefined,
sha1: undefined,
md5: undefined,
};*/
}
/**
* @description 移除该文件
* @returns this
*/
async delete() {
await FileManager_this._groupFileDelete({
id: this._details.id,
});
return this;
}
/**
* @description 移动文件
* @returns this
*/
async move(path) {
if (!path) {
throw new Error('Bot.FileManager.File.move 缺少必要的 path 参数');
}
await FileManager_this._groupFileMove({
id: this._details.id,
movePath: path,
});
// 更新 fields
await this._requestFields();
return this;
}
/**
* @description 重命名文件
* @returns this
*/
async rename(name) {
if (!name) {
throw new Error('Bot.FileManager.File.rename 缺少必要的 name 参数');
}
await FileManager_this._groupFileRename({
id: this._details.id,
rename: name,
});
// 更新 fields
await this._requestFields();
return this;
}
/**
* @private
* @description 请求 file info 并合并对象至 this._details
*/
async _requestFields() {
return Object.assign(this._details, await FileManager_this._getGroupFileInfo({ id: await this.id() }));
}
/**
* @private
* @description 获取属性的抽象
*/
async _getField(field) {
if (!this._details[field]) {
await this._requestFields();
}
return this._details[field];
}
/**
* @description 文件属性
*/
async allFields() { return await this._requestFields(); }
async isDir() { return !(await this._getField('isFile')); }
async isFile() { return await this._getField('isFile'); }
async name() { return await this._getField('name'); }
async path() { return await this._getField('path'); }
async id() { return await this._getField('id'); }
async length() { return await this._getField('length'); }
async downloadTimes() { return await this._getField('downloadTimes'); }
async uploaderId() { return await this._getField('uploaderId'); }
async uploadTime() { return await this._getField('uploadTime'); }
async lastModifyTime() { return await this._getField('lastModifyTime'); }
async downloadUrl() { return await this._getField('downloadUrl'); }
async sha1() { return await this._getField('sha1'); }
async md5() { return await this._getField('md5'); }
}
class Directory {
constructor(fileObj) {
this._details = {
name: fileObj?.name,
id: fileObj?.id,
path: fileObj?.path,
isFile: fileObj?.isFile,
};
}
/**
* @private
* @description 获取属性的抽象
*/
async _getField(field) {
return this._details[field];
}
/**
* @description 目录属性
*/
async allFields() { return await this._details; }
async isDir() { return !(await this._getField('isFile')); }
async isFile() { return await this._getField('isFile'); }
async name() { return await this._getField('name'); }
async path() { return await this._getField('path'); }
async id() { return await this._getField('id'); }
/**
* @description 获取指定目录下的 文件/目录 数组
* @param {string} dir 可选,目录,默认为当前实例指代的目录
* @returns
*/
async getFileList(dir = this._details.path) {
return (await FileManager_this._getGroupFileList({ dir })).map(fileObj => FileManager_this._getInstance(fileObj));
}
/**
* @description 上传文件至当前实例指代的目录下
* @param {Buffer} file 二选一,文件二进制数据
* @param {string} filePath 二选一,文件路径
* @param {string} filename 可选,文件名,默认为指定路径的文件名
*/
async upload({ file, filePath, filename }) {
// 检查参数
if (isBrowserEnv && filePath) {
throw new Error('Bot.FileManager.Directory.upload 浏览器端不支持 filePath 参数');
}
if (!file && !filePath) {
throw new Error('Bot.FileManager.Directory.upload 缺少必要的 file 或 filePath 参数');
}
// 若传入 filename 则统一转换为 Buffer
if (filename) {
// 优先使用 file 的原值
file = file ?? await promisify(fs.readFile)(filename);
}
await this._uploadFileAndSend({
file,
type: 'group',
path: await this.path() + filename ?? path.parse(filePath).base,
});
}
}
// 内部类引用
this.File = File;
this.Directory = Directory;
}
/**
* @private
* @description 工厂方法,返回 File Directory 实例
* @param {Object} fileObj
* @returns
*/
_getInstance(fileObj) {
if (fileObj?.isFile === true) {
return new this.File(fileObj);
} else if (fileObj?.isFile === false) {
return new this.Directory(fileObj);
}
return undefined;
}
/**
* @description 获取指定目录下的 文件/目录 数组
* @param {string} dir 可选,目录,默认为根目录
* @returns
*/
async getFileList(dir) {
return (await this._getGroupFileList({ dir })).map(fileObj => this._getInstance(fileObj));
}
/**
* @description 上传文件至指定的绝对路径
* @param {string} uploadPath 必须,上传的绝对路径
* @param {Buffer} file 二选一,文件二进制数据
* @param {string} filePath 二选一,文件路径
*/
async uploadTo({ uploadPath, file, filePath }) {
// 检查参数
if (isBrowserEnv() && filePath) {
throw new Error('Bot.FileManager.uploadTo 浏览器端不支持 filePath 参数');
}
if (!file && !filePath) {
throw new Error('Bot.FileManager.uploadTo 缺少必要的 file 或 filePath 参数');
}
// 若传入 filename 则统一转换为 Buffer
if (filePath) {
// 优先使用 file 的原值
file = file ?? await promisify(fs.readFile)(filePath);
}
await this._uploadFileAndSend({ type: 'Group', path: uploadPath, file });
}
}
module.exports = { FileManager };