@nocobase/plugin-file-manager
Version:
Provides files storage services with files collection template and attachment field.
200 lines (198 loc) • 6.86 kB
JavaScript
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tx_cos_exports = {};
__export(tx_cos_exports, {
default: () => tx_cos_default
});
module.exports = __toCommonJS(tx_cos_exports);
var import_util = require("util");
var import_stream = require("stream");
var import_url_join = __toESM(require("url-join"));
var import__ = require(".");
var import_constants = require("../../constants");
var import_utils = require("../utils");
const ERROR_NO_CLIENT = new Error("cos client undefined");
class CountingStream extends import_stream.Transform {
size = 0;
_transform(chunk, encoding, callback) {
this.size += chunk.length;
callback(null, chunk);
}
}
class TxCosStorage {
cos;
getFilename;
baseUrl;
options;
constructor({ config, baseUrl, filename }) {
const COS = require("cos-nodejs-sdk-v5");
this.cos = new COS({
SecretId: config.SecretId,
SecretKey: config.SecretKey,
SecurityToken: config.SecurityToken,
XCosSecurityToken: config.XCosSecurityToken,
FileParallelLimit: config.FileParallelLimit,
ChunkParallelLimit: config.ChunkParallelLimit,
ChunkSize: config.ChunkSize,
Domain: config.Domain,
Protocol: config.Protocol,
Timeout: config.Timeout,
KeepAlive: config.KeepAlive,
ForcePathStyle: config.ForcePathStyle,
CompatibilityMode: config.CompatibilityMode,
UseAccelerate: config.UseAccelerate
});
this.getFilename = filename;
this.baseUrl = baseUrl;
this.options = config;
}
getUploadedFileURL(key, location) {
if (this.baseUrl) {
return (0, import_url_join.default)(this.baseUrl, key);
}
if (!location) {
return key;
}
if (/^https?:\/\//.test(location)) {
return location;
}
return `https://${location}`;
}
_handleFile(req, file, cb) {
if (!this.cos) {
return cb(ERROR_NO_CLIENT);
}
const getFilename = (0, import_util.promisify)(this.getFilename);
Promise.resolve().then(async () => {
const key = await getFilename(req, file);
const counter = new CountingStream();
const body = file.stream.pipe(counter);
const params = {
Bucket: this.options.Bucket,
Region: this.options.Region,
Key: key,
Body: body
};
if (file.mimetype === "text/plain") {
params.ContentType = "text/plain; charset=utf-8";
} else if (file.mimetype) {
params.ContentType = file.mimetype;
}
const result = await (0, import_util.promisify)(this.cos.putObject).call(this.cos, params);
cb(null, {
key,
size: counter.size,
url: this.getUploadedFileURL(key, result == null ? void 0 : result.Location)
});
}).catch(cb);
}
_removeFile(req, file, cb) {
if (!this.cos) {
return cb(ERROR_NO_CLIENT);
}
if (!file.key) {
return cb(null);
}
this.cos.deleteObject(
{
Bucket: this.options.Bucket,
Region: this.options.Region,
Key: file.key
},
cb
);
}
}
class tx_cos_default extends import__.StorageType {
static defaults() {
return {
title: "\u817E\u8BAF\u4E91\u5BF9\u8C61\u5B58\u50A8",
type: import_constants.STORAGE_TYPE_TX_COS,
name: "tx-cos-1",
baseUrl: process.env.TX_COS_STORAGE_BASE_URL,
options: {
Region: process.env.TX_COS_REGION,
SecretId: process.env.TX_COS_SECRET_ID,
SecretKey: process.env.TX_COS_SECRET_KEY,
Bucket: process.env.TX_COS_BUCKET
}
};
}
static filenameKey = "url";
make() {
return new TxCosStorage({
config: this.storage.options,
baseUrl: this.storage.baseUrl,
filename: (0, import_utils.cloudFilenameGetter)(this.storage)
});
}
async exists(record) {
const { cos } = this.make();
try {
await (0, import_util.promisify)(cos.headObject).call(cos, {
Region: this.storage.options.Region,
Bucket: this.storage.options.Bucket,
Key: (0, import_utils.getFileKey)(record)
});
return true;
} catch (error) {
if (["NoSuchKey", "NotFound"].includes(error.name)) {
return false;
}
throw error;
}
}
async copy(source, target) {
const { cos } = this.make();
const sourceKey = (0, import_utils.getFileKey)(source);
const copySource = `${this.storage.options.Bucket}.cos.${this.storage.options.Region}.myqcloud.com/${sourceKey.split("/").map((segment) => encodeURIComponent(segment)).join("/")}`;
await (0, import_util.promisify)(cos.putObjectCopy).call(cos, {
Region: this.storage.options.Region,
Bucket: this.storage.options.Bucket,
Key: (0, import_utils.getFileKey)(target),
CopySource: copySource
});
}
async delete(records) {
const { cos } = this.make();
const { Deleted } = await (0, import_util.promisify)(cos.deleteMultipleObject).call(cos, {
Region: this.storage.options.Region,
Bucket: this.storage.options.Bucket,
Objects: records.map((record) => ({ Key: (0, import_utils.getFileKey)(record) }))
});
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === (0, import_utils.getFileKey)(record)))];
}
}