react-native-fs/FS.common.js

377 lines
13 KiB
JavaScript
Raw Normal View History

2016-06-30 00:08:53 +01:00
/**
* React Native FS
* @flow
*/
2015-05-08 20:05:37 +03:00
'use strict';
2015-10-19 14:40:05 +01:00
// This file supports both iOS and Android
// Stop bluebird going nuts because it can't find "self"
if (typeof self === 'undefined') {
global.self = global;
}
2015-09-30 18:32:58 -07:00
var RNFSManager = require('react-native').NativeModules.RNFSManager;
2016-05-14 23:19:27 +02:00
var NativeAppEventEmitter = require('react-native').NativeAppEventEmitter;
2015-05-08 20:05:37 +03:00
var Promise = require('bluebird');
var base64 = require('base-64');
var utf8 = require('utf8');
2015-05-08 20:05:37 +03:00
var _readDir = Promise.promisify(RNFSManager.readDir);
2016-01-29 02:20:02 +08:00
var _exists = Promise.promisify(RNFSManager.exists);
2015-05-08 20:05:37 +03:00
var _stat = Promise.promisify(RNFSManager.stat);
var _readFile = Promise.promisify(RNFSManager.readFile);
var _writeFile = Promise.promisify(RNFSManager.writeFile);
2016-06-30 00:08:53 +01:00
var _appendFile = Promise.promisify(RNFSManager.appendFile);
2016-01-16 10:52:56 -08:00
var _moveFile = Promise.promisify(RNFSManager.moveFile);
2015-05-09 00:17:10 +03:00
var _unlink = Promise.promisify(RNFSManager.unlink);
2015-10-20 23:31:29 +01:00
var _mkdir = Promise.promisify(RNFSManager.mkdir);
2015-10-21 00:17:03 +01:00
var _downloadFile = Promise.promisify(RNFSManager.downloadFile);
var _uploadFiles = RNFSManager.uploadFiles ? Promise.promisify(RNFSManager.uploadFiles) : function () { return Promise.reject('Not implemented on Android'); };
2015-08-18 14:27:52 -04:00
var _pathForBundle = Promise.promisify(RNFSManager.pathForBundle);
2016-03-18 10:53:00 -07:00
var _getFSInfo = Promise.promisify(RNFSManager.getFSInfo);
2015-05-08 20:05:37 +03:00
2016-06-30 00:08:53 +01:00
class RNFSError extends Error {
code: number;
constructor(message) {
super(message);
}
}
2015-05-08 20:05:37 +03:00
var convertError = (err) => {
2015-10-20 23:31:29 +01:00
if (err.isOperational && err.cause) {
2015-05-09 00:17:10 +03:00
err = err.cause;
}
2016-06-30 00:08:53 +01:00
var error = new RNFSError(err.description || err.message);
2015-05-08 20:05:37 +03:00
error.code = err.code;
throw error;
};
var NSFileTypeRegular = RNFSManager.NSFileTypeRegular;
var NSFileTypeDirectory = RNFSManager.NSFileTypeDirectory;
2015-11-20 00:16:13 +00:00
var jobId = 0;
var getJobId = () => {
jobId += 1;
return jobId;
};
2016-06-30 00:08:53 +01:00
type ReadDirItem = {
name: string; // The name of the item
path: string; // The absolute path to the item
size: string; // Size in bytes
isFile: () => boolean; // Is the file just a file?
isDirectory: () => boolean; // Is the file a directory?
};
type StatResult = {
name: string; // The name of the item
path: string; // The absolute path to the item
size: string; // Size in bytes
mode: number; // UNIX file mode
isFile: () => boolean; // Is the file just a file?
isDirectory: () => boolean; // Is the file a directory?
};
type WriteFileOptions = {
// iOS only. See https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index.html#//apple_ref/doc/constant_group/File_Attribute_Keys
};
type Headers = { [name: string]: string };
type Fields = { [name: string]: string };
type DownloadFileOptions = {
fromUrl: string; // URL to download file from
toFile: string; // Local filesystem path to save the file to
headers?: Headers; // An object of headers to be passed to the server
background?: boolean;
progressDivider?: number;
begin?: (res: DownloadBeginCallbackResult) => void;
progress?: (res: DownloadProgressCallbackResult) => void;
};
type DownloadBeginCallbackResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
statusCode: number; // The HTTP status code
contentLength: number; // The total size in bytes of the download resource
headers: Headers; // The HTTP response headers from the server
};
type DownloadProgressCallbackResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
contentLength: number; // The total size in bytes of the download resource
bytesWritten: number; // The number of bytes written to the file so far
};
type DownloadResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
statusCode: number; // The HTTP status code
bytesWritten: number; // The number of bytes written to the file
};
type UploadFileOptions = {
toUrl: string; // URL to upload file to
files: UploadFileItem[]; // An array of objects with the file information to be uploaded.
2016-06-30 11:45:11 +01:00
headers?: Headers; // An object of headers to be passed to the server
fields?: Fields; // An object of fields to be passed to the server
method?: string; // Default is 'POST', supports 'POST' and 'PUT'
2016-06-30 00:08:53 +01:00
begin?: (res: UploadBeginCallbackResult) => void;
progress?: (res: UploadProgressCallbackResult) => void;
};
type UploadFileItem = {
name: string; // Name of the file, if not defined then filename is used
filename: string; // Name of file
filepath: string; // Path to file
filetype: string; // The mimetype of the file to be uploaded, if not defined it will get mimetype from `filepath` extension
};
type UploadBeginCallbackResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
};
type UploadProgressCallbackResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
totalBytesExpectedToSend: number; // The total number of bytes that will be sent to the server
totalBytesSent: number; // The number of bytes sent to the server
};
type UploadResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
statusCode: number; // The HTTP status code
headers: Headers; // The HTTP response headers from the server
body: string; // The HTTP response body
};
type FSInfoResult = {
totalSpace: number; // The total amount of storage space on the device (in bytes).
freeSpace: number; // The amount of available storage space on the device (in bytes).
};
2015-05-08 20:05:37 +03:00
var RNFS = {
2016-06-30 00:08:53 +01:00
readDir(dirpath: string): Promise<ReadDirItem[]> {
return _readDir(dirpath).then(files => {
return files.map(file => ({
name: file.name,
path: file.path,
size: file.size,
isFile: () => file.type === NSFileTypeRegular,
isDirectory: () => file.type === NSFileTypeDirectory,
}));
}).catch(convertError);
2015-05-08 20:05:37 +03:00
},
// Node style version (lowercase d). Returns just the names
2016-06-30 00:08:53 +01:00
readdir(dirpath: string): Promise<string[]> {
return RNFS.readDir(dirpath).then(files => {
return files.map(file => file.name);
});
},
2016-06-30 00:08:53 +01:00
stat(filepath: string): Promise<StatResult> {
return _stat(filepath).then((result) => {
return {
'ctime': new Date(result.ctime * 1000),
'mtime': new Date(result.mtime * 1000),
'size': result.size,
'mode': result.mode,
isFile: () => result.type === NSFileTypeRegular,
isDirectory: () => result.type === NSFileTypeDirectory,
};
}).catch(convertError);
2015-05-08 20:05:37 +03:00
},
2016-03-18 10:53:00 -07:00
2016-06-30 00:08:53 +01:00
exists(filepath: string): Promise<boolean> {
return _exists(filepath).catch(convertError);
2016-01-28 21:36:31 +08:00
},
2015-05-08 20:05:37 +03:00
2016-06-30 00:08:53 +01:00
readFile(filepath: string, encoding?: string): Promise<string> {
if (!encoding) encoding = 'utf8';
2015-05-08 20:05:37 +03:00
2016-06-30 00:08:53 +01:00
return _readFile(filepath).then((b64) => {
var contents;
if (encoding === 'utf8') {
contents = utf8.decode(base64.decode(b64));
} else if (encoding === 'ascii') {
contents = base64.decode(b64);
} else if (encoding === 'base64') {
contents = b64;
} else {
throw new Error('Invalid encoding type "' + String(encoding) + '"');
}
return contents;
}).catch(convertError);
},
writeFile(filepath: string, contents: string, encoding?: string, options?: WriteFileOptions): Promise<void> {
var b64;
if (!encoding) encoding = 'utf8';
if (encoding === 'utf8') {
b64 = base64.encode(utf8.encode(contents));
} else if (encoding === 'ascii') {
b64 = base64.encode(contents);
} else if (encoding === 'base64') {
b64 = contents;
} else {
throw new Error('Invalid encoding type "' + encoding + '"');
}
return _writeFile(filepath, b64, options).catch(convertError);
2015-05-08 20:05:37 +03:00
},
2016-06-30 00:08:53 +01:00
appendFile(filepath: string, contents: string, encoding?: string, options?: WriteFileOptions): Promise<void> {
var b64;
if (!encoding) encoding = 'utf8';
if (encoding === 'utf8') {
b64 = base64.encode(utf8.encode(contents));
} else if (encoding === 'ascii') {
b64 = base64.encode(contents);
} else if (encoding === 'base64') {
b64 = contents;
} else {
throw new Error('Invalid encoding type "' + encoding + '"');
}
2016-06-30 00:08:53 +01:00
return _appendFile(filepath, b64, options).catch(convertError);
},
2016-06-30 00:08:53 +01:00
moveFile(filepath: string, destPath: string): Promise<void> {
return _moveFile(filepath, destPath).catch(convertError);
2016-01-16 10:52:56 -08:00
},
2016-06-30 00:08:53 +01:00
pathForBundle(bundleName: string): Promise<string> {
return _pathForBundle(bundleName);
},
2016-06-30 00:08:53 +01:00
getFSInfo(): Promise<FSInfoResult> {
return _getFSInfo().catch(convertError);
2016-03-18 10:53:00 -07:00
},
2016-06-30 00:08:53 +01:00
unlink(filepath: string): Promise<void> {
return _unlink(filepath).catch(convertError);
2015-05-09 00:17:10 +03:00
},
2016-06-30 00:08:53 +01:00
mkdir(filepath: string, excludeFromBackup?: boolean): Promise<void> {
excludeFromBackup = !!excludeFromBackup;
2016-06-30 00:08:53 +01:00
return _mkdir(filepath, excludeFromBackup).catch(convertError);
2015-10-20 23:31:29 +01:00
},
2016-06-30 00:08:53 +01:00
downloadFile(options: DownloadFileOptions): Promise<DownloadResult> {
if (arguments.length > 1) {
console.warn('Deprecated: Please see updated docs for `downloadFile`');
options = {
fromUrl: arguments[0],
toFile: arguments[1],
begin: arguments[2],
2016-06-30 00:08:53 +01:00
progress: arguments[3],
background: false
};
}
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`');
2015-11-20 00:16:13 +00:00
var jobId = getJobId();
2016-05-14 23:19:27 +02:00
var subscriptions = [];
2016-05-30 23:13:50 +01:00
if (options.begin) {
subscriptions.push(NativeAppEventEmitter.addListener('DownloadBegin-' + jobId, options.begin));
}
if (options.progress) {
subscriptions.push(NativeAppEventEmitter.addListener('DownloadProgress-' + jobId, options.progress));
2015-11-20 00:16:13 +00:00
}
var bridgeOptions = {
jobId: jobId,
fromUrl: options.fromUrl,
toFile: options.toFile,
headers: options.headers || {},
background: !!options.background,
2016-06-30 00:14:18 +01:00
progressDivider: options.progressDivider || 0
};
2016-06-30 00:08:53 +01:00
return _downloadFile(bridgeOptions).then(res => {
subscriptions.forEach(sub => sub.remove());
return res;
}).catch(convertError);
2015-10-21 00:17:03 +01:00
},
2016-06-30 00:08:53 +01:00
stopDownload(jobId: number): Promise<void> {
2015-11-23 17:08:52 +00:00
RNFSManager.stopDownload(jobId);
},
2016-06-30 00:08:53 +01:00
uploadFiles(options: UploadFileOptions): Promise<UploadResult> {
2016-05-30 23:13:50 +01:00
var jobId = getJobId();
2016-05-30 23:35:34 +01:00
var subscriptions = [];
2016-05-30 23:13:50 +01:00
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`');
2016-06-30 00:08:53 +01:00
if (options.begin) {
subscriptions.push(NativeAppEventEmitter.addListener('UploadBegin-' + jobId, options.begin));
}
2016-05-30 23:13:50 +01:00
if (options.beginCallback) {
2016-06-30 00:08:53 +01:00
// Deprecated
2016-05-30 23:35:34 +01:00
subscriptions.push(NativeAppEventEmitter.addListener('UploadBegin-' + jobId, options.beginCallback));
2016-05-30 23:13:50 +01:00
}
2016-06-30 00:08:53 +01:00
if (options.progress) {
subscriptions.push(NativeAppEventEmitter.addListener('UploadProgress-' + jobId, options.progress));
}
2016-05-30 23:13:50 +01:00
if (options.progressCallback) {
2016-06-30 00:08:53 +01:00
// Deprecated
2016-05-30 23:35:34 +01:00
subscriptions.push(NativeAppEventEmitter.addListener('UploadProgress-' + jobId, options.progressCallback));
2016-05-30 23:13:50 +01:00
}
var bridgeOptions = {
jobId: jobId,
toUrl: options.toUrl,
files: options.files,
headers: options.headers || {},
fields: options.fields || {},
method: options.method || 'POST'
};
2016-06-30 00:08:53 +01:00
return _uploadFiles(bridgeOptions).then(res => {
subscriptions.forEach(sub => sub.remove());
return res;
});
2016-05-30 23:13:50 +01:00
},
2016-06-30 00:08:53 +01:00
stopUpload(jobId: number): Promise<void> {
2016-05-30 23:13:50 +01:00
RNFSManager.stopUpload(jobId);
},
2015-10-23 00:13:12 +01:00
MainBundlePath: RNFSManager.MainBundlePath,
CachesDirectoryPath: RNFSManager.NSCachesDirectoryPath,
2015-12-02 11:12:06 +09:00
DocumentDirectoryPath: RNFSManager.NSDocumentDirectoryPath,
ExternalDirectoryPath: RNFSManager.NSExternalDirectoryPath,
2016-05-14 23:42:57 +02:00
TemporaryDirectoryPath: RNFSManager.NSTemporaryDirectoryPath,
LibraryDirectoryPath: RNFSManager.NSLibraryDirectoryPath,
PicturesDirectoryPath: RNFSManager.NSPicturesDirectoryPath
2015-05-08 20:05:37 +03:00
};
module.exports = RNFS;