Skip to content

Commit d490a3b

Browse files
authored
Merge pull request #449 from sonudoo/bug-fix-interrupted-downloads
Bug fix for download interruption promise rejection
2 parents 9931f1e + d03a502 commit d490a3b

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,16 +530,26 @@ private void done(Response resp) {
530530
}
531531
break;
532532
case FileStorage:
533+
ResponseBody responseBody = resp.body();
534+
533535
try {
534536
// In order to write response data to `destPath` we have to invoke this method.
535537
// It uses customized response body which is able to report download progress
536538
// and write response data to destination path.
537-
resp.body().bytes();
539+
responseBody.bytes();
538540
} catch (Exception ignored) {
539541
// ignored.printStackTrace();
540542
}
541-
this.destPath = this.destPath.replace("?append=true", "");
542-
callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
543+
544+
RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
545+
546+
if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){
547+
callback.invoke("RNFetchBlob failed. Download interrupted.", null);
548+
}
549+
else {
550+
this.destPath = this.destPath.replace("?append=true", "");
551+
callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
552+
}
543553
break;
544554
default:
545555
try {

android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class RNFetchBlobFileResp extends ResponseBody {
3333
long bytesDownloaded = 0;
3434
ReactApplicationContext rctContext;
3535
FileOutputStream ofStream;
36+
boolean isEndMarkerReceived;
3637

3738
public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException {
3839
super();
@@ -41,6 +42,7 @@ public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseB
4142
this.originalBody = body;
4243
assert path != null;
4344
this.mPath = path;
45+
this.isEndMarkerReceived = false;
4446
if (path != null) {
4547
boolean appendToExistingFile = !overwrite;
4648
path = path.replace("?append=true", "");
@@ -68,6 +70,11 @@ public long contentLength() {
6870
return originalBody.contentLength();
6971
}
7072

73+
public boolean isDownloadComplete() {
74+
return (bytesDownloaded == contentLength()) // Case of non-chunked downloads
75+
|| (contentLength() == -1 && isEndMarkerReceived); // Case of chunked downloads
76+
}
77+
7178
@Override
7279
public BufferedSource source() {
7380
ProgressReportingSource countable = new ProgressReportingSource();
@@ -83,22 +90,49 @@ public long read(@NonNull Buffer sink, long byteCount) throws IOException {
8390
bytesDownloaded += read > 0 ? read : 0;
8491
if (read > 0) {
8592
ofStream.write(bytes, 0, (int) read);
93+
} else if (contentLength() == -1 && read == -1) {
94+
// End marker has been received for chunked download
95+
isEndMarkerReceived = true;
8696
}
8797
RNFetchBlobProgressConfig reportConfig = RNFetchBlobReq.getReportProgress(mTaskId);
88-
if (reportConfig != null && contentLength() != 0 &&reportConfig.shouldReport(bytesDownloaded / contentLength())) {
89-
WritableMap args = Arguments.createMap();
90-
args.putString("taskId", mTaskId);
91-
args.putString("written", String.valueOf(bytesDownloaded));
92-
args.putString("total", String.valueOf(contentLength()));
93-
rctContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
94-
.emit(RNFetchBlobConst.EVENT_PROGRESS, args);
98+
99+
if (contentLength() != 0) {
100+
101+
// For non-chunked download, progress is received / total
102+
// For chunked download, progress can be either 0 (started) or 1 (ended)
103+
float progress = (contentLength() != -1) ? bytesDownloaded / contentLength() : ( ( isEndMarkerReceived ) ? 1 : 0 );
104+
105+
if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) {
106+
if (contentLength() != -1) {
107+
// For non-chunked downloads
108+
reportProgress(mTaskId, bytesDownloaded, contentLength());
109+
} else {
110+
// For chunked downloads
111+
if (!isEndMarkerReceived) {
112+
reportProgress(mTaskId, 0, contentLength());
113+
} else{
114+
reportProgress(mTaskId, bytesDownloaded, bytesDownloaded);
115+
}
116+
}
117+
}
118+
95119
}
120+
96121
return read;
97122
} catch(Exception ex) {
98123
return -1;
99124
}
100125
}
101126

127+
private void reportProgress(String taskId, long bytesDownloaded, long contentLength) {
128+
WritableMap args = Arguments.createMap();
129+
args.putString("taskId", taskId);
130+
args.putString("written", String.valueOf(bytesDownloaded));
131+
args.putString("total", String.valueOf(contentLength));
132+
rctContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
133+
.emit(RNFetchBlobConst.EVENT_PROGRESS, args);
134+
}
135+
102136
@Override
103137
public Timeout timeout() {
104138
return null;

0 commit comments

Comments
 (0)