react-native-fetch-blob
Version:
A module provides upload, download, and files access API. Supports file stream read/write for process large files.
214 lines (188 loc) • 6.34 kB
JavaScript
import RNFetchBlob from '../index.js'
import Log from '../utils/log.js'
import fs from '../fs'
import unicode from '../utils/unicode'
import Blob from './Blob'
const log = new Log('FetchPolyfill')
log.disable()
// log.level(3)
export default class Fetch {
constructor(config:RNFetchBlobConfig) {
Object.assign(this, new RNFetchBlobFetchPolyfill(config))
}
}
class RNFetchBlobFetchPolyfill {
constructor(config:RNFetchBlobConfig) {
this.build = () => (url, options = {}) => {
let body = options.body
let promise = Promise.resolve()
let blobCache = null
options.headers = options.headers || {}
let ctype = options['Content-Type'] || options['content-type']
let ctypeH = options.headers['Content-Type'] || options.headers['content-type']
options.headers['Content-Type'] = ctype || ctypeH
options.headers['content-type'] = ctype || ctypeH
options.method = options.method || 'GET'
if(body) {
// When the request body is an instance of FormData, create a Blob cache
// to upload the body.
if(body instanceof FormData) {
log.verbose('convert FormData to blob body')
promise = Blob.build(body).then((b) => {
blobCache = b
options.headers['Content-Type'] = 'multipart/form-data;boundary=' + b.multipartBoundary
return Promise.resolve(RNFetchBlob.wrap(b._ref))
})
}
// When request body is a Blob, use file URI of the Blob as request body.
else if (body.isRNFetchBlobPolyfill)
promise = Promise.resolve(RNFetchBlob.wrap(body.blobPath))
else if (typeof body !== 'object' && options.headers['Content-Type'] !== 'application/json')
promise = Promise.resolve(JSON.stringify(body))
else if (typeof body !== 'string')
promise = Promise.resolve(body.toString())
// send it as-is, leave the native module decide how to send the body.
else
promise = Promise.resolve(body)
}
// task is a progress reportable and cancellable Promise, however,
// task.then is not, so we have to extend task.then with progress and
// cancel function
let progressHandler, uploadHandler, cancelHandler
let statefulPromise = promise
.then((body) => {
let task = RNFetchBlob.config(config)
.fetch(options.method, url, options.headers, body)
if(progressHandler)
task.progress(progressHandler)
if(uploadHandler)
task.uploadProgress(uploadHandler)
if(cancelHandler)
task.cancel()
return task.then((resp) => {
log.verbose('response', resp)
// release blob cache created when sending request
if(blobCache !== null && blobCache instanceof Blob)
blobCache.close()
return Promise.resolve(new RNFetchBlobFetchRepsonse(resp))
})
})
// extend task.then progress with report and cancelling functions
statefulPromise.progress = (fn) => {
progressHandler = fn
}
statefulPromise.uploadProgress = (fn) => {
uploadHandler = fn
}
statefulPromise.cancel = () => {
cancelHandler = true
if(task.cancel)
task.cancel()
}
return statefulPromise
}
}
}
class RNFetchBlobFetchRepsonse {
constructor(resp:FetchBlobResponse) {
let info = resp.info()
this.headers = info.headers
this.ok = info.status >= 200 && info.status <= 299,
this.status = info.status
this.type = 'basic'
this.bodyUsed = false
this.resp = resp
this.rnfbRespInfo = info
this.rnfbResp = resp
}
rawResp() {
return Promise.resolve(this.rnfbResp)
}
arrayBuffer(){
log.verbose('to arrayBuffer', this.rnfbRespInfo)
this.bodyUsed = true
return readArrayBuffer(this.rnfbResp, this.rnfbRespInfo)
}
text() {
log.verbose('to text', this.rnfbResp, this.rnfbRespInfo)
this.bodyUsed = true
return readText(this.rnfbResp, this.rnfbRespInfo)
}
json() {
log.verbose('to json', this.rnfbResp, this.rnfbRespInfo)
this.bodyUsed = true
return readJSON(this.rnfbResp, this.rnfbRespInfo)
}
blob() {
log.verbose('to blob', this.rnfbResp, this.rnfbRespInfo)
this.bodyUsed = true
return readBlob(this.rnfbResp, this.rnfbRespInfo)
}
}
/**
* Get response data as array.
* @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
* @param {RNFetchBlobResponseInfo} info Response informations.
* @return {Promise<Array>}
*/
function readArrayBuffer(resp, info):Promise<Array> {
switch (info.rnfbEncode) {
case 'path':
return resp.readFile('ascii')
break
default:
let buffer = []
let str = resp.text()
for (let i in str) {
buffer[i] = str.charCodeAt(i);
}
return Promise.resolve(buffer)
break
}
}
/**
* Get response data as string.
* @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
* @param {RNFetchBlobResponseInfo} info Response informations.
* @return {Promise<string>}
*/
function readText(resp, info):Promise<string> {
switch (info.rnfbEncode) {
case 'base64':
return Promise.resolve(resp.text())
break
case 'path':
return resp.text()
break
default:
return Promise.resolve(resp.text())
break
}
}
/**
* Get response data as RNFetchBlob Blob polyfill object.
* @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
* @param {RNFetchBlobResponseInfo} info Response informations.
* @return {Promise<Blob>}
*/
function readBlob(resp, info):Promise<Blob> {
log.verbose('readBlob', resp, info)
return resp.blob()
}
/**
* Get response data as JSON object.
* @param {FetchBlobResponse} resp Response data object from RNFB fetch call.
* @param {RNFetchBlobResponseInfo} info Response informations.
* @return {Promise<object>}
*/
function readJSON(resp, info):Promise<object> {
log.verbose('readJSON', resp, info)
switch (info.rnfbEncode) {
case 'base64':
return Promise.resolve(resp.json())
case 'path':
return resp.json()
default:
return Promise.resolve(resp.json())
}
}