import * as plugins from './plugins.js'; import { Bucket } from './classes.bucket.js'; import { File } from './classes.file.js'; export class Directory { public bucketRef: Bucket; public parentDirectoryRef: Directory; public name: string; public tree: string[]; public files: string[]; public folders: string[]; constructor(bucketRefArg: Bucket, parentDiretory: Directory, name: string) { this.bucketRef = bucketRefArg; this.parentDirectoryRef = parentDiretory; this.name = name; } /** * returns an array of parent directories */ public getParentDirectories(): Directory[] { let parentDirectories: Directory[] = []; if (this.parentDirectoryRef) { parentDirectories.push(this.parentDirectoryRef); parentDirectories = parentDirectories.concat(this.parentDirectoryRef.getParentDirectories()); } return parentDirectories; } /** * returns the directory level */ public getDirectoryLevel(): number { return this.getParentDirectories().length; } /** * updates the base path */ public getBasePath(): string { 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 */ public async getFile(optionsArg: { name: string; createWithContents?: string | Buffer; }): Promise { // check wether the file exists const exists = await this.bucketRef.fastExists({ path: this.getBasePath() + optionsArg.name, }); if (!exists && !optionsArg.createWithContents) { return null; } if (!exists && optionsArg.createWithContents) { await File.create({ directory: this, name: optionsArg.name, contents: optionsArg.createWithContents, }); } return new File({ directoryRefArg: this, fileName: optionsArg.name, }) } /** * lists all files */ public async listFiles(): Promise { const done = plugins.smartpromise.defer(); const fileNameStream = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2( this.bucketRef.name, this.getBasePath(), false ); const fileArray: File[] = []; const duplexStream = new plugins.smartstream.SmartDuplex({ objectMode: true, writeFunction: async (bucketItem) => { if (bucketItem.prefix) { return; } if (!bucketItem.name) { return; } let subtractedPath = bucketItem.name.replace(this.getBasePath(), ''); if (subtractedPath.startsWith('/')) { subtractedPath = subtractedPath.substr(1); } if (!subtractedPath.includes('/')) { fileArray.push( new File({ directoryRefArg: this, fileName: subtractedPath, }) ); } }, finalFunction: async (tools) => { done.resolve(); } }); fileNameStream.pipe(duplexStream); await done.promise; return fileArray; } /** * lists all folders */ public async listDirectories(): Promise { const done = plugins.smartpromise.defer(); const basePath = this.getBasePath(); const completeDirStream = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2( this.bucketRef.name, this.getBasePath(), false ); const directoryArray: Directory[] = []; const duplexStream = new plugins.smartstream.SmartDuplex({ objectMode: true, writeFunction: async (bucketItem) => { if (bucketItem.name) { return; } let subtractedPath = bucketItem.prefix.replace(this.getBasePath(), ''); if (subtractedPath.startsWith('/')) { subtractedPath = subtractedPath.substr(1); } if (subtractedPath.includes('/')) { const dirName = subtractedPath.split('/')[0]; if (directoryArray.find((directory) => directory.name === dirName)) { return; } directoryArray.push(new Directory(this.bucketRef, this, dirName)); } }, finalFunction: async (tools) => { done.resolve(); } }); completeDirStream.pipe(duplexStream); await done.promise; return directoryArray; } /** * gets an array that has all objects with a certain prefix; */ public async getTreeArray() { const treeArray = await this.bucketRef.smartbucketRef.minioClient.listObjectsV2( this.bucketRef.name, this.getBasePath(), true ); } /** * gets a sub directory */ public async getSubDirectoryByName(dirNameArg: string): Promise { const dirNameArray = dirNameArg.split('/'); const getDirectory = async (directoryArg: Directory, dirNameToSearch: string) => { const directories = await directoryArg.listDirectories(); return directories.find((directory) => { return directory.name === dirNameToSearch; }); }; let wantedDirectory: Directory; for (const dirNameToSearch of dirNameArray) { const directoryToSearchIn = wantedDirectory ? wantedDirectory : this; wantedDirectory = await getDirectory(directoryToSearchIn, dirNameToSearch); } return wantedDirectory; } /** * moves the directory */ public async move() { // TODO throw new Error('moving a directory is not yet implemented'); } /** * creates a file within this directory * @param relativePathArg */ public async createEmptyFile(relativePathArg: string) { const emtpyFile = await File.create({ directory: this, name: relativePathArg, contents: '', }); } // file operations public async fastPut(optionsArg: { path: string; contents: string | Buffer }) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); await this.bucketRef.fastPut({ path, contents: optionsArg.contents, }); } public async fastGet(optionsArg: { path: string }) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); const result = await this.bucketRef.fastGet({ path, }); return result; } public fastGetStream(optionsArg: { path: string; }, typeArg: 'webstream'): Promise public async fastGetStream(optionsArg: { path: string; }, typeArg: 'nodestream'): Promise /** * fastGetStream * @param optionsArg * @returns */ public async fastGetStream(optionsArg: { path: string; }, typeArg: 'webstream' | 'nodestream'): Promise{ const path = plugins.path.join(this.getBasePath(), optionsArg.path); const result = await this.bucketRef.fastGetStream({ path }, typeArg as any); return result; } /** * fast put stream */ public async fastPutStream(optionsArg: { path: string; stream: plugins.stream.Readable; }): Promise { const path = plugins.path.join(this.getBasePath(), optionsArg.path); await this.bucketRef.fastPutStream({ path, readableStream: optionsArg.stream, }); } /** * removes a file within the directory * @param optionsArg */ public async fastRemove(optionsArg: { path: string }) { const path = plugins.path.join(this.getBasePath(), optionsArg.path); await this.bucketRef.fastRemove({ path, }); } /** * deletes the directory with all its contents */ public async delete() { const deleteDirectory = async (directoryArg: Directory) => { 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 directoryArg.fastRemove({ path: file.name, }); } }; await deleteDirectory(this); } }