@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
JavaScript
// 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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