Browse Source

Add JSON stream fs support #99

Ben Hsieh 7 years ago
parent
commit
a81b5f1719
2 changed files with 117 additions and 7 deletions
  1. 88
    1
      src/index.js
  2. 29
    6
      src/json-stream.js

+ 88
- 1
src/index.js View File

@@ -16,6 +16,7 @@ import type {
16 16
   RNFetchBlobStream,
17 17
   RNFetchBlobResponseInfo
18 18
 } from './types'
19
+import URIUtil from './utils/uri'
19 20
 import StatefulPromise from './class/StatefulPromise.js'
20 21
 import fs from './fs'
21 22
 import getUUID from './utils/uuid'
@@ -100,6 +101,86 @@ function config (options:RNFetchBlobConfig) {
100 101
   return { fetch : fetch.bind(options) }
101 102
 }
102 103
 
104
+/**
105
+ * Fetch from file system, use the same interface as RNFB.fetch
106
+ * @param  {RNFetchBlobConfig} [options={}] Fetch configurations
107
+ * @param  {string} method     Should be one of `get`, `post`, `put`
108
+ * @param  {string} url        A file URI string
109
+ * @param  {string} headers    Arguments of file system API
110
+ * @param  {any} body       Data to put or post to file systen.
111
+ * @return {Promise}
112
+ */
113
+function fetchFile(options = {}, method, url, headers = {}, body):Promise {
114
+
115
+  if(!URIUtil.isFileURI(url)) {
116
+    throw `could not fetch file from an invalid URI : ${url}`
117
+  }
118
+
119
+  url = URIUtil.unwrapFileURI(url)
120
+
121
+  let promise = null
122
+  let cursor = 0
123
+  let total = -1
124
+  let cacheData = ''
125
+  let info = null
126
+
127
+  let _progress, _uploadProgress, _stateChange
128
+
129
+  switch(method.toLowerCase()) {
130
+
131
+    case 'post':
132
+    break
133
+
134
+    case 'put':
135
+    break
136
+
137
+    // read data from file system
138
+    default:
139
+      promise = fs.stat(url)
140
+      .then((stat) => {
141
+        total = stat.size
142
+        return fs.readStream(url, headers.encoding || 'utf8', Math.floor(headers.bufferSize) || 4096)
143
+      })
144
+      .then((stream) => new Promise((resolve, reject) => {
145
+        stream.open()
146
+        info = {
147
+          state : "2",
148
+          headers : { 'source' : 'system-fs' },
149
+          status : 200,
150
+          respType : 'text',
151
+          rnfbEncode : headers.encoding || 'utf8'
152
+        }
153
+        _stateChange(info)
154
+        stream.onData((chunk) => {
155
+          _progress && _progress(cursor, total, chunk)
156
+          if(headers.noCache)
157
+            return
158
+          cacheData += chunk
159
+        })
160
+        stream.onError((err) => { reject(err) })
161
+        stream.onEnd(() => {
162
+          resolve(new FetchBlobResponse(null, info, cacheData))
163
+        })
164
+      }))
165
+    break
166
+  }
167
+
168
+  promise.progress = (fn) => {
169
+    _progress = fn
170
+    return promise
171
+  }
172
+  promise.stateChange = (fn) => {
173
+    _stateChange = fn
174
+    return promise
175
+  }
176
+  promise.uploadProgress = (fn) => {
177
+    _uploadProgress = fn
178
+    return promise
179
+  }
180
+
181
+  return promise
182
+}
183
+
103 184
 /**
104 185
  * Create a HTTP request by settings, the `this` context is a `RNFetchBlobConfig` object.
105 186
  * @param  {string} method HTTP method, should be `GET`, `POST`, `PUT`, `DELETE`
@@ -119,9 +200,15 @@ function fetch(...args:any):Promise {
119 200
   let options = this || {}
120 201
   let subscription, subscriptionUpload, stateEvent
121 202
   let respInfo = {}
203
+  let [method, url, headers, body] = [...args]
204
+
205
+  // fetch from file system
206
+  if(URIUtil.isFileURI(url)) {
207
+    return fetchFile(options, method, url, headers, body)
208
+  }
122 209
 
210
+  // from remote HTTP(S)
123 211
   let promise = new Promise((resolve, reject) => {
124
-    let [method, url, headers, body] = [...args]
125 212
     let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob'
126 213
 
127 214
     // on progress event listener

+ 29
- 6
src/json-stream.js View File

@@ -1,15 +1,38 @@
1 1
 import Oboe from './lib/oboe-browser.min.js'
2 2
 import XMLHttpRequest from './polyfill/XMLHttpRequest'
3
+import URIUtil from './utils/uri'
3 4
 
4 5
 const OboeExtended = (arg: string | object) => {
5
-  
6
-  window.XMLHttpRequest = XMLHttpRequest
6
+
7
+
7 8
   window.location = ''
8 9
 
9
-  if(typeof arg === 'string')
10
-    arg = 'JSONStream://' + arg
11
-  else if(typeof arg === 'object')
12
-    arg = Object.assign(arg, { url : 'JSONStream://' + arg.url })
10
+  if(!window.XMLHttpRequest.isRNFBPolyfill ) {
11
+    window.XMLHttpRequest = XMLHttpRequest
12
+    console.warn('Use JSONStream will automatically replace window.XMLHttpRequest with RNFetchBlob.polyfill.XMLHttpRequest. You are seeing this warning because you did not replace it maually.')
13
+  }
14
+
15
+  if(typeof arg === 'string') {
16
+    if(URIUtil.isFileURI(arg)) {
17
+      arg = {
18
+        url : 'JSONStream://' + arg,
19
+        headers : { noCache : true }
20
+      }
21
+    }
22
+    else
23
+      arg = 'JSONStream://' + arg
24
+
25
+  }
26
+  else if(typeof arg === 'object') {
27
+    let headers = arg.headers || {}
28
+    if(URIUtil.isFileURI(arg.url)) {
29
+      headers.noCache = true
30
+    }
31
+    arg = Object.assign(arg, {
32
+      url : 'JSONStream://' + arg.url,
33
+      headers
34
+    })
35
+  }
13 36
   return Oboe(arg)
14 37
 }
15 38