UNPKG

@push.rocks/smartbucket

Version:

A TypeScript library providing a cloud-agnostic interface for managing object storage with functionalities like bucket management, file and directory operations, and advanced features such as metadata handling and file locking.

326 lines 23.8 kB
// classes.directory.ts import * as plugins from './plugins.js'; import { Bucket } from './classes.bucket.js'; import { File } from './classes.file.js'; import * as helpers from './helpers.js'; export class Directory { constructor(bucketRefArg, parentDirectory, name) { this.bucketRef = bucketRefArg; this.parentDirectoryRef = parentDirectory; this.name = name; } /** * returns an array of parent directories */ getParentDirectories() { let parentDirectories = []; if (this.parentDirectoryRef) { parentDirectories.push(this.parentDirectoryRef); parentDirectories = parentDirectories.concat(this.parentDirectoryRef.getParentDirectories()); } return parentDirectories; } /** * returns the directory level */ getDirectoryLevel() { return this.getParentDirectories().length; } /** * updates the base path */ getBasePath() { const parentDirectories = this.getParentDirectories(); let basePath = ''; for (const parentDir of parentDirectories) { if (!parentDir.name && !basePath) { basePath = this.name + '/'; continue; } if (parentDir.name && !basePath) { basePath = parentDir.name + '/' + this.name + '/'; continue; } if (parentDir.name && basePath) { basePath = parentDir.name + '/' + basePath; continue; } } return basePath; } /** * gets a file by name */ async getFile(optionsArg) { const pathDescriptor = { directory: this, path: optionsArg.path, }; const exists = await this.bucketRef.fastExists({ path: await helpers.reducePathDescriptorToPath(pathDescriptor), }); if (!exists && optionsArg.getFromTrash) { const trash = await this.bucketRef.getTrash(); const trashedFile = await trash.getTrashedFileByOriginalName(pathDescriptor); return trashedFile; } if (!exists && !optionsArg.createWithContents) { throw new Error(`File not found at path '${optionsArg.path}'`); } if (!exists && optionsArg.createWithContents) { await File.create({ directory: this, name: optionsArg.path, contents: optionsArg.createWithContents, }); } return new File({ directoryRefArg: this, fileName: optionsArg.path, }); } /** * Check if a file exists in this directory */ async fileExists(optionsArg) { const pathDescriptor = { directory: this, path: optionsArg.path, }; return this.bucketRef.fastExists({ path: await helpers.reducePathDescriptorToPath(pathDescriptor), }); } /** * Check if a subdirectory exists */ async directoryExists(dirNameArg) { const directories = await this.listDirectories(); return directories.some(dir => dir.name === dirNameArg); } /** * Collects all ListObjectsV2 pages for a prefix. */ async listObjectsV2AllPages(prefix, delimiter) { const allContents = []; const allCommonPrefixes = []; let continuationToken; do { const command = new plugins.s3.ListObjectsV2Command({ Bucket: this.bucketRef.name, Prefix: prefix, Delimiter: delimiter, ContinuationToken: continuationToken, }); const response = await this.bucketRef.smartbucketRef.storageClient.send(command); if (response.Contents) { allContents.push(...response.Contents); } if (response.CommonPrefixes) { allCommonPrefixes.push(...response.CommonPrefixes); } continuationToken = response.IsTruncated ? response.NextContinuationToken : undefined; } while (continuationToken); return { contents: allContents, commonPrefixes: allCommonPrefixes }; } /** * lists all files */ async listFiles() { const { contents } = await this.listObjectsV2AllPages(this.getBasePath(), '/'); const fileArray = []; contents.forEach((item) => { if (item.Key && !item.Key.endsWith('/')) { const subtractedPath = item.Key.replace(this.getBasePath(), ''); if (!subtractedPath.includes('/')) { fileArray.push(new File({ directoryRefArg: this, fileName: subtractedPath, })); } } }); return fileArray; } /** * lists all folders */ async listDirectories() { try { const { commonPrefixes } = await this.listObjectsV2AllPages(this.getBasePath(), '/'); const directoryArray = []; if (commonPrefixes) { commonPrefixes.forEach((item) => { if (item.Prefix) { const subtractedPath = item.Prefix.replace(this.getBasePath(), ''); if (subtractedPath.endsWith('/')) { const dirName = subtractedPath.slice(0, -1); // Ensure the directory name is not empty (which would indicate the base directory itself) if (dirName) { directoryArray.push(new Directory(this.bucketRef, this, dirName)); } } } }); } return directoryArray; } catch (error) { console.error('Error listing directories:', error); throw error; } } /** * gets an array that has all objects with a certain prefix */ async getTreeArray() { const command = new plugins.s3.ListObjectsV2Command({ Bucket: this.bucketRef.name, Prefix: this.getBasePath(), Delimiter: '/', }); const response = await this.bucketRef.smartbucketRef.storageClient.send(command); return response.Contents; } /** * gets a sub directory by name */ async getSubDirectoryByName(dirNameArg, optionsArg = {}) { const dirNameArray = dirNameArg.split('/').filter(str => str.trim() !== ""); optionsArg = { getEmptyDirectory: false, createWithInitializerFile: false, ...optionsArg, }; const getDirectory = async (directoryArg, dirNameToSearch, isFinalDirectory) => { const directories = await directoryArg.listDirectories(); let returnDirectory = directories.find((directory) => { return directory.name === dirNameToSearch; }); if (returnDirectory) { return returnDirectory; } if (optionsArg.getEmptyDirectory || optionsArg.createWithInitializerFile) { returnDirectory = new Directory(this.bucketRef, directoryArg, dirNameToSearch); } if (isFinalDirectory && optionsArg.createWithInitializerFile) { returnDirectory?.createEmptyFile('00init.txt'); } return returnDirectory || null; }; if (optionsArg.couldBeFilePath) { const baseDirectory = await this.bucketRef.getBaseDirectory(); const existingFile = await baseDirectory.getFile({ path: dirNameArg, }); if (existingFile) { const adjustedPath = dirNameArg.substring(0, dirNameArg.lastIndexOf('/')); return this.getSubDirectoryByName(adjustedPath); } } let wantedDirectory = null; let counter = 0; for (const dirNameToSearch of dirNameArray) { counter++; const directoryToSearchIn = wantedDirectory ? wantedDirectory : this; wantedDirectory = await getDirectory(directoryToSearchIn, dirNameToSearch, counter === dirNameArray.length); } if (!wantedDirectory) { throw new Error(`Directory not found at path '${dirNameArg}'`); } return wantedDirectory; } /** * moves the directory */ async move() { // TODO throw new Error('Moving a directory is not yet implemented'); } /** * creates an empty file within this directory * @param relativePathArg */ async createEmptyFile(relativePathArg) { const emptyFile = await File.create({ directory: this, name: relativePathArg, contents: '', }); return emptyFile; } // file operations async fastPut(optionsArg) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); await this.bucketRef.fastPut({ path, contents: optionsArg.contents, }); } async fastGet(optionsArg) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); const result = await this.bucketRef.fastGet({ path, }); return result; } /** * fastGetStream * @param optionsArg * @returns */ async fastGetStream(optionsArg, typeArg) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); const result = await this.bucketRef.fastGetStream({ path, }, typeArg); return result; } /** * fast put stream */ async fastPutStream(optionsArg) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); await this.bucketRef.fastPutStream({ path, readableStream: optionsArg.stream, }); } /** * removes a file within the directory * uses file class to make sure effects for metadata etc. are handled correctly * @param optionsArg */ async fastRemove(optionsArg) { const file = await this.getFile({ path: optionsArg.path, }); await file.delete({ mode: optionsArg.mode ? optionsArg.mode : 'permanent', }); } /** * deletes the directory with all its contents */ async delete(optionsArg) { const deleteDirectory = async (directoryArg) => { const childDirectories = await directoryArg.listDirectories(); if (childDirectories.length === 0) { console.log('Directory empty! Path complete!'); } else { for (const childDir of childDirectories) { await deleteDirectory(childDir); } } const files = await directoryArg.listFiles(); for (const file of files) { await file.delete({ mode: optionsArg.mode ? optionsArg.mode : 'permanent', }); } }; await deleteDirectory(this); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kaXJlY3RvcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmRpcmVjdG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1QkFBdUI7QUFFdkIsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN6QyxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxNQUFNLE9BQU8sU0FBUztJQVNwQixZQUFZLFlBQW9CLEVBQUUsZUFBMEIsRUFBRSxJQUFZO1FBQ3hFLElBQUksQ0FBQyxTQUFTLEdBQUcsWUFBWSxDQUFDO1FBQzlCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxlQUFlLENBQUM7UUFDMUMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDbkIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksb0JBQW9CO1FBQ3pCLElBQUksaUJBQWlCLEdBQWdCLEVBQUUsQ0FBQztRQUN4QyxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzVCLGlCQUFpQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUNoRCxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLG9CQUFvQixFQUFFLENBQUMsQ0FBQztRQUMvRixDQUFDO1FBQ0QsT0FBTyxpQkFBaUIsQ0FBQztJQUMzQixDQUFDO0lBRUQ7O09BRUc7SUFDSSxpQkFBaUI7UUFDdEIsT0FBTyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxNQUFNLENBQUM7SUFDNUMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksV0FBVztRQUNoQixNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxD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