import * as plugins from './plugins.js'; import { Directory } from './classes.directory.js'; import { MetaData } from './classes.metadata.js'; /** * represents a file in a directory */ export class File { // STATIC /** * creates a file in draft mode * you need to call .save() to store it in s3 * @param optionsArg */ public static async create(optionsArg: { directory: Directory; name: string; contents: Buffer | string | plugins.stream.Readable; /** * if contents are of type string, you can specify the encoding here */ encoding?: 'utf8' | 'binary'; }): Promise { const contents = typeof optionsArg.contents === 'string' ? Buffer.from(optionsArg.contents, optionsArg.encoding) : optionsArg.contents; const file = new File({ directoryRefArg: optionsArg.directory, fileName: optionsArg.name, }); if (contents instanceof plugins.stream.Readable) {} else { await optionsArg.directory.fastPut({ path: optionsArg.name, contents: contents, }); } return file; } // INSTANCE public parentDirectoryRef: Directory; public name: string; public getBasePath(): string { return plugins.path.join(this.parentDirectoryRef.getBasePath(), this.name); }; constructor(optionsArg: { directoryRefArg: Directory; fileName: string }) { this.parentDirectoryRef = optionsArg.directoryRefArg; this.name = optionsArg.fileName; } public async getContentsAsString(): Promise { const fileBuffer = await this.getContents(); return fileBuffer.toString(); } public async getContents(): Promise { const resultBuffer = await this.parentDirectoryRef.bucketRef.fastGet({ path: this.getBasePath(), }); return resultBuffer; } public async getReadStream() { const readStream = this.parentDirectoryRef.bucketRef.fastGetStream({ path: this.getBasePath(), }); } /** * removes this file * for using recycling mechanics use .delete() */ public async remove() { await this.parentDirectoryRef.bucketRef.fastRemove({ path: this.getBasePath(), }); if (!this.name.endsWith('.metadata')) { await this.parentDirectoryRef.bucketRef.fastRemove({ path: this.getBasePath() + '.metadata', }); } await this.parentDirectoryRef.listFiles(); } /** * deletes the file with recycling mechanics */ public async delete() { await this.remove(); } /** * allows locking the file * @param optionsArg */ public async lock(optionsArg?: { timeoutMillis?: number }) { const metadata = await this.getMetaData(); await metadata.setLock({ lock: 'locked', expires: Date.now() + (optionsArg?.timeoutMillis || 1000), }); } /** * actively unlocks a file * */ public async unlock(optionsArg?: { /** * unlock the file even if not locked from this instance */ force?: boolean; }) { const metadata = await this.getMetaData(); await metadata.removeLock({ force: optionsArg?.force, }); } public async updateWithContents(optionsArg: { contents: Buffer | string | plugins.stream.Readable; encoding?: 'utf8' | 'binary'; }) { if (optionsArg.contents instanceof plugins.stream.Readable) { await this.parentDirectoryRef.bucketRef.fastPutStream({ path: this.getBasePath(), dataStream: optionsArg.contents, }); } else if (Buffer.isBuffer(optionsArg.contents)) { await this.parentDirectoryRef.bucketRef.fastPut({ path: this.getBasePath(), contents: optionsArg.contents, }); } else if (typeof optionsArg.contents === 'string') { await this.parentDirectoryRef.bucketRef.fastPut({ path: this.getBasePath(), contents: Buffer.from(optionsArg.contents, optionsArg.encoding), }); } } /** * allows updating the metadata of a file * @param updatedMetadata */ public async getMetaData() { if (this.name.endsWith('.metadata')) { throw new Error('metadata files cannot have metadata'); } const metadata = await MetaData.createForFile({ file: this, }); return metadata; } /** * gets the contents as json */ public async getJsonData() { const json = await this.getContentsAsString(); const parsed = await JSON.parse(json); return parsed; } public async writeJsonData(dataArg: any) { await this.updateWithContents({ contents: JSON.stringify(dataArg), }); } }