UNPKG

@nocobase/plugin-file-manager

Version:

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

210 lines (208 loc) • 6.31 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 __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var s3_exports = {}; __export(s3_exports, { default: () => s3_default }); module.exports = __toCommonJS(s3_exports); var import_client_s3 = require("@aws-sdk/client-s3"); var import_lib_storage = require("@aws-sdk/lib-storage"); var import_stream = require("stream"); var import__ = require("."); var import_constants = require("../../constants"); var import_utils2 = require("../utils"); class CountingStream extends import_stream.Transform { size = 0; _transform(chunk, encoding, callback) { this.size += chunk.length; callback(null, chunk); } } class s3_default extends import__.StorageType { static defaults() { return { title: "AWS S3", name: "aws-s3", type: import_constants.STORAGE_TYPE_S3, baseUrl: process.env.AWS_S3_STORAGE_BASE_URL, options: { region: process.env.AWS_S3_REGION, accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, bucket: process.env.AWS_S3_BUCKET } }; } static filenameKey = "key"; client; constructor(storage) { super(storage); const { accessKeyId, secretAccessKey, ...options } = this.storage.options; const params = { ...options, requestChecksumCalculation: "WHEN_REQUIRED" }; if (accessKeyId && secretAccessKey) { params.credentials = { accessKeyId, secretAccessKey }; } if (options.endpoint) { params.forcePathStyle = true; } else { params.endpoint = void 0; } this.client = new import_client_s3.S3Client(params); this.client.middlewareStack.remove("flexibleChecksumsMiddleware"); this.client.middlewareStack.remove("flexibleChecksumsInputMiddleware"); } make() { const { bucket, acl = "public-read" } = this.storage.options; const keyGetter = (0, import_utils2.cloudFilenameGetter)(this.storage); const client = this.client; const once = (fn) => { let called = false; return (...args) => { if (called) return; called = true; fn(...args); }; }; return { s3: client, async _handleFile(req, file, cb) { const done = once(cb); let key; try { key = await new Promise((resolve, reject) => { keyGetter(req, file, (err, value) => { if (err) { reject(err); return; } resolve(value); }); }); } catch (error) { done(error); return; } try { const contentType = file.mimetype || "application/octet-stream"; const counter = new CountingStream(); const uploadStream = file.stream.pipe(counter); const upload = new import_lib_storage.Upload({ client, params: { Bucket: bucket, Key: key, ACL: acl, Body: uploadStream, ContentType: contentType }, queueSize: 1, leavePartsOnError: false }); const result = await upload.done(); done(null, { size: counter.size, bucket, key, acl, contentType, etag: result.ETag, versionId: result.VersionId }); } catch (error) { done(error); } }, _removeFile(req, file, cb) { (async () => { try { await client.send( new import_client_s3.DeleteObjectCommand({ Bucket: bucket, Key: file.key }) ); cb(null); } catch (err) { cb(err); } })(); } }; } async deleteS3Objects(bucketName, objects) { const Deleted = []; for (const Key of objects) { const deleteCommand = new import_client_s3.DeleteObjectCommand({ Bucket: bucketName, Key }); await this.client.send(deleteCommand); Deleted.push({ Key }); } return { Deleted }; } async exists(record) { try { await this.client.send( new import_client_s3.HeadObjectCommand({ Bucket: this.storage.options.bucket, Key: this.getFileKey(record) }) ); return true; } catch (error) { if (["NotFound", "NoSuchKey", "NoSuchBucket"].includes(error.name)) { return false; } throw error; } } async copy(source, target) { const sourceKey = this.getFileKey(source); await this.client.send( new import_client_s3.CopyObjectCommand({ Bucket: this.storage.options.bucket, Key: this.getFileKey(target), CopySource: `${this.storage.options.bucket}/${sourceKey.split("/").map((segment) => encodeURIComponent(segment)).join("/")}` }) ); } async delete(records) { const { Deleted } = await this.deleteS3Objects( this.storage.options.bucket, records.map((record) => this.getFileKey(record)) ); return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === this.getFileKey(record)))]; } }