import IPostMessage from '../IPostMessage'; import { IStorageUnit, IFilePath, IFile, IHeaders, ICopyFileOptions, IMoveFileOptions, ExtractMethodType } from './types'; import StorageUnitsChangedMessage from './StorageUnitsChangedMessage'; import IFileSystem from './IFileSystem'; import { HashAlgorithm } from './HashAlgorithm'; /** * The `sos.fileSystem` API groups together methods for low-level access to the file system. The File System API supports both internal and * external storage. * * :::warning Differences between File System API and Offline Cache API * File System directory structure is **PERSISTENT** and is **NOT** automatically deleted through `Applet Reload` power action! * Applet Reload only deletes `/data` directory which is reserved for simplified [Offline Cache API](./offline). Use * `deleteFile()` to clear the device storage file system. * ::: * * :::info GitHub Example * - [Example usage of File System API in Applet](https://github.com/signageos/applet-examples/tree/master/examples/content-js-api/file-system) * ::: * *
* Device File System Capabilities * | Capability | Description | * |:------------|:-------------| * | `FILE_SYSTEM_INTERNAL_STORAGE` | If device supports internal storage units | * | `FILE_SYSTEM_EXTERNAL_STORAGE` | If device supports connecting external storage units | * | `FILE_SYSTEM_FILE_CHECKSUM` | If device supports checksum for MD5 or CRC32 hash algorithms | * | `FILE_SYSTEM_LINK` | If device supports creating hard links to files | * | `FILE_SYSTEM_CREATE_ARCHIVE` | If device supports creating archives - zip | * | `FILE_SYSTEM_ARCHIVE_EXTRACT_INFO` | If device supports extracting information about archive files | * * If you want to check if the device supports this capability, use [`sos.display.supports()`](https://developers.signageos.io/sdk/sos/display#supports). *
* * * ## Storing files permanently * To allow more low-level file operations, the applet SDK exposes the File System API. Files created using this API are permanent and are only removed on a factory reset or file system wipeout. * The file system is also shared between all applets, which means you cannot rely on any file system structure on startup because a different applet on the device could have saved files you didn't expect. * To mitigate this issue, create a directory for your applet and save all files inside it. * * @example * import sos from '@signageos/front-applet'; * * sos.onReady(async () => { * const storageUnits = await sos.fileSystem.listStorageUnits(); * const rootPath = { * filePath: '', // Empty string is used as an absolute path instead of "/" * storageUnit: storageUnits.find((s) => !s.removable), // Find internal storage * }; * * // This will return files previous applets saved to the device * const files = await sos.fileSystem.listFiles(rootPath); * }); */ export default class FileSystem implements IFileSystem { private messagePrefix; private postMessage; static MESSAGE_PREFIX: string; private eventEmitter; /** @internal */ constructor(messagePrefix: string, postMessage: IPostMessage); /** * The `listStorageUnits()` method lists all available storage units. All devices always have one internal storage device (with * `removable: false`) and zero or more external devices. The capacity values are in bytes. * * :::note * This is a mandatory method that is required for all the other File System APIs. The other APIs require a storageUnit object that is retrieved from this method to manipulate with files on a correct storage location (internal/external). * ::: * * :::warning * `storageUnit` is a dynamic object! It has to be always generated and retrieved by this JS API, as the values in type differ platform by platform. Never generate the object manually. `{"type":"internal"}` is for demonstration only. * ::: * * @returns {Promise} An array of storage units available on the device. * @throws InternalFileSystemError Unexpected error occurred when listing storage units. * @since 2.1.0 * * @example * // Storage units are equivalent to disk volumes (C:, D: etc on Windows; /mnt/disc1, /mnt/disc2 on Unix) * const storageUnits = await sos.fileSystem.listStorageUnits(); * const externalStorageUnits = storageUnits.filter((storageUnit) => storageUnit.removable); * externalStorageUnits.forEach((storageUnit) => { * console.log(`Storage Unit Type: ${storageUnit.type}`); * console.log(`Capacity: ${storageUnit.capacity} bytes`); * }); */ listStorageUnits(): Promise; /** * A shorthand method for listing only the internal storage units (i.e., those with the `removable: false`). The capacity values are in bytes. * * @returns {Promise} An array of internal storage units available on the device. * @since 7.0.0 * * @example * // List internal storage units * const internalStorageUnits = await sos.fileSystem.listInternalStorageUnits(); * internalStorageUnits.forEach((storageUnit) => { * console.log(`Storage Unit Type: ${storageUnit.type}`); * console.log(`Capacity: ${storageUnit.capacity} bytes`); * console.log(`Free Space: ${storageUnit.freeSpace} bytes`); * console.log(`Usable Space: ${storageUnit.usableSpace} bytes`); * }); */ listInternalStorageUnits(): Promise; /** * The `onStorageUnitsChanged()` method sets up a listener, which is called whenever the list of storage units changes. * * @param listener The listener function to be called when the storage units change. * @throws Error If `listener` is not a valid function. * @since 2.1.0 */ onStorageUnitsChanged(listener: () => void): void; /** * The `removeStorageUnitsChangedListener()` method removes a listener, previously added by `onStorageUnitsChanged()` */ removeStorageUnitsChangedListener(listener: () => void): void; /** * The `removeAllListeners()` method removes all listeners, previously added by `onStorageUnitsChanged()` */ removeAllListeners(): void; /** * The `listFiles()` method lists all files and directories in the specified path (nested files are not included). * * @param directoryPath The path to the directory where files will be listed. * @returns {Promise} A promise that resolves to an array of file paths in the specified directory. * @throws Error If `directoryPath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the path does not exist, or it is a file. * @since 2.1.0 * * @example * // List files in the root directory of the internal storage unit * const internalStorageUnit = (await sos.fileSystem.listInternalStorageUnits())[0]; * const directoryPath = { * storageUnit: internalStorageUnit, * filePath: '', // Empty string is used as an absolute path instead of "/" * }; * * const files = await sos.fileSystem.listFiles(directoryPath); * console.log('Files in the root directory:', files.length); * files.forEach((file) => { * console.log(`File: ${file.filePath}`); * }); */ listFiles(directoryPath: IFilePath): Promise; /** * The `exists()` method checks whether a file or directory exists. * * @param filePath The path to the file or directory to check. * @returns {Promise} A promise that resolves to `true` if the file or directory exists, `false` otherwise. * @throws Error If the `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If any error occurs during the existence check operation on the device. * @since 2.1.0 * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const fileExists = await sos.fileSystem.exists(filePath); * console.log(`File exists: ${fileExists}`); // Prints true if the file exists, false otherwise */ exists(filePath: IFilePath): Promise; /** * The `getFile()` method returns runtime information about a file path, such as local url, last modified date or size. * * :::warning * Return statement is a dynamic object! It has to be always generated and retrieved by this JS API, as the values in localUri differ platform by platform. Never generate the object manually. `{"localUri":"file://internal/path/to/file.txt"}` is for demonstration only. * ::: * * @param filePath The path to the file to be retrieved. * @returns {Promise} A promise that resolves to the file information or `null` if the file does not exist. * @throws Error If the `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the file is a directory. * @throws Error If any error occurs during the retrieval operation on the device. * @since 2.1.0 * * @example * // Get file information * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const fileInfo = await sos.fileSystem.getFile(filePath); * console.log(JSON.stringify(fileInfo)); // Prints the file information * console.log(fileInfo.localUri); // Prints the local URI of the file */ getFile(filePath: IFilePath): Promise; /** * The `writeFile()` method writes string content to the file specified by `filePath`. If the file does exist, it is created. * * @param filePath The path to the file to be written. * @param contents The content to be written to the file. * @returns {Promise} A promise that resolves when the content is written successfully. * @throws Error If the parent directory does not exist or the `filePath` is a directory. * @throws Error If the `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If any error occurs during the write operation on the device. * @since 3.2.0 * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const contents = 'This is the content to write to the file.'; * await sos.fileSystem.writeFile(filePath, contents); */ writeFile(filePath: IFilePath, contents: string): Promise; /** * The `appendFile()` method appends string content to the file specified by `filePath`. * If the file does exist, it is created. * * :::note * Only string can be appended to the file. If you want to append binary data, you have to convert it to a string first. * ::: * * @param filePath The path to the file to be appended. * @param contents The content to be appended to the file. * @returns {Promise} A promise that resolves when the content is appended successfully. * @throws Error If the parent directory does not exist. * @throws Error If the `filePath` is a directory. * @throws Error If the `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If any error occurs during the append operation on the device. * @since * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const contents = 'This is the content to append to the file.'; * await sos.fileSystem.appendFile(filePath, contents); */ appendFile(filePath: IFilePath, contents: string): Promise; /** * The `readFile()` method returns content of the file specified by `filePath`. * The file has to be a text file, otherwise the content will be mangled. * * @param filePath The path to the file to be read. * @returns {Promise} A promise that resolves to the content of the file. * @throws Error If the file does not exist. * @throws Error If the `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the file is a directory. * @throws Error If any error occurs during the read operation on the device. * @since 3.3.0 * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const fileContent = await sos.fileSystem.readFile(filePath); * console.log(`Content of the file: ${fileContent}`); */ readFile(filePath: IFilePath): Promise; /** * The `copyFile()` method creates a copy of file from `sourceFilePath` to `destinationFilePath`. * * @param sourceFilePath The path to the file to be copied. * @param destinationFilePath The path where the file will be copied to. * @param options Options for copying the file. * @param options.overwrite If set to `true`, the method will overwrite the destination file if it already exists. * @returns {Promise} A promise that resolves when the file is copied successfully. * @throws Error If the source file does not exist. * @throws Error If parent of the destination file path does not exist. * @throws Error If `options` object is not valid. * @throws Error If any error occurs during the copy operation on the device. * @since 2.1.0 * * @example * // Copy file from one directory to another and overwrite it if it already exists * const sourceFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/source/file.txt', * }; * * const destinationFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/destination/file.txt', * }; * * await sos.fileSystem.copyFile(sourceFilePath, destinationFilePath, { overwrite: true }); */ copyFile(sourceFilePath: IFilePath, destinationFilePath: IFilePath, options?: ICopyFileOptions): Promise; /** * The `moveFile()` method moves a file from `sourceFilePath` to `destinationFilePath`. * * @param sourceFilePath The path to the file to be moved. * @param destinationFilePath The path where the file will be moved to. * @param options Options for moving the file. * @param options.overwrite If set to `true`, the method will overwrite the destination file if it already exists. * @returns {Promise} A promise that resolves when the file is moved successfully. * @throws Error If the source file does not exist or parent of the destination file path does not exist. * @throws Error If the `options.overwrite` is not set and the destination file path already exists. * @throws Error If deleting path does not exist. * @throws Error If any error occurs during the move operation on the device. * @since 2.1.0 * * @example * // Move file from one directory to another and overwrite it if it already exists * const sourceFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/source/file.txt', * }; * * const destinationFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/destination/file.txt', * }; * * await sos.fileSystem.moveFile(sourceFilePath, destinationFilePath, { overwrite: true }); */ moveFile(sourceFilePath: IFilePath, destinationFilePath: IFilePath, options?: IMoveFileOptions): Promise; /** * The `deleteFile()` method deletes the file specified by `filePath`. * * @param filePath The path to the file or directory to be deleted. * @param recursive If set to `true`, the method will delete the directory and all its contents recursively. * @returns {Promise} A promise that resolves when the file is deleted successfully. * @throws Error If `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the file does not exist or if `recursive` is set to false and the file path is a directory. * @throws Error If deleting path does not exist. * @throws Error When is deleting directory and is not empty (not recursive). * @since 2.1.0 * * @example * // Delete directory and all files inside * //// First check, if there is such a directory * if (await sos.fileSystem.exists({ storageUnit: internalStorageUnit, filePath: 'test-dir' })) { * // Delete the directory and all it's content recursively * await sos.fileSystem.deleteFile({ storageUnit: internalStorageUnit, filePath: 'test-dir' }, true); * } * * // Delete file * //// First check, if there is such a file * if (await sos.fileSystem.exists({ storageUnit: internalStorageUnit, filePath: 'test-dir/downloaded-file.png' })) { * // Delete the file * await sos.fileSystem.deleteFile({ storageUnit: internalStorageUnit, filePath: 'test-dir/downloaded-file.png' }, false); * } */ deleteFile(filePath: IFilePath, recursive: boolean): Promise; /** * The `downloadFile()` method download a file from `sourceUri` and saves it to the specified path. If the file already exists, the file will be * overwritten. Optionally, headers for the download request may be specified. * * :::danger * For every download request, our Core Apps makes HEAD request for `content-length` header on that downloaded file. It's due to determining if device has enough space to download the file. * ::: * * #### Encoding * All downloads respect a standard of `Encoding` with optional compression of files. See [Mozilla standard Accept Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) and [Content Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding). * * Download file method is always sending optional following headers: * ``` * Accept-Encoding: gzip * Accept-Encoding: compress * Accept-Encoding: deflate * Accept-Encoding: br * Accept-Encoding: identity * Accept-Encoding: * * ``` * * If the server understands the `Encoding` standard, it compresses files using `gzip` algorithm before the files are sent to the client. If so, the response will contain the following headers: * ``` * Content-Encoding: gzip * Content-Encoding: compress * Content-Encoding: deflate * Content-Encoding: br * ``` * So the data communication is compressed under the hood. The client will automatically decompress data before it's saved to a specified location path. So from JS API point of view, there is no requirement to decompress data by itself. * * The standard is supported on all following platforms: * * - WebOS 3+ * - Tizen 2.4+ * - Brightsign * - Raspberry Pi * - Windows * * @param filePath The path where the downloaded file will be saved. * @param sourceUri The URI of the file to be downloaded. * @param headers Key, value pairs of HTTP headers to send along with the request. Used when the target file is protected by a password or if any * @returns {Promise} A promise that resolves when the file is downloaded successfully. * @throws Error If `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If `sourceUri` is not a valid URI. * @throws Error If `headers` is not a valid object. * @throws Error If the parent directory of `filePath` does not exist. * @throws Error If the network request fails. * @since 2.1.0 * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/downloaded/file.zip', * }; * const sourceUri = 'https://example.com/path/to/file.zip'; * const headers = { * 'Authorization': 'Bearer your_token_here', * }; * await sos.fileSystem.downloadFile(filePath, sourceUri, headers); */ downloadFile(filePath: IFilePath, sourceUri: string, headers?: IHeaders): Promise; /** * The `extractFile()` method extract (recursively) the archive file at `archiveFilePath` into a new file specified by `destinationDirectoryPath`. * * :::note * - The directory/folder you are extracting your ZIP file into has to be created BEFORE you start extracting the ZIP. * - Only supported extract method is `zip`. * ::: * * @param archiveFilePath The path to the archive file to be decompressed. * @param destinationDirectoryPath The path to the directory where the decompressed files will be saved. * @param method Extract method to use for extracting, e.g. 'zip'. * @throws Error If the archive file path does not exist. * @throws Error If it is not a valid archive file. * @throws Error If destination directory does not exist. * @since 2.1.0 * * @example * const archiveFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/archive.zip', * }; * * const destinationDirectoryPath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/destination/directory', * }; * * await sos.fileSystem.extractFile(archiveFilePath, destinationDirectoryPath, 'zip'); */ extractFile(archiveFilePath: IFilePath, destinationDirectoryPath: IFilePath, method: ExtractMethodType): Promise; /** * The `createArchive()` method creates an archive file from selected files and directories. * * :::warning * - Never start OR end the `filePath` with a slash - `/`. * - It is a good practice to check if file exists - `exists()` prior creating it * ::: * * :::info * - This function is available only on Tizen devices. * - All files are added to the archive based on absolute path from root directory. * ::: * * @param archiveFilePath The path where the archive file will be created. * @param archiveEntries An array of file paths to be included in the archive. * @returns {Promise} A promise that resolves when the archive file is created successfully. * @throws Error If `archiveFilePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If `archiveEntries` is not a valid array of objects. * @throws Error If the parent directory of `archiveFilePath` does not exist. * @throws Error If any of the `archiveEntries` do not exist or are directories. * @throws Error If creating the archive file fails. * @throws Error If the platform does not support creating archive files. * @since 5.12.0 * * @example * const archiveFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/archive.zip', * }; * * const archiveEntries = [ * { * storageUnit: internalStorageUnit, * filePath: 'path/to/file1.txt', * }, * { * storageUnit: internalStorageUnit, * filePath: 'path/to/file2.txt', * }, * { * storageUnit: internalStorageUnit, * filePath: 'path/to/directory1', * }, * ]; * * await sos.fileSystem.createArchive(archiveFilePath, archiveEntries); */ createArchive(archiveFilePath: IFilePath, archiveEntries: IFilePath[]): Promise; /** * The `getChecksumFile()` method computes a checksum of the file specified by `filePath`. * * :::warning Tizen limitation * If you are about to use the MD5 file validation it will automatically return on any Samsung Tizen - 2.4, 3.0 and 4.0. * Reason: MD5 file checksum is not available on any Tizen displays due to the Samsung restriction. * ::: * * @param filePath The path to the file for which the checksum will be computed. * @param hashType The type of hash algorithm to use for computing the checksum. * @returns {Promise} A promise that resolves to the computed checksum of the file. * @throws Error If `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If `hashType` is not a valid type or string. * @throws Error If the file does not exist. * @throws Error If `filepath` it is a directory * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/file.txt', * }; * * const checksum = await sos.fileSystem.getFileChecksum(filePath, 'md5'); * console.log(`Checksum of the file: ${checksum}`); */ getFileChecksum(filePath: IFilePath, hashType: HashAlgorithm): Promise; /** * The `createDirectory()` method create a new directory at specified path. * * :::warning * - Never start OR end the filePath with a slash - `/`. * - It is a good practice to check if directory exists - `isDirectory()` prior creating it. * ::: * * @param directoryPath The path where the new directory will be created. * @returns {Promise} A promise that resolves when the directory is created successfully. * @throws Error If `directoryPath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the directory already exists. * @throws Error If parent directory does not exist. * @since 2.1.0 * * @example * const internalStorageUnit = (await sos.fileSystem.listInternalStorageUnits())[0]; * const directoryPath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/new/directory', * }; * * await sos.fileSystem.createDirectory(directoryPath); */ createDirectory(directoryPath: IFilePath): Promise; /** * The `isDirectory()` method checks whether the file path points to a directory. * * @param filePath The file path to check. * @returns {Promise} A promise that resolves to `true` if the file path is a directory, `false` otherwise. * @throws Error If `filePath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the file path does not exist. * @since 2.1.0 * * @example * const filePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/directory', * }; * const isDir = await sos.fileSystem.isDirectory(filePath); * if (isDir) { * console.log('The file path is a directory.'); * } else { * console.log('The file path is not a directory.'); * } */ isDirectory(filePath: IFilePath): Promise; /** * The `link()` method creates a symbolic link from `sourceFilePath` (existing path) to `destinationFilePath` (new path). * * :::note * This method is only available on Linux devices. * ::: * * @param sourceFilePath The path to the existing file or directory that you want to link to. * @param destinationFilePath The path where the symbolic link will be created. * @throws Error If `sourceFilePath` or `destinationPath` is not a valid object or does not contain `storageUnit` and `filePath`. * @throws Error If the `sourceFilePath` does not exist or if the `destinationFilePath` already exists. * @throws Error The platform does not support linking directories. * @returns {Promise} A promise that resolves when the symbolic link is created successfully. * @since 4.0.0 * * @example * const internalStorageUnit = (await sos.fileSystem.listInternalStorageUnits())[0]; * const sourceFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/existing/file.txt', * }; * * const destinationFilePath = { * storageUnit: internalStorageUnit, * filePath: 'path/to/symlink/file_link.txt', * }; * * await sos.fileSystem.link(sourceFilePath, destinationFilePath); */ link(sourceFilePath: IFilePath, destinationFilePath: IFilePath): Promise; /** * The `wipeout()` method is used to wipe out all data from the file system. * * :::danger * - Ensure that function is called only once, otherwise it will wipe out the file system again on applet or device start! * - This function is clearing internal file system storage, cache storage and cookies. Local storage will not be cleared. * ::: * * @returns {Promise} A promise that resolves when the wipeout is complete. * * @example * await sos.fileSystem.wipeout().then(() => { * console.log('File system wiped out successfully.'); * await sos.management.power.systemReboot(); // Reboot the device after wipeout * }).catch((error) => { * console.error('Error wiping out file system:', error); * }); */ wipeout(): Promise; /** @internal */ handleMessageData(data: StorageUnitsChangedMessage): void; private getMessage; }