import API from './ecosystem-base.js';
import {Logger} from './../function/log-helper.js';
import {ErrorCode} from '../exception/exceptionDesc.js';
import {InfoType, WarningType} from '../information/informationCode.js';
export const factoryApiFile = function (f) {
const logModule = 'ecosystem-file';
/**
* The API.FILESYSTEM class provides a set of interfaces for managing the file system on the controller.
* It includes methods for retrieving file and directory contents, creating, updating, and deleting files or directories, and checking file existence.
* This class simplifies file system operations, enabling developers to efficiently interact with and manage files on the controller.
* @alias API.FILESYSTEM
* @namespace
*/
f.FILESYSTEM = new (function () {
const fixPath = function (path) {
return `${path.replace(/^HOME/, '$HOME').replace(/:$/, '')}/`;
};
const _getFile = async function (path) {
return await RWS.FileSystem.getFile(path);
};
const _getDirectory = async function (path) {
return await RWS.FileSystem.getDirectory(path);
};
/**
* Gets the content of a directory with specified path
* @alias getDirectoryContents
* @memberof API.FILESYSTEM
* @param {string} path Path to the file, including file name
* @example
* // Get the content of the TEMP directory of controller
* await API.FILESYSTEM.getDirectoryContents("$TEMP")
*/
this.getDirectoryContents = async function (path = '$HOME') {
try {
var directory = await _getDirectory(path);
var contents = await directory.getContents();
let names = {directories: [], files: []};
for (let item of contents.directories) {
names.directories.push(item.name);
}
for (let item of contents.files) {
names.files.push(item.name);
}
return names;
} catch (e) {
return API.rejectWithStatus(`Failed to get content of ${path} directory`, e, {
errorCode: ErrorCode.FailedToGetDirectoryContents,
});
}
};
/**
* Get the content of a file with specified path
* @alias getFile
* @memberof API.FILESYSTEM
* @param {string} path Path to the file, optional - including file name
* @param {string} file Name of the file
* @example
* // Get the file content of the file EIO.cfg in Home directory
* await API.FILESYSTEM.getFile("$HOME","EIO.cfg")
*/
this.getFile = async function (path, file) {
let url = `${path.replace(/:$/, '').replace(/^HOME/, '$HOME')}${file ? `/${file}` : ''}`;
try {
let f = await RWS.FileSystem.getFile(url);
return await f.getContents();
} catch (e) {
return API.rejectWithStatus(`Failed to get content of ${url}.`, e, {
errorCode: ErrorCode.FailedToGetFileContent,
});
}
};
/**
* Get a list of files objects including name and content
* @alias getFiles
* @memberof API.FILESYSTEM
* @param {string} path Path to the file, including file name
* @returns {Promise<object[]>} - Array of file objects [ {name, content}]
* @example
* await API.FILESYSTEM.getFiles("$HOME")
*/
this.getFiles = async function (path) {
try {
const directory = await _getDirectory(path);
const directoryContent = await directory.getContents();
const data = [];
for (let i = 0; i < directoryContent.files.length; i++) {
const name = directoryContent.files[i].name;
const file = await _getFile(`${path}/${name}`);
const fileContent = await file.getContents();
data.push({name, content: JSON.parse(fileContent)});
}
return data;
} catch (e) {
return API.rejectWithStatus(`Failed to get file list in path ${path}`, e, {
errorCode: ErrorCode.FailedToGetFileList,
});
}
};
/**
* Update the file content
* @alias updateFile
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @param {string} fileName fileName
* @param {string} data content to be updated
* @returns {Promise<object[]>} - Array of file objects [ {name, content}]
* @example
* await API.FILESYSTEM.updateFile("$HOME","test.txt","testcontent")
*/
this.updateFile = async function (directoryPath, fileName, data) {
try {
const file = await _getFile(`${directoryPath}/${fileName}`);
const setContentStatus = await file.setContents(data);
if (setContentStatus) {
return await file.save(true);
}
return API.rejectWithStatus('Error while updating file content', {}, {errorCode: ErrorCode.FailedToUpdateFile});
} catch (e) {
return API.rejectWithStatus('Error while updating file content', e, {errorCode: ErrorCode.FailedToUpdateFile});
}
};
/**
* Creates a new directory.
* @alias createDirectory
* @memberof API.FILESYSTEM
* @param {string} directoryPath The directory path
* @example
* await API.FILESYSTEM.createDirectory("$HOME/testFolder")
*/
this.createDirectory = async function (directoryPath) {
let dir = directoryPath.replace(/:$/, '').replace(/^HOME/, '$HOME');
let parts = dir.split('/');
let pathSoFar = '$HOME';
let startIndex = parts[0] === '$HOME' ? 1 : 0;
for (let i = startIndex; i < parts.length; i++) {
pathSoFar += '/' + parts[i];
try {
await RWS.FileSystem.createDirectory(pathSoFar);
} catch (e) {
if (e && e.httpStatus && e.httpStatus.code == 409) {
// the directory is already created
Logger.w(WarningType.FileOperation, `The directory ${pathSoFar} to be created already existed`);
} else {
return API.rejectWithStatus(`Failed to create ${pathSoFar} directory`, e, {
errorCode: ErrorCode.FailedToCreateDirectory,
});
}
}
}
};
/**
* Create a new file
* @alias createNewFile
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @param {string} fileName file name
* @param {string} data data content
* @param {boolean} overwrite Overwrite if the file already exists
* @example
* await API.FILESYSTEM.createNewFile("$HOME", "test.txt", "test new", true)
*/
this.createNewFile = async function (directoryPath, fileName, data, overwrite = false) {
try {
const directory = await _getDirectory(directoryPath);
const newFile = await directory.createFileObject(fileName);
const fileExists = await newFile.fileExists();
if (fileExists) {
if (overwrite) await this.updateFile(directoryPath, fileName, data);
else
throw new Error(ErrorCode.FailedToCreateFile, {
cause: `Create new file failed since file already exists and overwrite parameter is set to false.`,
});
} else {
const setContentStatus = await newFile.setContents(data);
if (setContentStatus) {
return await newFile.save(false);
}
}
} catch (e) {
return API.rejectWithStatus(` Failed to create ${directoryPath}/${fileName} file`, e, {
errorCode: ErrorCode.FailedToCreateFile,
});
}
};
/**
* Detect if the file already exists
* @alias fileExists
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @param {string} fileName file name
* @returns {Promise<boolean>} - true if the file exists, false otherwise
*
* @example
* const fileExists = await API.FILESYSTEM.fileExists("$HOME", "test.txt")
*/
this.fileExists = async function (directoryPath, fileName) {
try {
const directory = await _getDirectory(directoryPath);
const newFile = directory.createFileObject(fileName);
return await newFile.fileExists();
} catch (e) {
return false;
}
};
/**
* Delete file
* @alias deleteFile
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @param {string} fileName file name
* @example
* await API.FILESYSTEM.deleteFile("$HOME", "test.txt")
*/
this.deleteFile = async function (directoryPath, fileName) {
try {
const file = await _getFile(`${directoryPath}${fileName ? `/${fileName}` : ''}`);
return await file.delete();
} catch (e) {
return API.rejectWithStatus(`Failed to delete ${directoryPath}/${fileName} file`, e, {
errorCode: ErrorCode.FailedToDeleteFile,
});
}
};
/**
* Delete directory
* @alias deleteDirectory
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @example
* await API.FILESYSTEM.deleteDirectory("$HOME/testFolder")
*/
this.deleteDirectory = async function (directoryPath) {
try {
const dir = await _getDirectory(directoryPath);
return await dir.delete();
} catch (error) {
if (error.controllerStatus && error.controllerStatus.code == '-1073438713') {
Logger.w(WarningType.FileOperation, 'Cannot delete inexisted directory');
return;
}
return API.rejectWithStatus(
`Failed to delete ${directoryPath}, the possible cause can be the directory does not exist or the user does not own required grants`,
error,
{errorCode: ErrorCode.FailedToDeleteDirectory},
);
}
};
/**
* Delete all directories and files in a directory
* @alias deleteDirectoryContent
* @memberof API.FILESYSTEM
* @param {string} directoryPath directory path
* @example
* await API.FILESYSTEM.deleteDirectoryContent("$HOME/testFolder")
*/
this.deleteDirectoryContent = async function (directoryPath) {
try {
const dirContent = await this.getDirectoryContents(directoryPath);
if (!dirContent) return;
if (dirContent.directories && dirContent.directories.length > 0) {
for (const dir of dirContent.directories) {
const dirObject = await _getDirectory(`${directoryPath}/${dir}`);
await dirObject.delete();
}
}
for (let file of dirContent.files) {
await API.FILESYSTEM.deleteFile(directoryPath, file);
}
} catch (e) {
return API.rejectWithStatus(`Deleting content of ${directoryPath} directory failed`, e, {
errorCode: ErrorCode.FailedToDeleteDirectoryContent,
});
}
};
/**
* Recursively copies a file or directory (including all subdirectories and files).
* @alias copy
* @memberof API.FILESYSTEM
* @param {string} source Source path
* @param {string} destination Destination path
* @param {boolean} overwrite Overwrites the directory or file if it already exists in the destination path.
* @example
* await API.FILESYSTEM.copy("$HOME/EIO.cfg","$HOME/WebApps/EIO.cfg")
*/
this.copy = async function (source, destination, overwrite = false) {
const srcFile = RWS.FileSystem.createFileObject(source);
const destFile = RWS.FileSystem.createFileObject(destination);
if ((await destFile.fileExists()) && !overwrite) {
return API.rejectWithStatus(
`Copy file failed since destination file already exists and the overwrite parameter is set to false.`,
{},
{errorCode: ErrorCode.FailedToCopyFile},
);
}
return await srcFile.copy(destination, overwrite, false);
};
})();
f.constructedFile = true;
};
if (typeof API.constructedFile === 'undefined') {
factoryApiFile(API);
}
export default API;