UNPKG

@hashgraph/solo

Version:

An opinionated CLI tool to deploy and manage private Hedera Networks.

129 lines (110 loc) 4.36 kB
// SPDX-License-Identifier: Apache-2.0 import {type StorageBackend} from '../api/storage-backend.js'; import {StorageOperation} from '../api/storage-operation.js'; import {type Stats, statSync, lstatSync, readdirSync, writeFileSync, unlinkSync} from 'node:fs'; import {StorageBackendError} from '../api/storage-backend-error.js'; import {IllegalArgumentError} from '../../../core/errors/illegal-argument-error.js'; import {readFileSync} from 'node:fs'; import {PathEx} from '../../../business/utils/path-ex.js'; /** * A file storage backend that operates on files within a specified base path. This backend does not support recursive * operations into subfolders and only operates on files contained within the specified base path. All directory entries * are ignored. */ export class FileStorageBackend implements StorageBackend { /** * Creates a new file storage backend bound to the specified base path. The basic file storage backend does not support * recursive operations into subfolders and only operates on files contained within the specified base path. * All directory entries are ignored. * * @param basePath - The base path to use for all file operations. * @throws IllegalArgumentError if the base path is null, undefined, or empty. * @throws StorageBackendError if the base path does not exist or is not a directory. */ public constructor(public readonly basePath: string) { if (!basePath || basePath.trim().length === 0) { throw new IllegalArgumentError('basePath must not be null, undefined or empty'); } let stats: Stats; try { stats = lstatSync(basePath); } catch (error) { throw new StorageBackendError('basePath must exist and be valid', error); } if (!stats || !stats.isDirectory()) { throw new StorageBackendError(`basePath must be a valid directory: ${basePath}`); } } public isSupported(op: StorageOperation): boolean { switch (op) { case StorageOperation.List: case StorageOperation.ReadBytes: case StorageOperation.WriteBytes: case StorageOperation.Delete: { return true; } default: { return false; } } } public async list(): Promise<string[]> { try { const entries: string[] = readdirSync(this.basePath, {encoding: 'utf8', recursive: false}); if (entries.length === 0) { return []; } return entries.filter((item): boolean => statSync(PathEx.join(this.basePath, item))?.isFile()); } catch (error) { throw new StorageBackendError('Error listing files in base path', error); } } public async readBytes(key: string): Promise<Buffer> { if (!key || key.trim().length === 0) { throw new IllegalArgumentError('key must not be null, undefined or empty'); } const filePath: string = PathEx.join(this.basePath, key); try { return readFileSync(filePath); } catch (error) { throw new StorageBackendError(`error reading file: ${filePath}`, error); } } public async writeBytes(key: string, data: Buffer): Promise<void> { if (!key || key.trim().length === 0) { throw new IllegalArgumentError('key must not be null, undefined or empty'); } if (!data) { throw new IllegalArgumentError('data must not be null or undefined'); } const filePath: string = PathEx.join(this.basePath, key); try { writeFileSync(filePath, data, {flag: 'w'}); } catch (error) { throw new StorageBackendError(`error writing file: ${filePath}`, error); } } public async delete(key: string): Promise<void> { if (!key || key.trim().length === 0) { throw new IllegalArgumentError('key must not be null, undefined or empty'); } const filePath: string = PathEx.join(this.basePath, key); let stats: Stats; try { stats = statSync(filePath); } catch (error) { throw new StorageBackendError(`file not found or is not readable: ${filePath}`, error); } if (!stats) { throw new StorageBackendError(`file not found: ${filePath}`); } if (!stats.isFile()) { throw new StorageBackendError(`path is not a file: ${filePath}`); } try { unlinkSync(filePath); } catch (error) { throw new StorageBackendError(`error deleting file: ${filePath}`, error); } } }