@dr.pogodin/react-native-fs
Version:
Native filesystem access for React Native
331 lines (315 loc) • 12.4 kB
JavaScript
import { NativeEventEmitter } from 'react-native';
import RNFS from './ReactNativeFs';
import { decode, encode, normalizeFilePath, readFileGeneric, toEncoding } from './utils';
const nativeEventEmitter = new NativeEventEmitter(RNFS);
let lastJobId = 0;
// Internal functions.
/**
* Generic function used by readDir and readDirAssets.
*/
async function readDirGeneric(dirpath, command) {
const files = await command(normalizeFilePath(dirpath));
const {
FileTypeDirectory,
FileTypeRegular
} = RNFS.getConstants();
return files.map(file => ({
ctime: file.ctime && new Date(file.ctime * 1000) || null,
mtime: file.mtime && new Date(file.mtime * 1000) || null,
name: file.name,
path: file.path,
size: file.size,
isFile: () => file.type === FileTypeRegular,
isDirectory: () => file.type === FileTypeDirectory
}));
}
// Common exports.
export function appendFile(filepath, contents, encodingOrOptions) {
const b64 = encode(contents, toEncoding(encodingOrOptions));
return RNFS.appendFile(normalizeFilePath(filepath), b64);
}
export function copyFile(from, into, options = {}) {
return RNFS.copyFile(normalizeFilePath(from), normalizeFilePath(into), options);
}
export function downloadFile(options) {
if (typeof options !== 'object') {
throw new Error('downloadFile: Invalid value for argument `options`');
}
if (typeof options.fromUrl !== 'string') {
throw new Error('downloadFile: Invalid value for property `fromUrl`');
}
if (typeof options.toFile !== 'string') {
throw new Error('downloadFile: Invalid value for property `toFile`');
}
if (options.headers && typeof options.headers !== 'object') {
throw new Error('downloadFile: Invalid value for property `headers`');
}
if (options.background && typeof options.background !== 'boolean') {
throw new Error('downloadFile: Invalid value for property `background`');
}
if (options.progressDivider && typeof options.progressDivider !== 'number') {
throw new Error('downloadFile: Invalid value for property `progressDivider`');
}
if (options.progressInterval && typeof options.progressInterval !== 'number') {
throw new Error('downloadFile: Invalid value for property `progressInterval`');
}
if (options.readTimeout && typeof options.readTimeout !== 'number') {
throw new Error('downloadFile: Invalid value for property `readTimeout`');
}
if (options.connectionTimeout && typeof options.connectionTimeout !== 'number') {
throw new Error('downloadFile: Invalid value for property `connectionTimeout`');
}
if (options.backgroundTimeout && typeof options.backgroundTimeout !== 'number') {
throw new Error('downloadFile: Invalid value for property `backgroundTimeout`');
}
const jobId = ++lastJobId;
const subscriptions = [];
if (options.begin) {
subscriptions.push(nativeEventEmitter.addListener('DownloadBegin', res => {
if (res.jobId === jobId && options.begin) options.begin(res);
}));
}
if (options.progress) {
subscriptions.push(nativeEventEmitter.addListener('DownloadProgress', res => {
if (res.jobId === jobId && options.progress) options.progress(res);
}));
}
if (options.resumable) {
subscriptions.push(nativeEventEmitter.addListener('DownloadResumable', res => {
if (res.jobId === jobId && options.resumable) options.resumable(res);
}));
}
var nativeOptions = {
jobId: jobId,
fromUrl: options.fromUrl,
toFile: normalizeFilePath(options.toFile),
background: !!options.background,
backgroundTimeout: options.backgroundTimeout || 3600000,
// 1 hour
cacheable: options.cacheable ?? true,
connectionTimeout: options.connectionTimeout || 5000,
discretionary: !!options.discretionary,
headers: options.headers || {},
progressDivider: options.progressDivider || 0,
progressInterval: options.progressInterval || 0,
readTimeout: options.readTimeout || 15000,
hasBeginCallback: !!options.begin,
hasProgressCallback: !!options.progress,
hasResumableCallback: !!options.resumable
};
return {
jobId,
promise: (async () => {
try {
return await RNFS.downloadFile(nativeOptions);
} finally {
subscriptions.forEach(sub => sub.remove());
}
})()
};
}
export function exists(filepath) {
return RNFS.exists(normalizeFilePath(filepath));
}
export const getFSInfo = RNFS.getFSInfo;
export const isResumable = RNFS.isResumable;
export function mkdir(path, options = {}) {
return RNFS.mkdir(normalizeFilePath(path), options);
}
export function moveFile(filepath, destPath, options = {}) {
return RNFS.moveFile(normalizeFilePath(filepath), normalizeFilePath(destPath), options);
}
export function pickFile(options = {}) {
return RNFS.pickFile({
mimeTypes: options.mimeTypes || ['*/*']
});
}
export async function read(path,
// TODO: It would make more sense to read entire file by the default,
// or, if the position is given, to read from that position to the end.
length = 0, position = 0, encodingOrOptions) {
const b64 = await RNFS.read(normalizeFilePath(path), length, position);
return decode(b64, toEncoding(encodingOrOptions));
}
export function readFile(path, encodingOrOptions) {
return readFileGeneric(path, encodingOrOptions, RNFS.readFile);
}
export function readDir(dirpath) {
return readDirGeneric(dirpath, RNFS.readDir);
}
// Node style version (lowercase d). Returns just the names
export async function readdir(dirpath) {
const files = await RNFS.readDir(normalizeFilePath(dirpath));
return files.map(file => file.name || '');
}
export async function stat(filepath) {
const result = await RNFS.stat(normalizeFilePath(filepath));
const {
FileTypeDirectory,
FileTypeRegular
} = RNFS.getConstants();
return {
path: filepath,
ctime: new Date(result.ctime * 1000),
mtime: new Date(result.mtime * 1000),
size: result.size,
mode: result.mode,
originalFilepath: result.originalFilepath,
isFile: () => result.type === FileTypeRegular,
isDirectory: () => result.type === FileTypeDirectory
};
}
export const stopDownload = RNFS.stopDownload;
export function touch(filepath, mtime, ctime) {
if (ctime && !(ctime instanceof Date)) {
throw new Error('touch: Invalid value for argument `ctime`');
}
if (mtime && !(mtime instanceof Date)) {
throw new Error('touch: Invalid value for argument `mtime`');
}
return RNFS.touch(normalizeFilePath(filepath), {
ctime: ctime && ctime.getTime(),
mtime: mtime && mtime.getTime()
});
}
export function unlink(path) {
return RNFS.unlink(normalizeFilePath(path));
}
export function uploadFiles(options) {
const jobId = ++lastJobId;
const subscriptions = [];
if (typeof options !== 'object') {
throw new Error('uploadFiles: Invalid value for argument `options`');
}
if (typeof options.toUrl !== 'string') {
throw new Error('uploadFiles: Invalid value for property `toUrl`');
}
if (!Array.isArray(options.files)) {
throw new Error('uploadFiles: Invalid value for property `files`');
}
if (options.headers && typeof options.headers !== 'object') {
throw new Error('uploadFiles: Invalid value for property `headers`');
}
if (options.fields && typeof options.fields !== 'object') {
throw new Error('uploadFiles: Invalid value for property `fields`');
}
if (options.method && typeof options.method !== 'string') {
throw new Error('uploadFiles: Invalid value for property `method`');
}
if (options.begin) {
subscriptions.push(nativeEventEmitter.addListener('UploadBegin', options.begin));
} else if (options.beginCallback) {
// Deprecated
subscriptions.push(nativeEventEmitter.addListener('UploadBegin', options.beginCallback));
}
if (options.progress) {
subscriptions.push(nativeEventEmitter.addListener('UploadProgress', options.progress));
} else if (options.progressCallback) {
// Deprecated
subscriptions.push(nativeEventEmitter.addListener('UploadProgress', options.progressCallback));
}
var nativeOptions = {
jobId: jobId,
toUrl: options.toUrl,
files: options.files,
binaryStreamOnly: options.binaryStreamOnly || false,
headers: options.headers || {},
fields: options.fields || {},
method: options.method || 'POST',
hasBeginCallback: options.begin instanceof Function || options.beginCallback instanceof Function,
hasProgressCallback: options.progress instanceof Function || options.progressCallback instanceof Function
};
return {
jobId,
promise: RNFS.uploadFiles(nativeOptions).then(res => {
subscriptions.forEach(sub => sub.remove());
return res;
})
};
}
export function write(filepath, contents, position = -1, encodingOrOptions) {
const b64 = encode(contents, toEncoding(encodingOrOptions));
return RNFS.write(normalizeFilePath(filepath), b64, position);
}
export function writeFile(path, content, encodingOrOptions) {
const b64 = encode(content, toEncoding(encodingOrOptions));
return RNFS.writeFile(normalizeFilePath(path), b64, typeof encodingOrOptions === 'object' ? encodingOrOptions : {});
}
// Android-specific.
export function copyFileAssets(from, into) {
return RNFS.copyFileAssets(normalizeFilePath(from), normalizeFilePath(into));
}
export function copyFileRes(from, into) {
return RNFS.copyFileRes(from, normalizeFilePath(into));
}
export function existsAssets(filepath) {
return RNFS.existsAssets(filepath);
}
export function existsRes(filename) {
return RNFS.existsRes(filename);
}
export const getAllExternalFilesDirs = RNFS.getAllExternalFilesDirs;
// TODO: algorithm should have a dedicated type, effectively enumerating all
// correct values.
export function hash(filepath, algorithm) {
return RNFS.hash(normalizeFilePath(filepath), algorithm);
}
export async function readDirAssets(path) {
const res = await readDirGeneric(path, RNFS.readDirAssets);
return res;
}
export function readFileAssets(path, encodingOrOptions) {
return readFileGeneric(path, encodingOrOptions, RNFS.readFileAssets);
}
export function readFileRes(filename, encodingOrOptions) {
return readFileGeneric(filename, encodingOrOptions, RNFS.readFileRes);
}
export const scanFile = RNFS.scanFile;
// TODO: Not documented!
// setReadable for Android
export const setReadable = RNFS.setReadable;
// iOS-specific
export const completeHandlerIOS = RNFS.completeHandlerIOS;
// iOS only
// Copies fotos from asset-library (camera-roll) to a specific location
// with a given width or height
// @see: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset
export function copyAssetsFileIOS(imageUri, destPath, width, height, scale = 1.0, compression = 1.0, resizeMode = 'contain') {
return RNFS.copyAssetsFileIOS(imageUri, destPath, width, height, scale, compression, resizeMode);
}
// iOS only
// Copies fotos from asset-library (camera-roll) to a specific location
// with a given width or height
// @see: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset
export const copyAssetsVideoIOS = RNFS.copyAssetsVideoIOS;
// TODO: This is presumably iOS-specific, it is not documented,
// so it should be double-checked, what it does.
export const pathForBundle = RNFS.pathForBundle;
export const pathForGroup = RNFS.pathForGroup;
export const resumeDownload = RNFS.resumeDownload;
export const stopUpload = RNFS.stopUpload;
// Windows-specific.
// Windows workaround for slow copying of large folders of files
export function copyFolder(from, into) {
return RNFS.copyFolder(normalizeFilePath(from), normalizeFilePath(into));
}
const {
MainBundlePath,
CachesDirectoryPath,
ExternalCachesDirectoryPath,
DocumentDirectoryPath,
DownloadDirectoryPath,
ExternalDirectoryPath,
ExternalStorageDirectoryPath,
TemporaryDirectoryPath,
LibraryDirectoryPath,
PicturesDirectoryPath,
// For Windows
FileProtectionKeys,
RoamingDirectoryPath // For Windows
} = RNFS.getConstants();
export { MainBundlePath, CachesDirectoryPath, ExternalCachesDirectoryPath, DocumentDirectoryPath, DownloadDirectoryPath, ExternalDirectoryPath, ExternalStorageDirectoryPath, TemporaryDirectoryPath, LibraryDirectoryPath, PicturesDirectoryPath,
// For Windows
FileProtectionKeys, RoamingDirectoryPath // For Windows
};
//# sourceMappingURL=index.js.map