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

Commit 22db84f

Browse files
committed
Move IOS fs.readStream buffer to heap
1 parent 347ebaa commit 22db84f

File tree

2 files changed

+141
-134
lines changed

2 files changed

+141
-134
lines changed

src/ios/RNFetchBlobFS.m

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,19 +127,20 @@ + (void) readStream:(NSString *)uri
127127
[[self class] getPathFromUri:uri completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
128128

129129
RCTEventDispatcher * event = bridgeRef.eventDispatcher;
130+
int read = 0;
131+
int chunkSize = bufferSize;
132+
// allocate buffer in heap instead of stack
133+
uint8_t * buffer = (uint8_t *) malloc(bufferSize);
130134
@try
131135
{
132-
int read = 0;
133-
int chunkSize = bufferSize;
134-
uint8_t * buffer[bufferSize];
135-
136136
if(path != nil)
137137
{
138138
if([[NSFileManager defaultManager] fileExistsAtPath:path] == NO)
139139
{
140140
NSString * message = [NSString stringWithFormat:@"File not exists at path %@", path];
141141
NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": message };
142142
[event sendDeviceEventWithName:streamId body:payload];
143+
free(buffer);
143144
return ;
144145
}
145146
NSInputStream * stream = [[NSInputStream alloc] initWithFileAtPath:path];
@@ -165,6 +166,7 @@ + (void) readStream:(NSString *)uri
165166
NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": @"RNFetchBlob.readStream unable to resolve URI" };
166167
[event sendDeviceEventWithName:streamId body:payload];
167168
}
169+
168170
}
169171
@catch (NSError * err)
170172
{
@@ -173,6 +175,8 @@ + (void) readStream:(NSString *)uri
173175
}
174176
@finally
175177
{
178+
// release buffer
179+
free(buffer);
176180
NSDictionary * payload = @{ @"event": FS_EVENT_END, @"detail": @"" };
177181
[event sendDeviceEventWithName:streamId body:payload];
178182
}

test/test-0.9.4.js

Lines changed: 133 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -27,84 +27,84 @@ const dirs = RNFetchBlob.fs.dirs
2727

2828
let prefix = ((Platform.OS === 'android') ? 'file://' : '')
2929

30-
describe('issue #105', (report, done) => {
31-
let tmp = null
32-
RNFetchBlob
33-
.config({ fileCache : true })
34-
.fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
35-
.then((res) => {
36-
tmp = res.path()
37-
return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {
38-
'Content-Type' : 'multipart/form-data',
39-
'Expect' : '100-continue'
40-
}, [
41-
{ name : 'data', data : 'issue#105 test' },
42-
{ name : 'file', filename : 'github.png', data : RNFetchBlob.wrap(tmp) }
43-
])
44-
})
45-
.then((res) => {
46-
done()
47-
})
48-
})
49-
50-
describe('issue #106', (report, done) => {
51-
52-
fetch('https://rnfb-test-app.firebaseapp.com/6m-json.json')
53-
.then((res) => {
54-
console.log('## converted')
55-
return res.json()
56-
})
57-
.then((data) => {
58-
// console.log(data)
59-
report(<Assert key="fetch request success" expect={20000} actual={data.total}/>)
60-
done()
61-
})
62-
63-
})
64-
65-
describe('issue #111 get redirect destination', (report, done) => {
66-
RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/redirect`)
67-
.then((res) => {
68-
report(
69-
<Assert key="redirect history should tracable"
70-
expect={2}
71-
actual={res.info().redirects.length}/>,
72-
<Assert key="redirect history verify"
73-
expect={[`${TEST_SERVER_URL}/redirect`, `${TEST_SERVER_URL}/public/github.png`]}
74-
comparer={Comparer.equalToArray}
75-
actual={res.info().redirects}/>,
76-
)
77-
done()
78-
})
79-
})
80-
81-
describe('chunked encoding option test', (report, done) => {
82-
83-
let path = null
84-
let base64 = null
85-
86-
RNFetchBlob
87-
// .config({ fileCache : true })
88-
.fetch('GET', `${TEST_SERVER_URL}/public/1600k-img-dummy.jpg`)
89-
.then((res) => {
90-
base64 = res.base64()
91-
return RNFetchBlob
92-
.fetch('POST', `${TEST_SERVER_URL}/upload`, {
93-
'Content-Type' : 'application/octet-stream;BASE64'
94-
}, base64)
95-
})
96-
.then((res) => {
97-
let headers = res.info().headers
98-
console.log(res.text())
99-
report(<Assert key="request should not use chunked encoding"
100-
expect={undefined}
101-
actual={headers['transfer-encoding']}/>)
102-
fs.unlink(path)
103-
done()
104-
})
105-
})
106-
107-
describe('#118 ', (report, done) => {
30+
// describe('issue #105', (report, done) => {
31+
// let tmp = null
32+
// RNFetchBlob
33+
// .config({ fileCache : true })
34+
// .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
35+
// .then((res) => {
36+
// tmp = res.path()
37+
// return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {
38+
// 'Content-Type' : 'multipart/form-data',
39+
// 'Expect' : '100-continue'
40+
// }, [
41+
// { name : 'data', data : 'issue#105 test' },
42+
// { name : 'file', filename : 'github.png', data : RNFetchBlob.wrap(tmp) }
43+
// ])
44+
// })
45+
// .then((res) => {
46+
// done()
47+
// })
48+
// })
49+
//
50+
// describe('issue #106', (report, done) => {
51+
//
52+
// fetch('https://rnfb-test-app.firebaseapp.com/6m-json.json')
53+
// .then((res) => {
54+
// console.log('## converted')
55+
// return res.json()
56+
// })
57+
// .then((data) => {
58+
// // console.log(data)
59+
// report(<Assert key="fetch request success" expect={20000} actual={data.total}/>)
60+
// done()
61+
// })
62+
//
63+
// })
64+
//
65+
// describe('issue #111 get redirect destination', (report, done) => {
66+
// RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/redirect`)
67+
// .then((res) => {
68+
// report(
69+
// <Assert key="redirect history should tracable"
70+
// expect={2}
71+
// actual={res.info().redirects.length}/>,
72+
// <Assert key="redirect history verify"
73+
// expect={[`${TEST_SERVER_URL}/redirect`, `${TEST_SERVER_URL}/public/github.png`]}
74+
// comparer={Comparer.equalToArray}
75+
// actual={res.info().redirects}/>,
76+
// )
77+
// done()
78+
// })
79+
// })
80+
//
81+
// describe('chunked encoding option test', (report, done) => {
82+
//
83+
// let path = null
84+
// let base64 = null
85+
//
86+
// RNFetchBlob
87+
// // .config({ fileCache : true })
88+
// .fetch('GET', `${TEST_SERVER_URL}/public/1600k-img-dummy.jpg`)
89+
// .then((res) => {
90+
// base64 = res.base64()
91+
// return RNFetchBlob
92+
// .fetch('POST', `${TEST_SERVER_URL}/upload`, {
93+
// 'Content-Type' : 'application/octet-stream;BASE64'
94+
// }, base64)
95+
// })
96+
// .then((res) => {
97+
// let headers = res.info().headers
98+
// console.log(res.text())
99+
// report(<Assert key="request should not use chunked encoding"
100+
// expect={undefined}
101+
// actual={headers['transfer-encoding']}/>)
102+
// fs.unlink(path)
103+
// done()
104+
// })
105+
// })
106+
107+
describe('#118 readStream performance prepare the file', (report, done) => {
108108
let cache = null
109109
let size = 0
110110
let tick = Date.now()
@@ -114,59 +114,62 @@ describe('#118 ', (report, done) => {
114114
RNFetchBlob.config({fileCache : true})
115115
.fetch('GET', `${TEST_SERVER_URL}/public/22mb-dummy`)
116116
.then((res) => {
117+
report(<Info key="preparation complete"><Text>start in 3 seconds</Text></Info>)
117118
cache = res.path()
118-
return fs.readStream(cache, 'utf8', 102400)
119+
setTimeout(() => {
120+
fs.readStream(cache, 'utf8', 102400)
121+
.then((stream) => {
122+
stream.open()
123+
start = Date.now()
124+
stream.onData((chunk) => {
125+
count++
126+
size += chunk.length
127+
if(Date.now() - tick > 500) {
128+
tick = Date.now()
129+
report(
130+
<Info key="size" uid="100"><Text>{size} bytes read</Text></Info>)
131+
}
132+
})
133+
stream.onEnd(() => {
134+
report(
135+
<Info key="size" uid="100"><Text>{size} bytes read</Text></Info>,
136+
<Info key="elapsed"><Text>{Date.now() - start} ms</Text></Info>,
137+
<Info key="events"><Text>{count} times</Text></Info>,
138+
<Assert key="JS thread is not blocked" expect={true} actual={true}/>,)
139+
fs.stat(cache).then((stat) => {
140+
report(
141+
<Info key="info"><Text>{JSON.stringify(stat)}</Text></Info>)
142+
fs.unlink(cache)
143+
done()
144+
})
145+
})
146+
})
147+
}, 3000)
119148
})
120-
.then((stream) => {
121-
stream.open()
122-
start = Date.now()
123-
stream.onData((chunk) => {
124-
count++
125-
size += chunk.length
126-
if(Date.now() - tick > 500) {
127-
tick = Date.now()
128-
report(
129-
<Info key="size" uid="100"><Text>{size} bytes read</Text></Info>)
130-
}
131-
})
132-
stream.onEnd(() => {
133-
report(
134-
<Info key="size" uid="100"><Text>{size} bytes read</Text></Info>,
135-
<Info key="elapsed"><Text>{Date.now() - start} ms</Text></Info>,
136-
<Info key="events"><Text>{count} times</Text></Info>,
137-
<Assert key="JS thread is not blocked" expect={true} actual={true}/>,)
138-
fs.stat(cache).then((stat) => {
139-
report(
140-
<Info key="info"><Text>{JSON.stringify(stat)}</Text></Info>)
141-
fs.unlink(cache)
142-
})
143-
})
144-
})
145-
146149
})
147150

148-
describe('issue #120 upload progress should work when sending body as-is', (report, done) => {
149-
150-
let data = RNTest.prop('image')
151-
let tick = 0
152-
153-
let task = RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
154-
Authorization : `Bearer ${DROPBOX_TOKEN}`,
155-
'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+FILENAME+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
156-
'Content-Type' : 'text/plain; charset=dropbox-cors-hack',
157-
}, data)
158-
159-
task.uploadProgress((current, total) => {
160-
tick ++
161-
})
162-
.then((res) => {
163-
let resp = res.json()
164-
report(
165-
<Info key="viewer"><Text>{JSON.stringify(resp)}</Text></Info>,
166-
<Assert key="event should be triggered"
167-
expect={tick}
168-
comparer={Comparer.greater} actual={0}/>)
169-
done()
170-
})
171-
172-
})
151+
// describe('issue #120 upload progress should work when sending body as-is', (report, done) => {
152+
//
153+
// let data = RNTest.prop('image')
154+
// let tick = 0
155+
//
156+
// let task = RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
157+
// Authorization : `Bearer ${DROPBOX_TOKEN}`,
158+
// 'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+FILENAME+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
159+
// 'Content-Type' : 'text/plain; charset=dropbox-cors-hack',
160+
// }, data)
161+
//
162+
// task.uploadProgress((current, total) => {
163+
// tick ++
164+
// })
165+
// .then((res) => {
166+
// let resp = res.json()
167+
// report(
168+
// <Info key="viewer"><Text>{JSON.stringify(resp)}</Text></Info>,
169+
// <Assert key="event should be triggered"
170+
// expect={tick}
171+
// comparer={Comparer.greater} actual={0}/>)
172+
// done()
173+
// })
174+
//
175+
// })

0 commit comments

Comments
 (0)