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
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,58 +36,84 @@ 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 ;
53
49
requestType = type ;
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 () {
81
103
return mime ;
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 @@ boolean clearRequestBody() {
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 @@ private long caculateOctetContentLength() {
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 @@ private File createMultipartBodyCache() throws IOException {
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,16 +215,14 @@ private File createMultipartBodyCache() throws IOException {
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
}
209
222
// base64 embedded file content
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 @@ private File createMultipartBodyCache() throws IOException {
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 @@ private File createMultipartBodyCache() throws IOException {
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,45 +359,19 @@ public FormField(ReadableMap rawData) {
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
365
373
RNFetchBlob .RCTContext .getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
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
}
0 commit comments