Skip to content
This repository was archived by the owner on Mar 16, 2019. It is now read-only.

My proposed 0.10.9 changes #489

Merged
merged 46 commits into from
Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0dd09a4
Fix path argument in iOS excludeFromBackupKey (#473)
grylance Aug 9, 2017
57af353
Fix link to fs.readStream() and to fs.writeStream() and insert link t…
lll000111 Aug 10, 2017
3a31e35
Fix the documentation part of https://github.com/wkh237/react-native-…
lll000111 Aug 10, 2017
23ef0f7
More fixes for issue https://github.com/wkh237/react-native-fetch-blo…
lll000111 Aug 11, 2017
647e88f
Fix one issue raised in https://github.com/wkh237/react-native-fetch-…
lll000111 Aug 12, 2017
05d6e03
fix some access rights, remove unused items
lll000111 Aug 14, 2017
3952293
update gradle version setting in build.gradle
lll000111 Aug 14, 2017
4c7bc55
Revert gradle settings to previous values :-(
lll000111 Aug 14, 2017
d22bdc6
add a missing closing ")"
lll000111 Aug 14, 2017
0fea62a
Removed the part of an obsolete callback function parameter that I ha…
lll000111 Aug 14, 2017
a2f13b1
let mkdir resolve with "undefined" instead of "null" (my mistake)
lll000111 Aug 14, 2017
d3e47cd
mkdir: normalize iOS and Android error if something already exists (f…
lll000111 Aug 14, 2017
2a4b11b
fix a long/int issue
lll000111 Aug 14, 2017
2233980
my mistake - according to https://facebook.github.io/react-native/doc…
lll000111 Aug 14, 2017
34e2377
Adde "utf8" as default encoding for fs.readFile - fixes #450 and #484
lll000111 Aug 15, 2017
a530f52
follow my IDEA IDE's recommendations - SparseArray instead of HashMap…
lll000111 Aug 15, 2017
7588f82
polyfill/File.js: add a parameter===undefined? check (this happened s…
lll000111 Aug 15, 2017
9682c2c
make var static again
lll000111 Aug 15, 2017
0f371ac
Normalized errors for fs.ls()
lll000111 Aug 15, 2017
0bac254
forgot one parameter
lll000111 Aug 15, 2017
30af8e9
more parameter checks
lll000111 Aug 15, 2017
c2e1d63
forgot to resolve the promise
lll000111 Aug 15, 2017
51d7453
Forgot ;
lll000111 Aug 15, 2017
4674692
add more error parameter checks
lll000111 Aug 15, 2017
3bb3bf1
change readStream()/writeStream() default encoding to utf8 to match t…
lll000111 Aug 16, 2017
45dd56c
default encoding is set in fs.js (now), no need to do it twice
lll000111 Aug 16, 2017
c2803a1
fs.js: forgot one more error refactoring
bcpclone Aug 3, 2017
a9cb606
ReadStream error events: Set a default error code "EUNSPECIFIED" if n…
lll000111 Aug 17, 2017
1080fae
writeFile() Android and iOS: improve errors; ReadStream: Add "ENOENT"…
lll000111 Aug 17, 2017
36195ca
oops - one "}" too many - removed
lll000111 Aug 17, 2017
9cde86a
add EISDIR error to readFile()s error vocabulary (iOS and Android)
lll000111 Aug 17, 2017
54afd01
"or directory" is misplaced in a "no such file" error message for rea…
lll000111 Aug 17, 2017
ea6e4d9
Android: two reject() calls did not have a code, iOS: slice() did not…
lll000111 Aug 17, 2017
9d64f5b
writeStream: return ENOENT, EISDIR and EUNSPECIFIED according to the …
lll000111 Aug 17, 2017
3394cd1
"+ +" was one plus sign too many
lll000111 Aug 17, 2017
354dc48
this if has a whole block (that ois why I prefer a style where {} are…
lll000111 Aug 17, 2017
ef9745d
I renamed this variable
lll000111 Aug 17, 2017
3292b38
1) #491 "writeStream() does not create file if it doesn't exist?"
lll000111 Aug 17, 2017
131dab2
Java: getParentFolder() may return null - prevent a NullPointerExcept…
lll000111 Aug 17, 2017
e74c944
Relating to #298 -- looping through an array is not supposed to be do…
lll000111 Aug 21, 2017
39abada
Merge branch '0.10.9' of github.com:lll000111/react-native-fetch-blob…
wkh237 Aug 27, 2017
dbafc98
Fix IOS syntax errors in #489
wkh237 Aug 27, 2017
0b90448
#489 Fix typo and missing return statement
wkh237 Aug 31, 2017
9dc2506
fix error code
wkh237 Aug 31, 2017
f00fafb
Merge branch '0.10.9' into 0.10.9
lll000111 Aug 31, 2017
c93e97e
Merge branch 'review-489' of https://github.com/wkh237/react-native-f…
lll000111 Aug 31, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -590,10 +590,11 @@ File Access APIs
- [dirs](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#dirs)
- [createFile](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#createfilepath-data-encodingpromise)
- [writeFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writefilepathstring-contentstring--array-encodingstring-appendbooleanpromise)
- [appendFile (0.6.0) ](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--array-encodingstringpromise)
- [appendFile (0.6.0) ](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--arraynumber-encodingstring-promisenumber)
- [readFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise)
- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersizepromise)
- [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstring-appendbooleanpromise)
- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersize-interval-promisernfbreadstream)
- [hash (0.10.9)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithm-promise)
- [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstringpromise)
- [hash](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithmpromise)
- [unlink](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise)
- [mkdir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise)
Expand Down Expand Up @@ -644,6 +645,45 @@ RNFetchBlob.fs.readStream(

When using `writeStream`, the stream object becomes writable, and you can then perform operations like `write` and `close`.

Since version 0.10.9 `write()` resolves with the `RNFetchBlob` instance so you can promise-chain write calls:

```js
RNFetchBlob.fs.writeStream(
PATH_TO_FILE,
// encoding, should be one of `base64`, `utf8`, `ascii`
'utf8',
// should data append to existing content ?
true
)
.then(ofstream => ofstream.write('foo'))
.then(ofstream => ofstream.write('bar'))
.then(ofstream => ofstream.write('foobar'))
.then(ofstream => ofstream.close())
.catch(console.error)
```

or

```js
RNFetchBlob.fs.writeStream(
PATH_TO_FILE,
// encoding, should be one of `base64`, `utf8`, `ascii`
'utf8',
// should data append to existing content ?
true
)
.then(stream => Promise.all([
stream.write('foo'),
stream.write('bar'),
stream.write('foobar')
]))
// Use array destructuring to get the stream object from the first item of the array we get from Promise.all()
.then(([stream]) => stream.close())
.catch(console.error)
```

You should **NOT** do something like this:

```js
RNFetchBlob.fs.writeStream(
PATH_TO_FILE,
Expand All @@ -652,13 +692,18 @@ RNFetchBlob.fs.writeStream(
// should data append to existing content ?
true)
.then((ofstream) => {
// BAD IDEA - Don't do this, those writes are unchecked:
ofstream.write('foo')
ofstream.write('bar')
ofstream.close()
})

.catch(console.error) // Cannot catch any write() errors!
```

The problem with the above code is that the promises from the `ofstream.write()` calls are detached and "Lost".
That means the entire promise chain A) resolves without waiting for the writes to finish and B) any errors caused by them are lost.
That code may _seem_ to work if there are no errors, but those writes are of the type "fire and forget": You start them and then turn away and never know if they really succeeded.

### Cache File Management

When using `fileCache` or `path` options along with `fetch` API, response data will automatically store into the file system. The files will **NOT** removed unless you `unlink` it. There're several ways to remove the files
Expand Down
1 change: 1 addition & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ android {

dependencies {
compile 'com.facebook.react:react-native:+'
//compile 'com.squareup.okhttp3:okhttp:+'
//{RNFetchBlob_PRE_0.28_DEPDENDENCY}
}
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Wed May 18 12:33:41 CST 2016
#Sat Aug 12 07:48:35 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
Expand Down
59 changes: 28 additions & 31 deletions android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.app.DownloadManager;
import android.content.Intent;
import android.net.Uri;
import android.util.SparseArray;

import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Callback;
Expand Down Expand Up @@ -34,26 +35,23 @@

public class RNFetchBlob extends ReactContextBaseJavaModule {

// Cookies
private final ForwardingCookieHandler mCookieHandler;
private final CookieJarContainer mCookieJarContainer;
private final OkHttpClient mClient;

static ReactApplicationContext RCTContext;
static LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);
private static LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);
static LinkedBlockingQueue<Runnable> fsTaskQueue = new LinkedBlockingQueue<>();
static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);
static public boolean ActionViewVisible = false;
static HashMap<Integer, Promise> promiseTable = new HashMap<>();
private static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue);
private static boolean ActionViewVisible = false;
private static SparseArray<Promise> promiseTable = new SparseArray<>();

public RNFetchBlob(ReactApplicationContext reactContext) {

super(reactContext);

mClient = OkHttpClientProvider.getOkHttpClient();
mCookieHandler = new ForwardingCookieHandler(reactContext);
mCookieJarContainer = (CookieJarContainer) mClient.cookieJar();
ForwardingCookieHandler mCookieHandler = new ForwardingCookieHandler(reactContext);
CookieJarContainer mCookieJarContainer = (CookieJarContainer) mClient.cookieJar();
mCookieJarContainer.setCookieJar(new JavaNetCookieJar(mCookieHandler));

RCTContext = reactContext;
Expand Down Expand Up @@ -85,11 +83,21 @@ public Map<String, Object> getConstants() {
}

@ReactMethod
public void createFile(final String path, final String content, final String encode, final Callback callback) {
public void createFile(final String path, final String content, final String encode, final Promise promise) {
threadPool.execute(new Runnable() {
@Override
public void run() {
RNFetchBlobFS.createFile(path, content, encode, callback);
RNFetchBlobFS.createFile(path, content, encode, promise);
}
});
}

@ReactMethod
public void createFileASCII(final String path, final ReadableArray dataArray, final Promise promise) {
threadPool.execute(new Runnable() {
@Override
public void run() {
RNFetchBlobFS.createFileASCII(path, dataArray, promise);
}
});

Expand Down Expand Up @@ -124,21 +132,10 @@ public void onHostDestroy() {
};
RCTContext.addLifecycleEventListener(listener);
} catch(Exception ex) {
promise.reject(ex.getLocalizedMessage());
promise.reject("EUNSPECIFIED", ex.getLocalizedMessage());
}
}

@ReactMethod
public void createFileASCII(final String path, final ReadableArray dataArray, final Callback callback) {
threadPool.execute(new Runnable() {
@Override
public void run() {
RNFetchBlobFS.createFileASCII(path, dataArray, callback);
}
});

}

@ReactMethod
public void writeArrayChunk(final String streamId, final ReadableArray dataArray, final Callback callback) {
RNFetchBlobFS.writeArrayChunk(streamId, dataArray, callback);
Expand All @@ -150,8 +147,8 @@ public void unlink(String path, Callback callback) {
}

@ReactMethod
public void mkdir(String path, Callback callback) {
RNFetchBlobFS.mkdir(path, callback);
public void mkdir(String path, Promise promise) {
RNFetchBlobFS.mkdir(path, promise);
}

@ReactMethod
Expand All @@ -176,8 +173,8 @@ public void mv(String path, String dest, Callback callback) {
}

@ReactMethod
public void ls(String path, Callback callback) {
RNFetchBlobFS.ls(path, callback);
public void ls(String path, Promise promise) {
RNFetchBlobFS.ls(path, promise);
}

@ReactMethod
Expand Down Expand Up @@ -355,10 +352,10 @@ public void getContentIntent(String mime, Promise promise) {

@ReactMethod
public void addCompleteDownload (ReadableMap config, Promise promise) {
DownloadManager dm = (DownloadManager) RNFetchBlob.RCTContext.getSystemService(RNFetchBlob.RCTContext.DOWNLOAD_SERVICE);
DownloadManager dm = (DownloadManager) RCTContext.getSystemService(RCTContext.DOWNLOAD_SERVICE);
String path = RNFetchBlobFS.normalizePath(config.getString("path"));
if(path == null) {
promise.reject("RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path"), "RNFetchblob.addCompleteDownload can not resolve URI:" + path);
promise.reject("EINVAL", "RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path"));
return;
}
try {
Expand All @@ -375,7 +372,7 @@ public void addCompleteDownload (ReadableMap config, Promise promise) {
promise.resolve(null);
}
catch(Exception ex) {
promise.reject("RNFetchblob.addCompleteDownload failed", ex.getStackTrace().toString());
promise.reject("EUNSPECIFIED", ex.getLocalizedMessage());
}

}
Expand Down
60 changes: 28 additions & 32 deletions android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.RNFetchBlob;

import android.support.annotation.NonNull;
import android.util.Base64;

import com.facebook.react.bridge.Arguments;
Expand All @@ -21,21 +22,20 @@
import okhttp3.RequestBody;
import okio.BufferedSink;

public class RNFetchBlobBody extends RequestBody{
class RNFetchBlobBody extends RequestBody{

InputStream requestStream;
long contentLength = 0;
ReadableArray form;
String mTaskId;
String rawBody;
RNFetchBlobReq.RequestType requestType;
MediaType mime;
File bodyCache;
private InputStream requestStream;
private long contentLength = 0;
private ReadableArray form;
private String mTaskId;
private String rawBody;
private RNFetchBlobReq.RequestType requestType;
private MediaType mime;
private File bodyCache;
int reported = 0;
Boolean chunkedEncoding = false;
private Boolean chunkedEncoding = false;


public RNFetchBlobBody(String taskId) {
RNFetchBlobBody(String taskId) {
this.mTaskId = taskId;
}

Expand All @@ -49,7 +49,7 @@ RNFetchBlobBody setMIME(MediaType mime) {
return this;
}

RNFetchBlobBody setRequestType( RNFetchBlobReq.RequestType type) {
RNFetchBlobBody setRequestType(RNFetchBlobReq.RequestType type) {
this.requestType = type;
return this;
}
Expand Down Expand Up @@ -114,7 +114,7 @@ public MediaType contentType() {
}

@Override
public void writeTo(BufferedSink sink) {
public void writeTo(@NonNull BufferedSink sink) {
try {
pipeStreamToSink(requestStream, sink);
} catch(Exception ex) {
Expand Down Expand Up @@ -186,8 +186,7 @@ private File createMultipartBodyCache() throws IOException {
ArrayList<FormField> fields = countFormDataLength();
ReactApplicationContext ctx = RNFetchBlob.RCTContext;

for(int i = 0;i < fields.size(); i++) {
FormField field = fields.get(i);
for(FormField field : fields) {
String data = field.data;
String name = field.name;
// skip invalid fields
Expand Down Expand Up @@ -258,17 +257,14 @@ private File createMultipartBodyCache() throws IOException {
* @param sink The request body buffer sink
* @throws IOException
*/
private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws Exception {

byte [] chunk = new byte[10240];
private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws IOException {
byte[] chunk = new byte[10240];
int totalWritten = 0;
int read;
while((read = stream.read(chunk, 0, 10240)) > 0) {
if(read > 0) {
sink.write(chunk, 0, read);
totalWritten += read;
emitUploadProgress(totalWritten);
}
sink.write(chunk, 0, read);
totalWritten += read;
emitUploadProgress(totalWritten);
}
stream.close();
}
Expand All @@ -291,7 +287,7 @@ private void pipeStreamToFileStream(InputStream is, FileOutputStream os) throws

/**
* Compute approximate content length for form data
* @return
* @return ArrayList<FormField>
*/
private ArrayList<FormField> countFormDataLength() {
long total = 0;
Expand All @@ -300,11 +296,11 @@ private ArrayList<FormField> countFormDataLength() {
for(int i = 0;i < form.size(); i++) {
FormField field = new FormField(form.getMap(i));
list.add(field);
String data = field.data;
if(data == null) {
if(field.data == null) {
RNFetchBlobUtils.emitWarningEvent("RNFetchBlob multipart request builder has found a field without `data` property, the field `"+ field.name +"` will be removed implicitly.");
}
else if (field.filename != null) {
String data = field.data;
// upload from storage
if (data.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
String orgPath = data.substring(RNFetchBlobConst.FILE_PREFIX.length());
Expand Down Expand Up @@ -333,7 +329,7 @@ else if (field.filename != null) {
}
// data field
else {
total += field.data != null ? field.data.getBytes().length : 0;
total += field.data.getBytes().length;
}
}
contentLength = total;
Expand All @@ -346,11 +342,11 @@ else if (field.filename != null) {
*/
private class FormField {
public String name;
public String filename;
public String mime;
String filename;
String mime;
public String data;

public FormField(ReadableMap rawData) {
FormField(ReadableMap rawData) {
if(rawData.hasKey("name"))
name = rawData.getString("name");
if(rawData.hasKey("filename"))
Expand All @@ -368,7 +364,7 @@ public FormField(ReadableMap rawData) {

/**
* Emit progress event
* @param written
* @param written Integer
*/
private void emitUploadProgress(int written) {
RNFetchBlobProgressConfig config = RNFetchBlobReq.getReportUploadProgress(mTaskId);
Expand Down
5 changes: 1 addition & 4 deletions android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;

import java.util.HashMap;


public class RNFetchBlobConfig {
class RNFetchBlobConfig {

public Boolean fileCache;
public String path;
Expand Down
Loading