@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
118 lines • 4.56 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
import { StorageOperation } from '../api/storage-operation.js';
import { 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 {
basePath;
/**
* 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.
*/
constructor(basePath) {
this.basePath = basePath;
if (!basePath || basePath.trim().length === 0) {
throw new IllegalArgumentError('basePath must not be null, undefined or empty');
}
let 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}`);
}
}
isSupported(op) {
switch (op) {
case StorageOperation.List:
case StorageOperation.ReadBytes:
case StorageOperation.WriteBytes:
case StorageOperation.Delete: {
return true;
}
default: {
return false;
}
}
}
async list() {
try {
const entries = readdirSync(this.basePath, { encoding: 'utf8', recursive: false });
if (entries.length === 0) {
return [];
}
return entries.filter((item) => statSync(PathEx.join(this.basePath, item))?.isFile());
}
catch (error) {
throw new StorageBackendError('Error listing files in base path', error);
}
}
async readBytes(key) {
if (!key || key.trim().length === 0) {
throw new IllegalArgumentError('key must not be null, undefined or empty');
}
const filePath = PathEx.join(this.basePath, key);
try {
return readFileSync(filePath);
}
catch (error) {
throw new StorageBackendError(`error reading file: ${filePath}`, error);
}
}
async writeBytes(key, data) {
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 = PathEx.join(this.basePath, key);
try {
writeFileSync(filePath, data, { flag: 'w' });
}
catch (error) {
throw new StorageBackendError(`error writing file: ${filePath}`, error);
}
}
async delete(key) {
if (!key || key.trim().length === 0) {
throw new IllegalArgumentError('key must not be null, undefined or empty');
}
const filePath = PathEx.join(this.basePath, key);
let 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);
}
}
}
//# sourceMappingURL=file-storage-backend.js.map