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
2015-09-30 18:32:58 -07:00
var RNFSManager = require ( 'react-native' ) . NativeModules . RNFSManager ;
2016-07-18 22:46:13 +01:00
2015-11-20 00:16:13 +00:00
var NativeAppEventEmitter = require ( 'react-native' ) . NativeAppEventEmitter ; // iOS
var DeviceEventEmitter = require ( 'react-native' ) . DeviceEventEmitter ; // Android
2015-05-08 20:05:37 +03:00
var base64 = require ( 'base-64' ) ;
2015-10-22 01:25:52 +01:00
var utf8 = require ( 'utf8' ) ;
2015-05-08 20:05:37 +03:00
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-08-01 19:36:15 +01:00
type MkdirOptions = {
NSURLIsExcludedFromBackupKey ? : boolean ;
} ;
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-08-01 19:36:15 +01:00
mkdir ( filepath : string , options : MkdirOptions ) : Promise < void > {
options = options || { } ;
return RNFSManager . mkdir ( filepath , options ) . then ( ( ) => void 0 ) ;
} ,
moveFile ( filepath : string , destPath : string ) : Promise < void > {
return RNFSManager . moveFile ( filepath , destPath ) . then ( ( ) => void 0 ) ;
} ,
copyFile ( filepath : string , destPath : string ) : Promise < void > {
return RNFSManager . copyFile ( filepath , destPath ) . then ( ( ) => void 0 ) ;
} ,
pathForBundle ( bundleNamed : string ) : Promise < string > {
return RNFSManager . pathForBundle ( bundleNamed ) ;
} ,
getFSInfo ( ) : Promise < FSInfoResult > {
return RNFSManager . getFSInfo ( ) ;
} ,
unlink ( filepath : string ) : Promise < void > {
return RNFSManager . unlink ( filepath ) . then ( ( ) => void 0 ) ;
} ,
exists ( filepath : string ) : Promise < boolean > {
return RNFSManager . exists ( filepath ) ;
} ,
stopDownload ( jobId : number ) : void {
RNFSManager . stopDownload ( jobId ) ;
} ,
stopUpload ( jobId : number ) : void {
RNFSManager . stopUpload ( jobId ) ;
} ,
2016-06-30 00:08:53 +01:00
readDir ( dirpath : string ) : Promise < ReadDirItem [ ] > {
2016-07-18 22:46:13 +01:00
return RNFSManager . readDir ( dirpath ) . then ( files => {
2016-06-30 00:08:53 +01:00
return files . map ( file => ( {
name : file . name ,
path : file . path ,
size : file . size ,
isFile : ( ) => file . type === NSFileTypeRegular ,
isDirectory : ( ) => file . type === NSFileTypeDirectory ,
} ) ) ;
2016-07-18 22:46:13 +01:00
} ) ;
2015-05-08 20:05:37 +03:00
} ,
2015-10-22 01:25:52 +01: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 ) ;
} ) ;
2015-10-22 01:25:52 +01:00
} ,
2016-06-30 00:08:53 +01:00
stat ( filepath : string ) : Promise < StatResult > {
2016-07-18 22:46:13 +01:00
return RNFSManager . stat ( filepath ) . then ( ( result ) => {
2016-06-30 00:08:53 +01:00
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 ,
} ;
2016-07-18 22:46:13 +01:00
} ) ;
2016-01-28 21:36:31 +08:00
} ,
2015-05-08 20:05:37 +03:00
2016-07-27 00:15:41 +01:00
readFile ( filepath : string , encodingOrOptions ? : any ) : Promise < string > {
var options = {
encoding : 'utf8'
} ;
if ( encodingOrOptions ) {
if ( typeof encodingOrOptions === 'string' ) {
options . encoding = encodingOrOptions ;
} else if ( typeof encodingOrOptions === 'object' ) {
options = encodingOrOptions ;
}
}
2015-05-08 20:05:37 +03:00
2016-07-18 22:46:13 +01:00
return RNFSManager . readFile ( filepath ) . then ( ( b64 ) => {
2016-06-30 00:08:53 +01:00
var contents ;
2016-07-27 00:15:41 +01:00
if ( options . encoding === 'utf8' ) {
2016-06-30 00:08:53 +01:00
contents = utf8 . decode ( base64 . decode ( b64 ) ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'ascii' ) {
2016-06-30 00:08:53 +01:00
contents = base64 . decode ( b64 ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'base64' ) {
2016-06-30 00:08:53 +01:00
contents = b64 ;
} else {
2016-07-27 00:15:41 +01:00
throw new Error ( 'Invalid encoding type "' + String ( options . encoding ) + '"' ) ;
2016-06-30 00:08:53 +01:00
}
return contents ;
2016-07-18 22:46:13 +01:00
} ) ;
2016-06-30 00:08:53 +01:00
} ,
2016-07-27 00:15:41 +01:00
writeFile ( filepath : string , contents : string , encodingOrOptions ? : any ) : Promise < void > {
2016-06-30 00:08:53 +01:00
var b64 ;
2016-07-27 00:15:41 +01:00
var options = {
encoding : 'utf8'
} ;
if ( encodingOrOptions ) {
if ( typeof encodingOrOptions === 'string' ) {
options . encoding = encodingOrOptions ;
} else if ( typeof encodingOrOptions === 'object' ) {
options = encodingOrOptions ;
}
}
2016-06-30 00:08:53 +01:00
2016-07-27 00:15:41 +01:00
if ( options . encoding === 'utf8' ) {
2016-06-30 00:08:53 +01:00
b64 = base64 . encode ( utf8 . encode ( contents ) ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'ascii' ) {
2016-06-30 00:08:53 +01:00
b64 = base64 . encode ( contents ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'base64' ) {
2016-06-30 00:08:53 +01:00
b64 = contents ;
} else {
2016-07-27 00:15:41 +01:00
throw new Error ( 'Invalid encoding type "' + options . encoding + '"' ) ;
2016-06-30 00:08:53 +01:00
}
2016-08-01 19:36:15 +01:00
return RNFSManager . writeFile ( filepath , b64 , { } ) . then ( ( ) => void 0 ) ;
2015-05-08 20:05:37 +03:00
} ,
2016-07-27 00:15:41 +01:00
appendFile ( filepath : string , contents : string , encodingOrOptions ? : any ) : Promise < void > {
2015-10-22 01:25:52 +01:00
var b64 ;
2016-07-27 00:15:41 +01:00
var options = {
encoding : 'utf8'
} ;
if ( encodingOrOptions ) {
if ( typeof encodingOrOptions === 'string' ) {
options . encoding = encodingOrOptions ;
} else if ( typeof encodingOrOptions === 'object' ) {
options = encodingOrOptions ;
}
}
2015-10-22 01:25:52 +01:00
2016-07-27 00:15:41 +01:00
if ( options . encoding === 'utf8' ) {
2015-10-22 01:25:52 +01:00
b64 = base64 . encode ( utf8 . encode ( contents ) ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'ascii' ) {
2015-10-22 01:25:52 +01:00
b64 = base64 . encode ( contents ) ;
2016-07-27 00:15:41 +01:00
} else if ( options . encoding === 'base64' ) {
2015-10-22 01:25:52 +01:00
b64 = contents ;
} else {
2016-07-27 00:15:41 +01:00
throw new Error ( 'Invalid encoding type "' + options . encoding + '"' ) ;
2015-10-22 01:25:52 +01:00
}
2016-07-27 00:15:41 +01:00
return RNFSManager . appendFile ( filepath , b64 , { } ) ;
2015-05-09 00:17:10 +03:00
} ,
2016-06-30 00:08:53 +01:00
downloadFile ( options : DownloadFileOptions ) : Promise < DownloadResult > {
2016-06-02 00:49:01 +01:00
if ( arguments . length > 1 ) {
2016-06-04 08:50:07 +01:00
console . warn ( 'Deprecated: Please see updated docs for `downloadFile`' ) ;
2016-06-02 00:49:01 +01:00
options = {
fromUrl : arguments [ 0 ] ,
toFile : arguments [ 1 ] ,
begin : arguments [ 2 ] ,
2016-06-30 00:08:53 +01:00
progress : arguments [ 3 ] ,
background : false
2016-06-02 00:49:01 +01:00
} ;
}
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`' ) ;
2016-06-08 17:52:08 +01:00
if ( options . progressDivider && typeof options . progressDivider !== 'number' ) throw new Error ( 'downloadFile: Invalid value for property `progressDivider`' ) ;
2016-06-02 00:49:01 +01:00
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
2016-06-02 00:49:01 +01:00
if ( options . begin ) {
subscriptions . push ( NativeAppEventEmitter . addListener ( 'DownloadBegin-' + jobId , options . begin ) ) ;
2015-11-23 16:29:25 +00:00
}
2016-06-02 00:49:01 +01:00
if ( options . progress ) {
subscriptions . push ( NativeAppEventEmitter . addListener ( 'DownloadProgress-' + jobId , options . progress ) ) ;
2015-11-20 00:16:13 +00:00
}
2016-06-02 00:49:01 +01: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-02 00:49:01 +01:00
} ;
2016-07-18 22:46:13 +01:00
return RNFSManager . downloadFile ( bridgeOptions ) . then ( res => {
2016-06-30 00:08:53 +01:00
subscriptions . forEach ( sub => sub . remove ( ) ) ;
return res ;
2016-07-18 22:46:13 +01:00
} ) ;
2015-11-23 17:08:52 +00:00
} ,
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-07-18 22:46:13 +01:00
return RNFSManager . uploadFiles ( bridgeOptions ) . then ( res => {
2016-06-30 00:08:53 +01:00
subscriptions . forEach ( sub => sub . remove ( ) ) ;
return res ;
} ) ;
2016-05-30 23:13:50 +01:00
} ,
2015-10-23 00:13:12 +01:00
MainBundlePath : RNFSManager . MainBundlePath ,
2015-05-08 20:17:59 +03:00
CachesDirectoryPath : RNFSManager . NSCachesDirectoryPath ,
2015-12-02 11:12:06 +09:00
DocumentDirectoryPath : RNFSManager . NSDocumentDirectoryPath ,
2016-03-31 10:20:52 -07:00
ExternalDirectoryPath : RNFSManager . NSExternalDirectoryPath ,
2016-05-14 23:42:57 +02:00
TemporaryDirectoryPath : RNFSManager . NSTemporaryDirectoryPath ,
2016-01-05 12:24:42 +01:00
LibraryDirectoryPath : RNFSManager . NSLibraryDirectoryPath ,
PicturesDirectoryPath : RNFSManager . NSPicturesDirectoryPath
2016-07-18 22:46:13 +01:00
2015-05-08 20:05:37 +03:00
} ;
module . exports = RNFS ;