Skip to content

Commit

Permalink
[IMPROVEMENT] Use Rest API for file upload (#1005)
Browse files Browse the repository at this point in the history
* removed rn-fetch-blob and use native XMLHttpRequest instead

* removed unnessary changes

* fix android bug

* fix android bug

* added tmid support

* fix bug

* fixed isssue with cacel model

* fix problems with audio

* done requested changes

* fix bug with android
  • Loading branch information
pranavpandey1998official authored and diegolmello committed Jun 28, 2019
1 parent 3b43cb3 commit 4814582
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 156 deletions.
1 change: 0 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ dependencies {
implementation project(":reactnativekeyboardinput")
implementation project(':react-native-video')
implementation project(':react-native-vector-icons')
implementation project(':rn-fetch-blob')
implementation project(':react-native-fast-image')
implementation project(':realm')
implementation project(':reactnativenotifications')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.RNFetchBlob.RNFetchBlobPackage;
import com.brentvatne.react.ReactVideoPackage;
import com.dylanvann.fastimage.FastImageViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
Expand Down Expand Up @@ -74,7 +73,6 @@ protected List<ReactPackage> getPackages() {
new RNDeviceInfo(),
new PickerPackage(),
new VectorIconsPackage(),
new RNFetchBlobPackage(),
new RealmReactPackage(),
new ReactVideoPackage(),
new ReactNativeAudioPackage(),
Expand Down
2 changes: 0 additions & 2 deletions android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':rn-fetch-blob'
project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
include ':react-native-image-crop-picker'
project(':react-native-image-crop-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-crop-picker/android')
include ':react-native-i18n'
Expand Down
11 changes: 7 additions & 4 deletions app/containers/MessageBox/Recording.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ export default class extends React.PureComponent {

this.recordingCanceled = false;
this.recording = true;
this.name = `${ Date.now() }.aac`;
this.state = {
currentTime: '00:00'
};
}

componentDidMount() {
const audioPath = `${ AudioUtils.CachesDirectoryPath }/${ Date.now() }.aac`;
const audioPath = `${ AudioUtils.CachesDirectoryPath }/${ this.name }`;

AudioRecorder.prepareRecordingAtPath(audioPath, {
SampleRate: 22050,
Expand Down Expand Up @@ -84,12 +85,14 @@ export default class extends React.PureComponent {
if (!didSucceed) {
return onFinish && onFinish(didSucceed);
}

const path = filePath.startsWith('file://') ? filePath.split('file://')[1] : filePath;
if (isAndroid) {
filePath = filePath.startsWith('file://') ? filePath : `file://${ filePath }`;
}
const fileInfo = {
name: this.name,
type: 'audio/aac',
store: 'Uploads',
path
path: filePath
};
return onFinish && onFinish(fileInfo);
}
Expand Down
186 changes: 102 additions & 84 deletions app/lib/methods/sendFileMessage.js
Original file line number Diff line number Diff line change
@@ -1,111 +1,129 @@
import RNFetchBlob from 'rn-fetch-blob';

import reduxStore from '../createStore';
import database from '../realm';
import log from '../../utils/log';

const promises = {};
const uploadQueue = {};

function _ufsCreate(fileInfo) {
return this.sdk.methodCall('ufsCreate', fileInfo);
export function isUploadActive(path) {
return !!uploadQueue[path];
}

function _ufsComplete(fileId, store, token) {
return this.sdk.methodCall('ufsComplete', fileId, store, token);
export function cancelUpload(path) {
if (uploadQueue[path]) {
uploadQueue[path].abort();
database.write(() => {
const upload = database.objects('uploads').filtered('path = $0', path);
try {
database.delete(upload);
} catch (e) {
log('err_send_file_message_delete_upload', e);
}
});
delete uploadQueue[path];
}
}

function _sendFileMessage(rid, data, msg = {}) {
// RC 0.22.0
return this.sdk.methodCall('sendFileMessage', rid, null, data, msg);
}
export function sendFileMessage(rid, fileInfo, tmid) {
return new Promise((resolve, reject) => {
try {
const { FileUpload_MaxFileSize, Site_Url } = reduxStore.getState().settings;
const { id, token } = reduxStore.getState().login.user;

export function isUploadActive(path) {
return !!promises[path];
}
// -1 maxFileSize means there is no limit
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
return reject({ error: 'error-file-too-large' }); // eslint-disable-line
}

export async function cancelUpload(path) {
if (promises[path]) {
await promises[path].cancel();
}
}
const uploadUrl = `${ Site_Url }/api/v1/rooms.upload/${ rid }`;

export async function sendFileMessage(rid, fileInfo, tmid) {
try {
const data = await RNFetchBlob.wrap(fileInfo.path);
if (!fileInfo.size) {
const fileStat = await RNFetchBlob.fs.stat(fileInfo.path);
fileInfo.size = fileStat.size;
fileInfo.name = fileStat.filename;
}
const xhr = new XMLHttpRequest();
const formData = new FormData();

const { FileUpload_MaxFileSize } = reduxStore.getState().settings;
fileInfo.rid = rid;

// -1 maxFileSize means there is no limit
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
return Promise.reject({ error: 'error-file-too-large' }); // eslint-disable-line
}
database.write(() => {
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_1', e);
}
});

fileInfo.rid = rid;
uploadQueue[fileInfo.path] = xhr;
xhr.open('POST', uploadUrl);

database.write(() => {
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_1', e);
formData.append('file', {
uri: fileInfo.path,
type: fileInfo.type,
name: fileInfo.name || 'fileMessage'
});

if (fileInfo.description) {
formData.append('description', fileInfo.description);
}

if (tmid) {
formData.append('tmid', tmid);
}
});

const result = await _ufsCreate.call(this, fileInfo);
xhr.setRequestHeader('X-Auth-Token', token);
xhr.setRequestHeader('X-User-Id', id);

xhr.upload.onprogress = ({ total, loaded }) => {
database.write(() => {
fileInfo.progress = Math.floor((loaded / total) * 100);
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_2', e);
}
});
};

promises[fileInfo.path] = RNFetchBlob.fetch('POST', result.url, {
'Content-Type': 'octet-stream'
}, data);
// Workaround for https://github.com/joltup/rn-fetch-blob/issues/96
setTimeout(() => {
if (promises[fileInfo.path] && promises[fileInfo.path].uploadProgress) {
promises[fileInfo.path].uploadProgress((loaded, total) => {
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 400) { // If response is all good...
database.write(() => {
fileInfo.progress = Math.floor((loaded / total) * 100);
const upload = database.objects('uploads').filtered('path = $0', fileInfo.path);
try {
database.create('uploads', fileInfo, true);
database.delete(upload);
const response = JSON.parse(xhr.response);
resolve(response);
} catch (e) {
return log('err_send_file_message_create_upload_2', e);
reject(e);
log('err_send_file_message_delete_upload', e);
}
});
} else {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
const response = JSON.parse(xhr.response);
reject(response);
} catch (err) {
reject(err);
log('err_send_file_message_create_upload_3', err);
}
});
}
};

xhr.onerror = (e) => {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
reject(e);
} catch (err) {
reject(err);
log('err_send_file_message_create_upload_3', err);
}
});
}
});
await promises[fileInfo.path];

const completeResult = await _ufsComplete.call(this, result.fileId, fileInfo.store, result.token);

await _sendFileMessage.call(this, completeResult.rid, {
_id: completeResult._id,
type: completeResult.type,
size: completeResult.size,
name: completeResult.name,
description: completeResult.description,
url: completeResult.path
}, {
tmid
});
};

database.write(() => {
const upload = database.objects('uploads').filtered('path = $0', fileInfo.path);
try {
database.delete(upload);
} catch (e) {
log('err_send_file_message_delete_upload', e);
}
});
} catch (e) {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
} catch (err) {
log('err_send_file_message_create_upload_3', err);
}
});
}
xhr.send(formData);
} catch (err) {
log('err_send_file_message_create_upload_4', err);
}
});
}
Loading

0 comments on commit 4814582

Please sign in to comment.