UNPKG

@nocobase/plugin-file-manager

Version:

Provides files storage services with files collection template and attachment field.

200 lines (198 loc) 6.86 kB
/** * 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)))]; } }