|
@@ -1,7 +1,6 @@
|
1
|
1
|
package com.RNFetchBlob;
|
2
|
2
|
|
3
|
3
|
import android.util.Base64;
|
4
|
|
-import android.util.Log;
|
5
|
4
|
|
6
|
5
|
import com.facebook.react.bridge.Arguments;
|
7
|
6
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
@@ -13,23 +12,14 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
13
|
12
|
import java.io.ByteArrayInputStream;
|
14
|
13
|
import java.io.File;
|
15
|
14
|
import java.io.FileInputStream;
|
16
|
|
-import java.io.FileNotFoundException;
|
17
|
15
|
import java.io.FileOutputStream;
|
18
|
16
|
import java.io.IOException;
|
19
|
17
|
import java.io.InputStream;
|
20
|
|
-import java.nio.ByteBuffer;
|
21
|
|
-import java.nio.MappedByteBuffer;
|
22
|
18
|
import java.util.ArrayList;
|
23
|
|
-import java.util.HashMap;
|
24
|
19
|
|
25
|
20
|
import okhttp3.MediaType;
|
26
|
21
|
import okhttp3.RequestBody;
|
27
|
|
-import okhttp3.FormBody;
|
28
|
|
-import okio.Buffer;
|
29
|
22
|
import okio.BufferedSink;
|
30
|
|
-import okio.ForwardingSink;
|
31
|
|
-import okio.Okio;
|
32
|
|
-import okio.Sink;
|
33
|
23
|
|
34
|
24
|
/**
|
35
|
25
|
* Created by wkh237 on 2016/7/11.
|
|
@@ -38,7 +28,6 @@ public class RNFetchBlobBody extends RequestBody{
|
38
|
28
|
|
39
|
29
|
InputStream requestStream;
|
40
|
30
|
long contentLength = 0;
|
41
|
|
- long bytesWritten = 0;
|
42
|
31
|
ReadableArray form;
|
43
|
32
|
String mTaskId;
|
44
|
33
|
String rawBody;
|
|
@@ -47,6 +36,13 @@ public class RNFetchBlobBody extends RequestBody{
|
47
|
36
|
File bodyCache;
|
48
|
37
|
|
49
|
38
|
|
|
39
|
+ /**
|
|
40
|
+ * Single file or raw content request constructor
|
|
41
|
+ * @param taskId
|
|
42
|
+ * @param type
|
|
43
|
+ * @param form
|
|
44
|
+ * @param contentType
|
|
45
|
+ */
|
50
|
46
|
public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, ReadableArray form, MediaType contentType) {
|
51
|
47
|
this.mTaskId = taskId;
|
52
|
48
|
this.form = form;
|
|
@@ -54,27 +50,53 @@ public class RNFetchBlobBody extends RequestBody{
|
54
|
50
|
mime = contentType;
|
55
|
51
|
try {
|
56
|
52
|
bodyCache = createMultipartBodyCache();
|
|
53
|
+ requestStream = new FileInputStream(bodyCache);
|
57
|
54
|
contentLength = bodyCache.length();
|
58
|
|
- } catch (IOException e) {
|
59
|
|
- e.printStackTrace();
|
|
55
|
+ } catch(Exception ex) {
|
|
56
|
+ ex.printStackTrace();
|
|
57
|
+ RNFetchBlobUtils.emitWarningEvent("RNFetchBlob failed to create request multipart body :" + ex.getLocalizedMessage());
|
60
|
58
|
}
|
61
|
59
|
}
|
62
|
60
|
|
|
61
|
+ /**
|
|
62
|
+ * Multipart request constructor
|
|
63
|
+ * @param taskId
|
|
64
|
+ * @param type
|
|
65
|
+ * @param rawBody
|
|
66
|
+ * @param contentType
|
|
67
|
+ */
|
63
|
68
|
public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, String rawBody, MediaType contentType) {
|
64
|
69
|
this.mTaskId = taskId;
|
65
|
70
|
requestType = type;
|
66
|
71
|
this.rawBody = rawBody;
|
67
|
72
|
mime = contentType;
|
68
|
|
- if(rawBody != null) {
|
69
|
|
- if(requestType == RNFetchBlobReq.RequestType.AsIs)
|
70
|
|
- contentLength = rawBody.length();
|
71
|
|
- else
|
72
|
|
- contentLength = caculateOctetContentLength();
|
|
73
|
+ if(rawBody == null) {
|
|
74
|
+ this.rawBody = "";
|
|
75
|
+ requestType = RNFetchBlobReq.RequestType.AsIs;
|
|
76
|
+ }
|
|
77
|
+ try {
|
|
78
|
+ switch (requestType) {
|
|
79
|
+ case SingleFile:
|
|
80
|
+ requestStream = getReuqestStream();
|
|
81
|
+ contentLength = requestStream.available();
|
|
82
|
+ break;
|
|
83
|
+ case AsIs:
|
|
84
|
+ contentLength = this.rawBody.getBytes().length;
|
|
85
|
+ break;
|
|
86
|
+ case Others:
|
|
87
|
+ break;
|
|
88
|
+ }
|
|
89
|
+ } catch(Exception ex) {
|
|
90
|
+ ex.printStackTrace();
|
|
91
|
+ RNFetchBlobUtils.emitWarningEvent("RNFetchBlob failed to create single content request body :" + ex.getLocalizedMessage() + "\r\n");
|
73
|
92
|
}
|
|
93
|
+
|
74
|
94
|
}
|
75
|
95
|
|
76
|
|
- // ${RN 0.26+ ONLY} @Override
|
77
|
|
- // ${RN 0.26+ ONLY} public long contentLength() { return contentLength; }
|
|
96
|
+ @Override
|
|
97
|
+ public long contentLength() {
|
|
98
|
+ return contentLength;
|
|
99
|
+ }
|
78
|
100
|
|
79
|
101
|
@Override
|
80
|
102
|
public MediaType contentType() {
|
|
@@ -82,23 +104,16 @@ public class RNFetchBlobBody extends RequestBody{
|
82
|
104
|
}
|
83
|
105
|
|
84
|
106
|
@Override
|
85
|
|
- public void writeTo(BufferedSink sink) throws IOException {
|
86
|
|
-
|
87
|
|
- ProgressReportingSource source = new ProgressReportingSource(sink, mTaskId);
|
88
|
|
- BufferedSink buffer = Okio.buffer(source);
|
89
|
|
- switch (requestType) {
|
90
|
|
- case Form:
|
91
|
|
- pipeStreamToSink(new FileInputStream(bodyCache), sink);
|
92
|
|
- break;
|
93
|
|
- case SingleFile:
|
94
|
|
- if(requestStream != null)
|
95
|
|
- pipeStreamToSink(requestStream, sink);
|
96
|
|
- break;
|
97
|
|
- case AsIs:
|
98
|
|
- writeRawData(sink);
|
99
|
|
- break;
|
|
107
|
+ public void writeTo(BufferedSink sink) {
|
|
108
|
+ try {
|
|
109
|
+ if (requestType == RNFetchBlobReq.RequestType.AsIs)
|
|
110
|
+ sink.write(rawBody.getBytes());
|
|
111
|
+ else
|
|
112
|
+ pipeStreamToSink(requestStream, sink);
|
|
113
|
+ } catch(Exception ex) {
|
|
114
|
+ RNFetchBlobUtils.emitWarningEvent(ex.getLocalizedMessage());
|
|
115
|
+ ex.printStackTrace();
|
100
|
116
|
}
|
101
|
|
- buffer.flush();
|
102
|
117
|
}
|
103
|
118
|
|
104
|
119
|
boolean clearRequestBody() {
|
|
@@ -113,8 +128,8 @@ public class RNFetchBlobBody extends RequestBody{
|
113
|
128
|
return true;
|
114
|
129
|
}
|
115
|
130
|
|
116
|
|
- private long caculateOctetContentLength() {
|
117
|
|
- long total = 0;
|
|
131
|
+ private InputStream getReuqestStream() throws Exception {
|
|
132
|
+
|
118
|
133
|
// upload from storage
|
119
|
134
|
if (rawBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
|
120
|
135
|
String orgPath = rawBody.substring(RNFetchBlobConst.FILE_PREFIX.length());
|
|
@@ -123,32 +138,30 @@ public class RNFetchBlobBody extends RequestBody{
|
123
|
138
|
if (RNFetchBlobFS.isAsset(orgPath)) {
|
124
|
139
|
try {
|
125
|
140
|
String assetName = orgPath.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
|
126
|
|
- total += RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
|
127
|
|
- requestStream = RNFetchBlob.RCTContext.getAssets().open(assetName);
|
128
|
|
- } catch (IOException e) {
|
129
|
|
- RNFetchBlobUtils.emitWarningEvent(e.getLocalizedMessage());
|
|
141
|
+ return RNFetchBlob.RCTContext.getAssets().open(assetName);
|
|
142
|
+ } catch (Exception e) {
|
|
143
|
+ throw new Exception("error when getting request stream from asset : " +e.getLocalizedMessage());
|
130
|
144
|
}
|
131
|
145
|
} else {
|
132
|
146
|
File f = new File(RNFetchBlobFS.normalizePath(orgPath));
|
133
|
147
|
try {
|
134
|
148
|
if(!f.exists())
|
135
|
149
|
f.createNewFile();
|
136
|
|
- total += f.length();
|
137
|
|
- requestStream = new FileInputStream(f);
|
|
150
|
+ return new FileInputStream(f);
|
138
|
151
|
} catch (Exception e) {
|
139
|
|
- RNFetchBlobUtils.emitWarningEvent("RNetchBlob error when counting content length: " +e.getLocalizedMessage());
|
|
152
|
+ throw new Exception("error when getting request stream: " +e.getLocalizedMessage());
|
140
|
153
|
}
|
141
|
154
|
}
|
142
|
|
- } else {
|
|
155
|
+ }
|
|
156
|
+ // base 64 encoded
|
|
157
|
+ else {
|
143
|
158
|
try {
|
144
|
159
|
byte[] bytes = Base64.decode(rawBody, 0);
|
145
|
|
- requestStream = new ByteArrayInputStream(bytes);
|
146
|
|
- total += requestStream.available();
|
|
160
|
+ return new ByteArrayInputStream(bytes);
|
147
|
161
|
} catch(Exception ex) {
|
148
|
|
- RNFetchBlobUtils.emitWarningEvent("RNetchBlob error when counting content length: " +ex.getLocalizedMessage());
|
|
162
|
+ throw new Exception("error when getting request stream: " + ex.getLocalizedMessage());
|
149
|
163
|
}
|
150
|
164
|
}
|
151
|
|
- return total;
|
152
|
165
|
}
|
153
|
166
|
|
154
|
167
|
/**
|
|
@@ -191,7 +204,7 @@ public class RNFetchBlobBody extends RequestBody{
|
191
|
204
|
InputStream in = ctx.getAssets().open(assetName);
|
192
|
205
|
pipeStreamToFileStream(in, os);
|
193
|
206
|
} catch (IOException e) {
|
194
|
|
- RNFetchBlobUtils.emitWarningEvent("RNFetchBlob Failed to create form data asset :" + orgPath + ", " + e.getLocalizedMessage() );
|
|
207
|
+ RNFetchBlobUtils.emitWarningEvent("Failed to create form data asset :" + orgPath + ", " + e.getLocalizedMessage() );
|
195
|
208
|
}
|
196
|
209
|
}
|
197
|
210
|
// data from normal files
|
|
@@ -202,7 +215,7 @@ public class RNFetchBlobBody extends RequestBody{
|
202
|
215
|
pipeStreamToFileStream(fs, os);
|
203
|
216
|
}
|
204
|
217
|
else {
|
205
|
|
- RNFetchBlobUtils.emitWarningEvent("RNFetchBlob Failed to create form data from path :" + orgPath + ", file not exists.");
|
|
218
|
+ RNFetchBlobUtils.emitWarningEvent("Failed to create form data from path :" + orgPath + ", file not exists.");
|
206
|
219
|
}
|
207
|
220
|
}
|
208
|
221
|
}
|
|
@@ -210,8 +223,6 @@ public class RNFetchBlobBody extends RequestBody{
|
210
|
223
|
else {
|
211
|
224
|
byte[] b = Base64.decode(data, 0);
|
212
|
225
|
os.write(b);
|
213
|
|
- bytesWritten += b.length;
|
214
|
|
- emitUploadProgress();
|
215
|
226
|
}
|
216
|
227
|
|
217
|
228
|
}
|
|
@@ -221,7 +232,6 @@ public class RNFetchBlobBody extends RequestBody{
|
221
|
232
|
header += "Content-Type: " + field.mime + "\r\n\r\n";
|
222
|
233
|
os.write(header.getBytes());
|
223
|
234
|
byte[] fieldData = field.data.getBytes();
|
224
|
|
- bytesWritten += fieldData.length;
|
225
|
235
|
os.write(fieldData);
|
226
|
236
|
}
|
227
|
237
|
// form end
|
|
@@ -235,28 +245,22 @@ public class RNFetchBlobBody extends RequestBody{
|
235
|
245
|
return outputFile;
|
236
|
246
|
}
|
237
|
247
|
|
238
|
|
- /**
|
239
|
|
- * Write data to request body as-is
|
240
|
|
- * @param sink
|
241
|
|
- */
|
242
|
|
- private void writeRawData(BufferedSink sink) throws IOException {
|
243
|
|
- byte[] bytes = rawBody.getBytes();
|
244
|
|
- contentLength = bytes.length;
|
245
|
|
- sink.write(bytes);
|
246
|
|
- }
|
247
|
|
-
|
248
|
248
|
/**
|
249
|
249
|
* Pipe input stream to request body output stream
|
250
|
250
|
* @param stream The input stream
|
251
|
251
|
* @param sink The request body buffer sink
|
252
|
252
|
* @throws IOException
|
253
|
253
|
*/
|
254
|
|
- private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws IOException {
|
|
254
|
+ private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws Exception {
|
|
255
|
+
|
255
|
256
|
byte [] chunk = new byte[10240];
|
|
257
|
+ int totalWritten = 0;
|
256
|
258
|
int read;
|
257
|
259
|
while((read = stream.read(chunk, 0, 10240)) > 0) {
|
258
|
260
|
if(read > 0) {
|
259
|
261
|
sink.write(chunk, 0, read);
|
|
262
|
+ totalWritten += read;
|
|
263
|
+ emitUploadProgress(totalWritten);
|
260
|
264
|
}
|
261
|
265
|
}
|
262
|
266
|
stream.close();
|
|
@@ -355,10 +359,14 @@ public class RNFetchBlobBody extends RequestBody{
|
355
|
359
|
}
|
356
|
360
|
}
|
357
|
361
|
|
358
|
|
- private void emitUploadProgress() {
|
|
362
|
+ /**
|
|
363
|
+ * Emit progress event
|
|
364
|
+ * @param written
|
|
365
|
+ */
|
|
366
|
+ private void emitUploadProgress(int written) {
|
359
|
367
|
WritableMap args = Arguments.createMap();
|
360
|
368
|
args.putString("taskId", mTaskId);
|
361
|
|
- args.putString("written", String.valueOf(bytesWritten));
|
|
369
|
+ args.putString("written", String.valueOf(written));
|
362
|
370
|
args.putString("total", String.valueOf(contentLength));
|
363
|
371
|
|
364
|
372
|
// emit event to js context
|
|
@@ -366,34 +374,4 @@ public class RNFetchBlobBody extends RequestBody{
|
366
|
374
|
.emit(RNFetchBlobConst.EVENT_UPLOAD_PROGRESS, args);
|
367
|
375
|
}
|
368
|
376
|
|
369
|
|
- private final class ProgressReportingSource extends ForwardingSink {
|
370
|
|
-
|
371
|
|
- private long bytesWritten = 0;
|
372
|
|
- private String mTaskId;
|
373
|
|
- private Sink delegate;
|
374
|
|
-
|
375
|
|
- public ProgressReportingSource (Sink delegate, String taskId) {
|
376
|
|
- super(delegate);
|
377
|
|
- this.mTaskId = taskId;
|
378
|
|
- this.delegate = delegate;
|
379
|
|
- }
|
380
|
|
-
|
381
|
|
- @Override
|
382
|
|
- public void write(Buffer source, long byteCount) throws IOException {
|
383
|
|
- delegate.write(source, byteCount);
|
384
|
|
- // on progress, emit RNFetchBlobProgress upload progress event with ticketId,
|
385
|
|
- // bytesWritten, and totalSize
|
386
|
|
- bytesWritten += byteCount;
|
387
|
|
- WritableMap args = Arguments.createMap();
|
388
|
|
- args.putString("taskId", mTaskId);
|
389
|
|
- args.putString("written", String.valueOf(bytesWritten));
|
390
|
|
- args.putString("total", String.valueOf(contentLength));
|
391
|
|
-
|
392
|
|
- if(RNFetchBlobReq.isReportUploadProgress(mTaskId)) {
|
393
|
|
- // emit event to js context
|
394
|
|
- RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
395
|
|
- .emit(RNFetchBlobConst.EVENT_UPLOAD_PROGRESS, args);
|
396
|
|
- }
|
397
|
|
- }
|
398
|
|
- }
|
399
|
377
|
}
|