react-native-blob-util
Version:
A module provides upload, download, and files access API. Supports file stream read/write for process large files.
481 lines (442 loc) • 16.1 kB
JavaScript
// Copyright 2016 wkh237@github. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
// import type {ReactNativeBlobUtilConfig, ReactNativeBlobUtilNative, ReactNativeBlobUtilStream} from './types'
import {Platform} from 'react-native';
import ReactNativeBlobUtilSession from './class/ReactNativeBlobUtilSession';
import ReactNativeBlobUtilWriteStream from './class/ReactNativeBlobUtilWriteStream';
import ReactNativeBlobUtilReadStream from './class/ReactNativeBlobUtilReadStream';
import ReactNativeBlobUtilFile from './class/ReactNativeBlobUtilFile';
import ReactNativeBlobUtil from './codegenSpecs/NativeBlobUtils';
const constants = ReactNativeBlobUtil.getConstants();
const dirs = {
DocumentDir: constants.DocumentDir,
CacheDir: constants.CacheDir,
PictureDir: constants.PictureDir,
MusicDir: constants.MusicDir,
MovieDir: constants.MovieDir,
DownloadDir: constants.DownloadDir,
DCIMDir: constants.DCIMDir,
SDCardDir: constants.SDCardDir, // Depracated
SDCardApplicationDir: constants.SDCardApplicationDir, // Deprecated
MainBundleDir: constants.MainBundleDir,
LibraryDir: constants.LibraryDir,
ApplicationSupportDir: constants.ApplicationSupportDir,
LegacyPictureDir: constants.LegacyPictureDir,
LegacyMusicDir: constants.LegacyMusicDir,
LegacyMovieDir: constants.LegacyMovieDir,
LegacyDownloadDir: constants.LegacyDownloadDir,
LegacyDCIMDir: constants.LegacyDCIMDir,
LegacySDCardDir: constants.LegacySDCardDir, // Depracated
};
function addCode(code: string, error: Error): Error {
error.code = code;
return error;
}
/**
* Get a file cache session
* @param {string} name Stream ID
* @return {ReactNativeBlobUtilSession}
*/
function session(name: string): ReactNativeBlobUtilSession {
let s = ReactNativeBlobUtilSession.getSession(name);
if (s)
return new ReactNativeBlobUtilSession(name);
else {
ReactNativeBlobUtilSession.setSession(name, []);
return new ReactNativeBlobUtilSession(name, []);
}
}
function asset(path: string): string {
if (Platform.OS === 'ios') {
// path from camera roll
if (/^assets-library\:\/\//.test(path))
return path;
}
return 'bundle-assets://' + path;
}
function createFile(path: string, data: string, encoding: 'base64' | 'ascii' | 'utf8' = 'utf8'): Promise<string> {
if (encoding.toLowerCase() === 'ascii') {
return Array.isArray(data) ?
ReactNativeBlobUtil.createFileASCII(path, data) :
Promise.reject(addCode('EINVAL', new TypeError('`data` of ASCII file must be an array with 0..255 numbers')));
}
else {
return ReactNativeBlobUtil.createFile(path, data, encoding);
}
}
/**
* Create write stream to a file.
* @param {string} path Target path of file stream.
* @param {string} encoding Encoding of input data.
* @param {boolean} [append] A flag represent if data append to existing ones.
* @return {Promise<ReactNativeBlobUtilWriteStream>} A promise resolves a `WriteStream` object.
*/
function writeStream(
path: string,
encoding?: 'utf8' | 'ascii' | 'base64' = 'utf8',
append?: boolean = false,
): Promise<ReactNativeBlobUtilWriteStream> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
return new Promise((resolve, reject) => {
ReactNativeBlobUtil.writeStream(path, encoding, append, (errCode, errMsg, streamId: string) => {
if (errMsg) {
const err = new Error(errMsg);
err.code = errCode;
reject(err);
}
else
resolve(new ReactNativeBlobUtilWriteStream(streamId, encoding));
});
});
}
/**
* Create file stream from file at `path`.
* @param {string} path The file path.
* @param {string} encoding Data encoding, should be one of `base64`, `utf8`, `ascii`
* @param {boolean} bufferSize Size of stream buffer.
* @param {number} [tick=10] Interval in milliseconds between reading chunks of data
* @return {ReactNativeBlobUtilStream} ReactNativeBlobUtilStream stream instance.
*/
function readStream(
path: string,
encoding: 'utf8' | 'ascii' | 'base64' = 'utf8',
bufferSize?: number,
tick?: number = 10
): Promise<ReactNativeBlobUtilReadStream> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
return Promise.resolve(new ReactNativeBlobUtilReadStream(path, encoding, bufferSize, tick));
}
/**
* Create a directory.
* @param {string} path Path of directory to be created
* @return {Promise}
*/
function mkdir(path: string): Promise {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
return ReactNativeBlobUtil.mkdir(path);
}
/**
* Returns the path for the app group.
* @param {string} groupName Name of app group
* @return {Promise}
*/
function pathForAppGroup(groupName: string): Promise {
return ReactNativeBlobUtil.pathForAppGroup(groupName);
}
/**
* Returns the path for the app group synchronous.
* @param {string} groupName Name of app group
* @return {string} Path of App Group dir
*/
function syncPathAppGroup(groupName: string): string {
if (Platform.OS === 'ios') {
return ReactNativeBlobUtil.syncPathAppGroup(groupName);
}
else {
return '';
}
}
/**
* Wrapper method of readStream.
* @param {string} path Path of the file.
* @param {'base64' | 'utf8' | 'ascii'} encoding Encoding of read stream.
* @return {Promise<Array<number> | string>}
*/
function readFile(path: string, encoding: string = 'utf8'): Promise<any> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
return ReactNativeBlobUtil.readFile(path, encoding, false);
}
/**
* Reads the file, then transforms it before returning the content
* @param {string} path Path of the file.
* @param {'base64' | 'utf8' | 'ascii'} encoding Encoding of read stream.
* @return {Promise<Array<number> | string>}
*/
function readFileWithTransform(path: string, encoding: string = 'utf8'): Promise<any> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
}
return ReactNativeBlobUtil.readFile(path, encoding, true);
}
/**
* Write data to file.
* @param {string} path Path of the file.
* @param {string | number[]} data Data to write to the file.
* @param {string} encoding Encoding of data (Optional).
* @return {Promise}
*/
function writeFile(path: string, data: string | Array<number>, encoding: ?string = 'utf8'): Promise {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
if (encoding.toLocaleLowerCase() === 'ascii') {
if (!Array.isArray(data)) {
return Promise.reject(addCode('EINVAL', new TypeError('"data" must be an Array when encoding is "ascii"')));
}
else
return ReactNativeBlobUtil.writeFileArray(path, data, false);
}
else {
if (typeof data !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)));
}
else
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, false);
}
}
/**
* Transforms the data and then writes to the file.
* @param {string} path Path of the file.
* @param {string | number[]} data Data to write to the file.
* @param {string} encoding Encoding of data (Optional).
* @return {Promise}
*/
function writeFileWithTransform(path: string, data: string | Array<number>, encoding: ?string = 'utf8'): Promise {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
}
if (encoding.toLocaleLowerCase() === 'ascii') {
return Promise.reject(addCode('EINVAL', new TypeError('ascii is not supported for converted files')))
}
else {
if (typeof data !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)))
}
else
return ReactNativeBlobUtil.writeFile(path, encoding, data, true, false)
}
}
function appendFile(path: string, data: string | Array<number>, encoding?: string = 'utf8'): Promise<number> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
if (encoding.toLocaleLowerCase() === 'ascii') {
if (!Array.isArray(data)) {
return Promise.reject(addCode('EINVAL', new TypeError('`data` of ASCII file must be an array with 0..255 numbers')));
}
else
return ReactNativeBlobUtil.writeFileArray(path, data, true);
}
else {
if (typeof data !== 'string') {
return Promise.reject(addCode('EINVAL'), new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`));
}
else
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, true);
}
}
/**
* Show statistic data of a path.
* @param {string} path Target path
* @return {ReactNativeBlobUtilFile}
*/
function stat(path: string): Promise<ReactNativeBlobUtilFile> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
ReactNativeBlobUtil.stat(path, (err, stat) => {
if (err)
reject(new Error(err));
else {
if (stat) {
stat.size = parseInt(stat.size);
stat.lastModified = parseInt(stat.lastModified);
}
resolve(stat);
}
});
});
}
/**
* Android only method, request media scanner to scan the file.
* @param {Array<Object<string, string>>} pairs Array contains Key value pairs with key `path` and `mime`.
* @return {Promise}
*/
function scanFile(pairs: any): Promise {
return new Promise((resolve, reject) => {
if (pairs === undefined) {
return reject(addCode('EINVAL', new TypeError('Missing argument')));
}
ReactNativeBlobUtil.scanFile(pairs, (err) => {
if (err)
reject(addCode('EUNSPECIFIED', new Error(err)));
else
resolve();
});
});
}
function hash(path: string, algorithm: string): Promise<string> {
if (typeof path !== 'string' || typeof algorithm !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" and/or "algorithm"')));
}
return ReactNativeBlobUtil.hash(path, algorithm);
}
function cp(path: string, dest: string): Promise<boolean> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string' || typeof dest !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" and/or "destination"')));
}
ReactNativeBlobUtil.cp(path, dest, (err, res) => {
if (err)
reject(addCode('EUNSPECIFIED', new Error(err)));
else
resolve(res);
});
});
}
function mv(path: string, dest: string): Promise<boolean> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string' || typeof dest !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" and/or "destination"')));
}
ReactNativeBlobUtil.mv(path, dest, (err, res) => {
if (err)
reject(addCode('EUNSPECIFIED', new Error(err)));
else
resolve(res);
});
});
}
function lstat(path: string): Promise<Array<ReactNativeBlobUtilFile>> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
ReactNativeBlobUtil.lstat(path, (err, stat) => {
if (err)
reject(addCode('EUNSPECIFIED', new Error(err)));
else
resolve(stat);
});
});
}
function ls(path: string): Promise<Array<String>> {
if (typeof path !== 'string') {
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
return ReactNativeBlobUtil.ls(path);
}
/**
* Remove file at path.
* @param {string} path:string Path of target file.
* @return {Promise}
*/
function unlink(path: string): Promise {
return new Promise((resolve, reject) => {
if (typeof path !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
ReactNativeBlobUtil.unlink(path, (err) => {
if (err) {
reject(addCode('EUNSPECIFIED', new Error(err)));
}
else
resolve();
});
});
}
/**
* Check if file exists and if it is a folder.
* @param {string} path Path to check
* @return {Promise<boolean>}
*/
function exists(path: string): Promise<boolean> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
try {
ReactNativeBlobUtil.exists(path, (exist) => {
resolve(exist);
});
} catch (err) {
reject(addCode('EUNSPECIFIED', new Error(err)));
}
});
}
function slice(src: string, dest: string, start: number, end: number): Promise {
if (typeof src !== 'string' || typeof dest !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "src" and/or "destination"')));
}
let p = Promise.resolve();
let size = 0;
function normalize(num, size) {
if (num < 0)
return Math.max(0, size + num);
if (!num && num !== 0)
return size;
return num;
}
if (start < 0 || end < 0 || !start || !end) {
p = p.then(() => stat(src))
.then((stat) => {
size = Math.floor(stat.size);
start = normalize(start || 0, size);
end = normalize(end, size);
});
}
return p.then(() => ReactNativeBlobUtil.slice(src, dest, start, end));
}
function isDir(path: string): Promise<bool> {
return new Promise((resolve, reject) => {
if (typeof path !== 'string') {
return reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
}
try {
ReactNativeBlobUtil.exists(path, (exist, isDir) => {
resolve(isDir);
});
} catch (err) {
reject(addCode('EUNSPECIFIED', new Error(err)));
}
});
}
function df(): Promise<{ free: number, total: number }> {
return new Promise((resolve, reject) => {
ReactNativeBlobUtil.df((err, stat) => {
if (err)
reject(addCode('EUNSPECIFIED', new Error(err)));
else
resolve(stat);
});
});
}
export default {
ReactNativeBlobUtilSession,
unlink,
mkdir,
session,
ls,
readStream,
mv,
cp,
writeStream,
writeFile,
writeFileWithTransform,
readFileWithTransform,
appendFile,
pathForAppGroup,
syncPathAppGroup,
readFile,
hash,
exists,
createFile,
isDir,
stat,
lstat,
scanFile,
dirs,
slice,
asset,
df
};