From b7ec17c8d174877502aaffbf90613fc110ffe854 Mon Sep 17 00:00:00 2001 From: rickevry Date: Sun, 23 Apr 2017 15:59:38 +0200 Subject: [PATCH] fetch instead of XMLHttpRequest putWithFetch shows that there is a bug in how XMLHttpRequest loads a video stream. Instead of uploading the video, it uploads the first frame (as an image). --- package.json | 3 +- src/FetchRequest.js | 142 ++++++++++++++++++++++++++++++++++++++++++++ src/RNS3.js | 21 ++++++- 3 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 src/FetchRequest.js diff --git a/package.json b/package.json index aeb73ed8..2c3ff8de 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ }, "dependencies": { "buffer": "^4.5.1", - "crypto-js": "^3.1.6" + "crypto-js": "^3.1.6", + "react-native-fetch-blob": "^0.10.4" }, "devDependencies": { "babel-cli": "^6.24.0", diff --git a/src/FetchRequest.js b/src/FetchRequest.js new file mode 100644 index 00000000..ca442e43 --- /dev/null +++ b/src/FetchRequest.js @@ -0,0 +1,142 @@ +/** + * Request + */ + +import RNFetchBlob from 'react-native-fetch-blob' + +const isBlank = string => + null == string || !/\S/.test(string) + +const notBlank = string => + !isBlank(string) + +const parseHeaders = (xhr) => { + return (xhr.getAllResponseHeaders() || '') + .split(/\r?\n/) + .filter(notBlank) + .reduce((headers, headerString) => { + let header = headerString.split(":")[0]; + headers[header] = xhr.getResponseHeader(header); + return headers; + }, {}); +} + +const buildResponseObject = (xhr) => { + let headers = {}; + try { + headers = parseHeaders(xhr) + } catch (e) {}; + return { + status: xhr.status, + text: xhr.responseText, + headers: headers + }; +} + +const buildResponseHandler = (xhr, resolve, reject) => { + return () => { + let fn = xhr.status === 0 ? reject : resolve; + fn(buildResponseObject(xhr)); + } +} + +const decorateProgressFn = (fn) => { + return (e) => { + e.percent = e.loaded / e.total; + return fn(e); + } +} + +export class FetchRequest { + static create(...args) { + return new this(...args); + } + + constructor(url, method, attrs = {}, headers = {}) { + //this._xhr = new Request.XMLHttpRequest(); + //this._formData = new Request.FormData(); + + this.url = url; + this.method = method; + this.headers = {}; + this.formData = []; + + //this._xhr.open(method, url); + + // this._promise = new Promise((resolve, reject) => { + // this._xhr.onload = buildResponseHandler(this._xhr, resolve, reject); + // this._xhr.onerror = buildResponseHandler(this._xhr, resolve, reject); + // }); + + Object.keys(attrs).forEach((k) => this.set(k, attrs[k])); + Object.keys(headers).forEach((k) => this.header(k, headers[k])); + } + + header(key, value) { + this.headers[key] = value; + //this._xhr.setRequestHeader(key, value); + return this; + } + + set(key, value) { + let newKeyValue = { + name: key, + data: value + }; + + if (key=="file") { + newKeyValue.data = RNFetchBlob.wrap(value.uri); + newKeyValue.filename = value.name; + } + + this.formData.push(newKeyValue); + // this._formData.append(key, value); + return this; + } + + send() { + +RNFetchBlob + //.config({ + // // DCIMDir is in external storage + // path : dirs.DCIMDir + '/music.mp3' + //}) + .fetch(this.method, this.url, this.headers, this.formData) + .then((r) => { + // console.log("file uploaded", r); + // scan file success + }) + .catch((err) => { + console.log("upload error", error); + // scan file error + }) + + // this._xhr.send(this._formData); + return this; + } + + abort() { + //this._xhr.abort(); + return this; + } + + progress(fn) { + //if (this._xhr.upload) { + // this._xhr.upload.onprogress = decorateProgressFn(fn); + //} + return this; + } + + then(...args) { + //this._promise = this._promise.then(...args); + return this; + } + + catch(...args) { + //this._promise = this._promise.catch(...args); + return this; + } +} + +// Request.FormData = FormData +// Request.XMLHttpRequest = XMLHttpRequest diff --git a/src/RNS3.js b/src/RNS3.js index de17e04f..c2431257 100644 --- a/src/RNS3.js +++ b/src/RNS3.js @@ -3,6 +3,7 @@ */ import { Request } from './Request' +import { FetchRequest } from './FetchRequest' import { S3Policy } from './S3Policy' const AWS_DEFAULT_S3_HOST = 's3.amazonaws.com' @@ -30,6 +31,7 @@ const setBodyAsParsedXML = (response) => }) export class RNS3 { + static put(file, options) { options = { ...options, @@ -47,4 +49,21 @@ export class RNS3 { .send() .then(setBodyAsParsedXML) } -} + + static putWithFetch(file, options) { + options = { + ...options, + key: (options.keyPrefix || '') + file.name, + date: new Date, + contentType: file.type + } + + const url = `https://${options.bucket}.${options.awsUrl || AWS_DEFAULT_S3_HOST}` + const method = "POST" + const policy = S3Policy.generate(options) + + return FetchRequest.create(url, method, policy) + .set("file", file) + .send() + .then(setBodyAsParsedXML) + }}