Skip to content

Commit 55abe45

Browse files
- Added logic that introduces the concept of transformers
- adding logic for the library to throw up errors when the library consumer specifies data to be transformed but a transformer has not been set.
1 parent 1512092 commit 55abe45

18 files changed

+230
-16
lines changed

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,11 @@ public void removeSession(ReadableArray paths, Callback callback) {
233233
}
234234

235235
@ReactMethod
236-
public void readFile(final String path, final String encoding, final Promise promise) {
236+
public void readFile(final String path, final String encoding, final boolean transformFile, final Promise promise) {
237237
threadPool.execute(new Runnable() {
238238
@Override
239239
public void run() {
240-
ReactNativeBlobUtilFS.readFile(path, encoding, promise);
240+
ReactNativeBlobUtilFS.readFile(path, encoding, transformFile, promise);
241241
}
242242
});
243243
}
@@ -253,11 +253,11 @@ public void run() {
253253
}
254254

255255
@ReactMethod
256-
public void writeFile(final String path, final String encoding, final String data, final boolean append, final Promise promise) {
256+
public void writeFile(final String path, final String encoding, final String data, final boolean transformFile, final boolean append, final Promise promise) {
257257
threadPool.execute(new Runnable() {
258258
@Override
259259
public void run() {
260-
ReactNativeBlobUtilFS.writeFile(path, encoding, data, append, promise);
260+
ReactNativeBlobUtilFS.writeFile(path, encoding, data, transformFile, append, promise);
261261
}
262262
});
263263
}

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
class ReactNativeBlobUtilConfig {
99

1010
public Boolean fileCache;
11+
public Boolean transformFile;
1112
public String path;
1213
public String appendExt;
1314
public ReadableMap addAndroidDownloads;
@@ -26,6 +27,7 @@ class ReactNativeBlobUtilConfig {
2627
if (options == null)
2728
return;
2829
this.fileCache = options.hasKey("fileCache") && options.getBoolean("fileCache");
30+
this.transformFile = options.hasKey("transformFile") ? options.getBoolean("transformFile") : false;
2931
this.path = options.hasKey("path") ? options.getString("path") : null;
3032
this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
3133
this.trusty = options.hasKey("trusty") && options.getBoolean("trusty");

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ static boolean writeFile(String path, String encoding, String data, final boolea
121121
* @param data Array passed from JS context.
122122
* @param promise RCT Promise
123123
*/
124-
static void writeFile(String path, String encoding, String data, final boolean append, final Promise promise) {
124+
static void writeFile(String path, String encoding, String data, final boolean transformFile, final boolean append, final Promise promise) {
125125
try {
126126
int written;
127127
File f = new File(path);
@@ -169,6 +169,12 @@ static void writeFile(String path, String encoding, String data, final boolean a
169169
}
170170
} else {
171171
byte[] bytes = ReactNativeBlobUtilUtils.stringToBytes(data, encoding);
172+
if (transformFile) {
173+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
174+
throw new IllegalStateException("Write file with transform was specified but the shared file transformer is not set");
175+
}
176+
bytes = ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(bytes);
177+
}
172178
FileOutputStream fout = new FileOutputStream(f, append);
173179
try {
174180
fout.write(bytes);
@@ -237,7 +243,7 @@ static void writeFile(String path, ReadableArray data, final boolean append, fin
237243
* @param encoding Encoding of read stream.
238244
* @param promise JS promise
239245
*/
240-
static void readFile(String path, String encoding, final Promise promise) {
246+
static void readFile(String path, String encoding, final boolean transformFile, final Promise promise) {
241247
String resolved = ReactNativeBlobUtilUtils.normalizePath(path);
242248
if (resolved != null)
243249
path = resolved;
@@ -280,6 +286,13 @@ else if (resolved == null) {
280286
return;
281287
}
282288

289+
if (transformFile) {
290+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
291+
throw new IllegalStateException("Read file with transform was specified but the shared file transformer is not set");
292+
}
293+
bytes = ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onReadFile(bytes);
294+
}
295+
283296
switch (encoding.toLowerCase(Locale.ROOT)) {
284297
case "base64":
285298
promise.resolve(Base64.encodeToString(bytes, Base64.NO_WRAP));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ReactNativeBlobUtil;
2+
3+
public class ReactNativeBlobUtilFileTransformer {
4+
public interface FileTransformer {
5+
public byte[] onWriteFile(byte[] data);
6+
public byte[] onReadFile(byte[] data);
7+
}
8+
9+
public static ReactNativeBlobUtilFileTransformer.FileTransformer sharedFileTransformer;
10+
}

android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java

+26-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ enum ResponseFormat {
8787
BASE64
8888
}
8989

90+
private boolean shouldTransformFile() {
91+
return this.options.transformFile &&
92+
// Can only process if it's written to a file
93+
(this.options.fileCache || this.options.path != null);
94+
}
95+
9096
public static HashMap<String, Call> taskTable = new HashMap<>();
9197
public static HashMap<String, Long> androidDownloadManagerTaskTable = new HashMap<>();
9298
static HashMap<String, ReactNativeBlobUtilProgressConfig> progressReport = new HashMap<>();
@@ -124,7 +130,9 @@ public ReactNativeBlobUtilReq(ReadableMap options, String taskId, String method,
124130
this.rawRequestBodyArray = arrayBody;
125131
this.client = client;
126132

127-
if (this.options.fileCache || this.options.path != null)
133+
// If transformFile is specified, we first want to get the response back in memory so we can
134+
// encrypt it wholesale and at that point, write it into the file storage.
135+
if((this.options.fileCache || this.options.path != null) && !this.shouldTransformFile())
128136
responseType = ResponseType.FileStorage;
129137
else
130138
responseType = ResponseType.KeepInMemory;
@@ -557,6 +565,23 @@ private void done(Response resp) {
557565
// response data directly pass to JS context as string.
558566
else {
559567
byte[] b = resp.body().bytes();
568+
// If process file option is turned on, we first keep response in memory and then stream that content
569+
// after processing
570+
if (this.shouldTransformFile()) {
571+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
572+
throw new IllegalStateException("Write file with transform was specified but the shared file transformer is not set");
573+
}
574+
this.destPath = this.destPath.replace("?append=true", "");
575+
File file = new File(this.destPath);
576+
if (!file.exists()) {
577+
file.createNewFile();
578+
}
579+
try (FileOutputStream fos = new FileOutputStream(file)) {
580+
fos.write(ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(b));
581+
}
582+
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
583+
return;
584+
}
560585
if (responseFormat == ResponseFormat.BASE64) {
561586
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
562587
return;

fs.js

+41-2
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,20 @@ function readFile(path: string, encoding: string = 'utf8'): Promise<any> {
160160
if (typeof path !== 'string') {
161161
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
162162
}
163-
return ReactNativeBlobUtil.readFile(path, encoding);
163+
return ReactNativeBlobUtil.readFile(path, encoding, false);
164+
}
165+
166+
/**
167+
* Reads the file, then transforms it before returning the content
168+
* @param {string} path Path of the file.
169+
* @param {'base64' | 'utf8' | 'ascii'} encoding Encoding of read stream.
170+
* @return {Promise<Array<number> | string>}
171+
*/
172+
function readFileWithTransform(path: string, encoding: string = 'utf8'): Promise<any> {
173+
if (typeof path !== 'string') {
174+
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
175+
}
176+
return ReactNativeBlobUtil.readFile(path, encoding, true);
164177
}
165178

166179
/**
@@ -186,7 +199,31 @@ function writeFile(path: string, data: string | Array<number>, encoding: ?string
186199
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)));
187200
}
188201
else
189-
return ReactNativeBlobUtil.writeFile(path, encoding, data, false);
202+
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, false);
203+
}
204+
}
205+
206+
/**
207+
* Transforms the data and then writes to the file.
208+
* @param {string} path Path of the file.
209+
* @param {string | number[]} data Data to write to the file.
210+
* @param {string} encoding Encoding of data (Optional).
211+
* @return {Promise}
212+
*/
213+
function writeFileWithTransform(path: string, data: string | Array<number>, encoding: ?string = 'utf8'): Promise {
214+
if (typeof path !== 'string') {
215+
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
216+
}
217+
if (encoding.toLocaleLowerCase() === 'ascii') {
218+
return Promise.reject(addCode('EINVAL', new TypeError('ascii is not supported for converted files')))
219+
}
220+
else {
221+
if (typeof data !== 'string') {
222+
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)))
223+
}
224+
225+
else
226+
return ReactNativeBlobUtil.writeFile(path, encoding, data, true, false)
190227
}
191228
}
192229

@@ -415,6 +452,8 @@ export default {
415452
cp,
416453
writeStream,
417454
writeFile,
455+
writeFileWithTransform,
456+
readFileWithTransform,
418457
appendFile,
419458
pathForAppGroup,
420459
syncPathAppGroup,

index.d.ts

+22
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ export interface FS {
399399
*/
400400
writeFile(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
401401

402+
/**
403+
* Processes the data and then writes to the file.
404+
* @param path Path of the file.
405+
* @param data Data to write to the file.
406+
* @param encoding Encoding of data (Optional).
407+
*/
408+
writeFileWithTransform(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
409+
402410
appendFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise<number>;
403411

404412
/**
@@ -408,6 +416,13 @@ export interface FS {
408416
*/
409417
readFile(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
410418

419+
/**
420+
* Reads from a file and then processes the data before returning
421+
* @param path Path of the file.
422+
* @param encoding Encoding of read stream.
423+
*/
424+
readFileWithTransform(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
425+
411426
/**
412427
* Check if file exists and if it is a folder.
413428
* @param path Path to check
@@ -698,6 +713,13 @@ export interface ReactNativeBlobUtilConfig {
698713
*/
699714
fileCache?: boolean;
700715

716+
/**
717+
* Set this property to true if you want the data to be processed before it gets written onto disk.
718+
* This only has effect if the FileTransformer has been registered and the library is configured to write
719+
* response onto disk.
720+
*/
721+
transformFile?: boolean;
722+
701723
/**
702724
* Set this property to change temp file extension that created by fetch response data.
703725
*/

ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
8C4801A6200CF71700FED7ED /* ReactNativeBlobUtilRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4801A5200CF71700FED7ED /* ReactNativeBlobUtilRequest.m */; };
11+
9FD8D3C326F1736000009F35 /* ReactNativeBlobUtilFileTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FD8D3C226F1736000009F35 /* ReactNativeBlobUtilFileTransformer.m */; };
1112
A158F4271D052E49006FFD38 /* ReactNativeBlobUtilFS.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F4261D052E49006FFD38 /* ReactNativeBlobUtilFS.m */; };
1213
A158F42D1D0535BB006FFD38 /* ReactNativeBlobUtilConst.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42C1D0535BB006FFD38 /* ReactNativeBlobUtilConst.m */; };
1314
A158F4301D0539DB006FFD38 /* ReactNativeBlobUtilNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* ReactNativeBlobUtilNetwork.m */; };
@@ -32,6 +33,8 @@
3233
/* Begin PBXFileReference section */
3334
8C4801A4200CF71700FED7ED /* ReactNativeBlobUtilRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativeBlobUtilRequest.h; sourceTree = "<group>"; };
3435
8C4801A5200CF71700FED7ED /* ReactNativeBlobUtilRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeBlobUtilRequest.m; sourceTree = "<group>"; };
36+
9FD8D3C126F1709A00009F35 /* ReactNativeBlobUtilFileTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativeBlobUtilFileTransformer.h; sourceTree = "<group>"; };
37+
9FD8D3C226F1736000009F35 /* ReactNativeBlobUtilFileTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeBlobUtilFileTransformer.m; sourceTree = "<group>"; };
3538
A158F4261D052E49006FFD38 /* ReactNativeBlobUtilFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativeBlobUtilFS.m; sourceTree = "<group>"; };
3639
A158F4281D052E57006FFD38 /* ReactNativeBlobUtilFS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativeBlobUtilFS.h; sourceTree = "<group>"; };
3740
A158F4291D0534A9006FFD38 /* ReactNativeBlobUtilConst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactNativeBlobUtilConst.h; sourceTree = "<group>"; };
@@ -69,6 +72,8 @@
6972
A15C30051CD25C330074CB35 = {
7073
isa = PBXGroup;
7174
children = (
75+
9FD8D3C226F1736000009F35 /* ReactNativeBlobUtilFileTransformer.m */,
76+
9FD8D3C126F1709A00009F35 /* ReactNativeBlobUtilFileTransformer.h */,
7277
A19B48241D98102400E6868A /* ReactNativeBlobUtilProgress.m */,
7378
A19B48231D98100800E6868A /* ReactNativeBlobUtilProgress.h */,
7479
A1F950181D7E9134002A95A6 /* IOS7Polyfill.h */,
@@ -156,6 +161,7 @@
156161
A166D1AA1CE0647A00273590 /* ReactNativeBlobUtil.h in Sources */,
157162
8C4801A6200CF71700FED7ED /* ReactNativeBlobUtilRequest.m in Sources */,
158163
A158F42D1D0535BB006FFD38 /* ReactNativeBlobUtilConst.m in Sources */,
164+
9FD8D3C326F1736000009F35 /* ReactNativeBlobUtilFileTransformer.m in Sources */,
159165
A158F4271D052E49006FFD38 /* ReactNativeBlobUtilFS.m in Sources */,
160166
A158F4301D0539DB006FFD38 /* ReactNativeBlobUtilNetwork.m in Sources */,
161167
A19B48251D98102400E6868A /* ReactNativeBlobUtilProgress.m in Sources */,

ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m

+4-3
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ - (NSDictionary *)constantsToExport
252252
}
253253

254254
#pragma mark - fs.writeFile
255-
RCT_EXPORT_METHOD(writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
255+
RCT_EXPORT_METHOD(writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data transformFile:(BOOL)transformFile append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
256256
{
257-
[ReactNativeBlobUtilFS writeFile:path encoding:[NSString stringWithString:encoding] data:data append:append resolver:resolve rejecter:reject];
257+
[ReactNativeBlobUtilFS writeFile:path encoding:[NSString stringWithString:encoding] data:data transformFile:transformFile append:append resolver:resolve rejecter:reject];
258258
}
259259

260260
#pragma mark - fs.writeArray
@@ -494,11 +494,12 @@ - (NSDictionary *)constantsToExport
494494
#pragma mark - fs.readFile
495495
RCT_EXPORT_METHOD(readFile:(NSString *)path
496496
encoding:(NSString *)encoding
497+
transformFile:(BOOL) transformFile
497498
resolver:(RCTPromiseResolveBlock)resolve
498499
rejecter:(RCTPromiseRejectBlock)reject)
499500
{
500501

501-
[ReactNativeBlobUtilFS readFile:path encoding:encoding onComplete:^(NSData * content, NSString * code, NSString * err) {
502+
[ReactNativeBlobUtilFS readFile:path encoding:encoding transformFile:transformFile onComplete:^(NSData * content, NSString * code, NSString * err) {
502503
if(err != nil) {
503504
reject(code, err, nil);
504505
return;

ios/ReactNativeBlobUtilConst.h

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern NSString *const AL_PREFIX;
2929

3030
// config
3131
extern NSString *const CONFIG_USE_TEMP;
32+
extern NSString *const CONFIG_TRANSFORM_FILE;
3233
extern NSString *const CONFIG_FILE_PATH;
3334
extern NSString *const CONFIG_FILE_EXT;
3435
extern NSString *const CONFIG_TRUSTY;

ios/ReactNativeBlobUtilConst.m

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
// fetch configs
1515
NSString *const CONFIG_USE_TEMP = @"fileCache";
16+
NSString *const CONFIG_TRANSFORM_FILE = @"transformFile";
1617
NSString *const CONFIG_FILE_PATH = @"path";
1718
NSString *const CONFIG_FILE_EXT = @"appendExt";
1819
NSString *const CONFIG_TRUSTY = @"trusty";

ios/ReactNativeBlobUtilFS.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
+ (NSDictionary *) stat:(NSString *) path error:(NSError **) error;
7373
+ (void) exists:(NSString *) path callback:(RCTResponseSenderBlock)callback;
7474
+ (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
75-
+ (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
75+
+ (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data transformFile:(BOOL)transformFile append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
76+
+ (void) readFile:(NSString *)path encoding:(NSString *)encoding transformFile:(BOOL)transformFile onComplete:(void (^)(NSData * content, NSString* code, NSString * errMsg))onComplete;
7677
+ (void) readFile:(NSString *)path encoding:(NSString *)encoding onComplete:(void (^)(NSData * content, NSString* code, NSString * errMsg))onComplete;
7778
+ (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock;
7879
+ (void) slice:(NSString *)path

0 commit comments

Comments
 (0)