I am trying to upload multiple files on server in flutter but they are taking to much time to upload.I am using Dio() for uploading..is any better way to upload multiple files on server in flutter.?
I am sending upload function.in which 10 files during upload takes more than 5 minutes
here is my code!
_upLoadFiles() async {
List <FileWithComment> uploadControls = preUpload();
var token = await _getToken();
print("Token: $token");
if (files) {
try {
final result = await InternetAddress.lookup("google.com");
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
FormData data = FormData.fromMap({
"jwt": token,
"comment": [],
"directory": widget.dName,
"directory_id": widget.folderId,
"case_id": widget.case_id,
"media_files": await _mediaFileList(),
});
await Dio()
.post(
"${MyFlutterApp.baseUrl}media_upload.php",
data: data,
onSendProgress: _setUploadProgress,
options: Options(
contentType: "multipart/form-data",
),
)
.then((res) => (res.data))
.then((d) => json.decode(d))
.then((res) => postUpload(res));
}
} on SocketException catch (_) {
_saveLocal(uploadControls);
} catch (e) {
if (e.toString().contains("Cannot retrieve length of file")) {
_showSnackBar("Cannot Upload File Try Again Later", Color(0xffDC0000), Colors.white);
}
}
} else {
print("${widget.dName}");
try {
final result = await InternetAddress.lookup("google.com");
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
FormData data = FormData.fromMap({
"jwt": token,
"directory": widget.dName,
"directory_id": widget.folderId,
"case_id": widget.case_id,
"comment": list.map((filewithcomment) => filewithcomment.comment).toList(),
"media_files": await _mediaFileList(),
"f_location": list.map((filewithcomment) => filewithcomment.location).toList(),
});
await Dio()
.post("${MyFlutterApp.baseUrl}media_upload.php",
data: data,
onSendProgress: _setUploadProgress,
options: Options(
contentType: "multipart/form-data",
))
.then((res) {
return res.data;
})
.then((d) => json.decode(d))
.then((res) => postUpload(res));
}
} on SocketException catch (_) {
_saveLocal(uploadControls);
} catch (e) {
print(e);
if (e.toString().contains("Cannot retrieve length of file")) {
_showSnackBar("Cannot Upload File Try Again Later", Color(0xffDC0000), Colors.white);
}
}
}
}
This is mediafileList()..May be there is issue in these lines of code
Future<List<MultipartFile>> _mediaFileList() async {
Completer complete = Completer<List<MultipartFile>>();
List<MultipartFile> filesList = [];
for (int index = 0; index < list.length; index++) {
if (list[index].file is File) {
var file = list[index].file;
filesList.add(await MultipartFile.fromFile(file.path, filename: file.path.split('/').last));
}
if (list[index].file is String) {
var file = File(list[index].file);
filesList.add(await MultipartFile.fromFile(
file.path, filename: file.path.split('/').last));
}
if (index == list.length - 1) complete.complete(filesList);
}
return complete.future;
}
I want to send image in react-Native-Gifted-chat like sending text. I am novice in react-native.
I have already used react-native-image-picker for pick a image from physical device, now I am unable to render image in message[].
You can call the onSend method of GiftedChat with an object as a parameter. Just pass an object with image as key. For example
onSend({ image: "https://picsum.photos/id/237/200/300" });
you can use this
import DocumentPicker from 'react-native-document-picker';
install this library first
then simply choose the file from the document picker
use this function
onAttatchFile = async () => {
try {
const res = await DocumentPicker.pick({
type: [DocumentPicker.types.allFiles],
});
// console.log(res);
let type = res.name.slice(res.name.lastIndexOf('.') + 1);
if (
res.type == 'doc' ||
res.type == 'application/pdf' ||
res.type == 'image/jpeg' ||
res.type == 'image/png' ||
res.type == 'image/jpg' ||
res.type == 'application/msword' ||
type == 'docx'
) {
this.setState({slectedFile: res}, () => this.onSendWithImage());
} else {
alert(`${type} files not allowed`);
}
} catch (err) {
//Handling any exception (If any)
if (DocumentPicker.isCancel(err)) {
//If user canceled the document selection
// alert('Canceled from single doc picker');
} else {
//For Unknown Error
// alert('Unknown Error: ' + JSON.stringify(err));
throw err;
}
}
};
use this function when you want to send the image
onSendWithImage() {
let imageData = {
name: this.state.slectedFile.name,
type: this.state.slectedFile.type,
size: this.state.slectedFile.size,
uri: this.state.slectedFile.uri,
};
var formData = new FormData();
formData.append('type', 2);
formData.append('senderId', this.state.senderData.id),
formData.append('recieverId', this.state.reciverData._id),
formData.append('message', imageData);
post('sendMessage', formData).then(res =>
res.success ? this.msjSendSuccess(res) : this.msjSendFailure(res),
);
}
talk with your backend and say to him /her to send the image in the image key
complete enjoy React native
Good afternoon folks,
Here's an issue that's currently driving me up the wall and I cannot seem to see the wood for the trees.
I have a React Native app with a built in file uploader, part of this uploader is the use of the abortcontroller which allows the code to send a signal to the fetch request to stop the call in-flight
This works perfectly as one would expect the problem is if the user then selects another file or tries to upload the file the cancelled previously my promise returns instantly with the abort error still in place preventing any further uploads and for love nor money can I seem to find a way to stop this from occurring.
Here is the reduced version of my screen (urls removed, some data points removed, etc) to protect the privacy of my system
import React from 'react';
import {StyleSheet,View,ScrollView,Alert,} from 'react-native';
import AppSettings from '../../constants/AppSettings'
import Colours from '../../constants/Colours';
import CustomHeader from '../../components/CustomHeader';
import CustomButton from '../../components/CustomButton';
import TextContent from '../../components/TextContent';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import Constants from 'expo-constants';
import * as DocumentPicker from 'expo-document-picker';
import * as Permissions from 'expo-permissions';
import CustomInput from '../../components/CustomInput';
import Progressbar from '../../components/ProgressBar';
import * as Network from 'expo-network';
export default class UploadScreen extends React.Component {
state = {
file: null,
filetype: null,
fileExtention:null,
uploading: false,
pickResult: null,
mainDataLoaded: false,
docDesc:null,
enteredPassword:'',
currentUploadPercent:0,
uploadTime: 0,
startPick: false,
};
render() {
return (
<View style={styles.screenContainer}>
<LinearGradient start={[0, 1]} end={[0,0.9]} colors={['rgba(163, 163, 163,1)', 'rgba(163, 163, 163,0)']} style={{flex:1}} >
<ScrollView style={styles.scrollContainer} contentContainerStyle={styles.defaultContainer}>
<View style={{flex:1, alignItems: 'center', justifyContent: 'center', width:'100%' }}>
<TextContent>Upload file containing: {this.state.docDesc}</TextContent>
{this._maybeRenderFile()}
{this._maybeRenderControls()}
{this._maybeRenderUploadingIndicator()}
</View>
</ScrollView>
</LinearGradient>
</View>
);
}
_maybeRenderUploadingIndicator = () => {
if (this.state.uploading) {
return (
<View style={{width:'80%',alignItems:'center'}}>
<Progressbar progress={this.state.currentUploadPercent}/>
<CustomButton style={{width:'100%'}} onPress={()=>{AbortUpload(this)}} title='Cancel Upload'></CustomButton>
</View>
);
}
};
_maybeRenderControls = () => {
if (!this.state.uploading) {
return (
<View style={{width:'100%',alignItems:'center'}}>
<CustomButton style={{width:'80%'}} onPress={this._pickImage} title='Select file to upload'><MaterialCommunityIcons style={{color:Colours.PrimaryButtonText}} name="folder-open" size={30}/></CustomButton>
</View>
);
}
};
_maybeRenderFile = () => {
if (this.state.file) {
switch (this.state.filetype) {
case 'application/pdf':
const passwordHandler = enteredText => {
this.setState({enteredPassword: enteredText});
};
return (
<View style={{alignItems:'center'}}>
<MaterialCommunityIcons style={{color:Colours.PrimaryText}} name="file-pdf" size={100}/>
<TextContent style={{textAlign:'center'}}>File to upload: {this.state.file}</TextContent>
<TextContent>If this file requires a password to access please type it below or leave blank if not required.</TextContent>
{!this.state.uploading && (
<View>
<CustomInput placeholder='PDF Password (if applicable)' autoCapitalize='characters' autoCompleteType='off' autoCorrect={false} textContentType='none' onChangeText={passwordHandler} value={this.state.enteredPassword}/>
<CustomButton style={{width:'100%'}} onPress={()=>{this._handleImagePicked(this.state.pickResult)}} title='Upload this file'><MaterialCommunityIcons style={{color:Colours.PrimaryButtonText}} name="file-upload-outline" size={30}/></CustomButton>
<TextContent style={{textAlign:'center'}}>Or</TextContent>
</View>
)}
</View>
);
break;
case 'image/jpg':
case 'image/png':
case 'image/gif':
return (
<View style={{alignItems:'center'}}>
<MaterialCommunityIcons style={{color:Colours.PrimaryText}} name="file-image" size={100}/>
<TextContent style={{textAlign:'center'}}>File to upload: {this.state.file}</TextContent>
{!this.state.uploading && (
<View>
<CustomButton style={{minWidth:'80%'}} onPress={()=>{this._handleImagePicked(this.state.pickResult)}} title='Upload this file'><MaterialCommunityIcons style={{color:Colours.PrimaryButtonText}} name="file-upload-outline" size={30}/></CustomButton>
<TextContent style={{textAlign:'center'}}>Or</TextContent>
</View>
)}
</View>
);
break;
default:
break;
}
}
};
_askPermission = async (type, failureMessage) => {
const { status, permissions } = await Permissions.askAsync(type);
if (status === 'denied') {
alert(failureMessage);
}
};
_pickImage = async () => {
await this._askPermission(
Permissions.CAMERA_ROLL,
'We need the file permission to access files from your phone...'
);
if(!this.state.startPick){
this.setState({startPick: true})
let pickerResult = await DocumentPicker.getDocumentAsync({});
if(pickerResult.type == 'success'){
this.setState({startPick: false})
//Get file extention
var splitAt = pickerResult.name.lastIndexOf(".")
var fileExt = pickerResult.name.slice(splitAt,pickerResult.name.length).toLowerCase()
switch (fileExt) {
case '.pdf':
this.setState({file: pickerResult.name, filetype: 'application/pdf', pickResult: pickerResult, fileExtention: fileExt})
break;
case '.jpg':
this.setState({file: pickerResult.name, filetype: 'image/jpg', pickResult: pickerResult, fileExtention: fileExt})
break;
case '.jpeg':
this.setState({file: pickerResult.name, filetype: 'image/jpg', pickResult: pickerResult, fileExtention: fileExt})
break;
case '.png':
this.setState({file: pickerResult.name, filetype: 'image/png', pickResult: pickerResult, fileExtention: fileExt})
break;
case '.gif':
this.setState({file: pickerResult.name, filetype: 'image/gif', pickResult: pickerResult, fileExtention: fileExt})
break;
default:
this.setState({file: null, filetype: null, pickResult: null})
Alert.alert('Unsupported filetype','For security reasons you may only select images or PDF files to upload.')
break;
}
}else{
//No file selected
this.setState({file: null, filetype: null, pickResult: null})
this.setState({startPick: false})
}
if(__DEV__){console.log('Result:', pickerResult)}
}else{
if(__DEV__){console.log('Pick already started')}
}
};
_StatusCheck = async() =>{
return fetch('Url for server side upload status response')
.then((response) => response.json())
.then((responseJson) => {
return responseJson
})
.catch((error) =>{
console.error(error);
});
}
_handleImagePicked = async pickerResult => {
try {
if (!pickerResult.cancelled) {
var thisTime = Date.now()
this.setState({uploadTime: thisTime})
var myPromise = new Promise(function(){})
myPromise = MakeQuerablePromise(new uploadFileAsync(
pickerResult.uri,
this.state.docType + '-' + Date.now() + this.state.fileExtention,
this.state.filetype,
this.state.docType,
this.state.docDesc,
this.state.enteredPassword,
this.state.quoteID,
this.state.uploading,
thisTime,
controller.signal
));
this.setState({ uploading: true });
if(__DEV__){
console.log("Initial fulfilled:", myPromise.isFulfilled());//false
console.log("Initial rejected:", myPromise.isRejected());//false
console.log("Initial pending:", myPromise.isPending());//true
}
for (let index = 0; index < 1;) {
var currentStatus = await this._StatusCheck()
var curTime = new Date()
if(__DEV__){
console.log('Time:',curTime.getHours(),':',curTime.getMinutes(),':',curTime.getSeconds())
console.log('Status:',currentStatus)
console.log("Promise status- fulfilled:", myPromise.isFulfilled(), "rejected:", myPromise.isRejected(),"pending:", myPromise.isPending());//false
console.log('Promise Content:',myPromise)
}
if(!myPromise.isRejected()){
if(currentStatus.percent != undefined){
if(currentStatus.percent < 100){
this.setState({currentUploadPercent:currentStatus.percent})
if(__DEV__){
console.log('Upload progess ' + currentStatus.percent)
console.log("Promise status: fulfilled:", myPromise.isFulfilled(), "rejected:", myPromise.isRejected(),"pending:", myPromise.isPending());//false
}
}else{
this.setState({currentUploadPercent:currentStatus.percent})
if(__DEV__){
console.log('Upload progess 100%')
console.log("Promise status: fulfilled:", myPromise.isFulfilled(), "rejected:", myPromise.isRejected(),"pending:", myPromise.isPending());//false
}
}
}
}
if(myPromise.isFulfilled() == true){
if(__DEV__){
console.log("Entered Fulfilled State - Promise status: fulfilled:", myPromise.isFulfilled(), "rejected:", myPromise.isRejected(),"pending:", myPromise.isPending());//false
}
index++
}
if(myPromise.isRejected() == true){
if(__DEV__){
console.log("Entered Rejected State - Promise status: fulfilled:", myPromise.isFulfilled(), "rejected:", myPromise.isRejected(),"pending:", myPromise.isPending());//false
}
index++
}
}
if(myPromise.isRejected() == false){
myPromise.then(response => response.json()).then((responseJson)=>{
if(__DEV__){
console.log('Promise Json:',responseJson)
console.log("Final fulfilled:", myPromise.isFulfilled());//true
console.log("Final rejected:", myPromise.isRejected());//false
console.log("Final pending:", myPromise.isPending());//false
}
if(responseJson.datapage.result.gitUploadStatus.successful == true){
//Successful upload
this.props.navigation.navigate('CaptureThanks')
}else{
//Upload had a issue
Alert.alert('Upload error','There was an issue with the upload, this maybe a temporary issue with your connection or with the server please ensure you have a good steady signal and try again, if the problem persists please contact us. Error Code: '+responseJson.datapage.gitUploadStatus.errorMessage)
}
})
}else{
//Rejected promise handle failure
if(myPromise.rejectReason() == 'AbortError'){
myPromise = MakeQuerablePromise(new Promise(function(resolve, reject){
resolve('AbortError')
}))
}else{
Alert.alert('Upload error','There was an issue with the upload, this maybe a temporary issue with your connection or with the server please ensure you have a good steady signal and try again, if the problem persists please contact us. Error Code: '+responseJson.datapage.gitUploadStatus.errorMessage)
}
}
}
} catch (e) {
if(__DEV__){
console.log('Error Name:',e.name)
console.log('Catch Error:',{ e });
}
return;
} finally {
if(__DEV__){
console.log('Reached Final')
}
myPromise = MakeQuerablePromise(new Promise(function(resolve, reject){
resolve('Finished')
}))
console.log(myPromise)
this.setState({ uploading: false, currentUploadPercent:0 });
}
};
}
function MakeQuerablePromise(promise) {
// Don't modify any promise that has been already modified.
if (promise.isResolved){
return promise
};
// Set initial state
var isPending = true;
var isRejected = false;
var isFulfilled = false;
var rejectReason = '';
// Observe the promise, saving the fulfillment in a closure scope.
var result = promise.then(
function(v) {
isFulfilled = true;
isPending = false;
rejectReason = '';
return v;
},
function(e) {
isRejected = true;
isPending = false;
rejectReason = e.name;
return e;
}
);
result.isFulfilled = function() { return isFulfilled; };
result.isPending = function() { return isPending; };
result.isRejected = function() { return isRejected; };
result.rejectReason = function() {return rejectReason; };
return result;
}
const controller = new AbortController;
async function uploadFileAsync(uri,name,type,docType,docDesc,password,quoteid,isUploading,uploadTime,abortSignal) {
if(!isUploading){
if(__DEV__){console.log('Making upload request for ',docType,' Document description:', docDesc)}
let apiUrl = 'Url to push the upload to';
let formData = new FormData();
//(method) FormData.append(name: string, value: string | Blob, fileName?: string): void
formData.append('filename', {
uri,
name: name,
type: type,
documentType:docType,
description:docDesc,
password:password,
quoteid:quoteid,
});
let options = {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
signal: abortSignal,
};
if(__DEV__){console.log('Options:', options)}
return fetch(apiUrl, options);
}else{
return null
}
}
async function AbortUpload(stateObject){
controller.abort()
stateObject.setState({isUploading: false})
}
UploadScreen.navigationOptions = {
header: () => <CustomHeader goback={true} title='Document Upload'/>,
title: AppSettings.AppName + ' ',
headerTitleStyle:{
fontFamily: AppSettings.HeaderFont,
},
headerStyle: {
backgroundColor: Colours.HeaderBackground
},
headerTintColor: Colours.HeaderText
};
const styles = StyleSheet.create({
screenContainer:{
flex:1,
backgroundColor: Colours.PrimaryBackgroud,
},
scrollContainer:{
flex: 1,
height:'100%'
},
defaultContainer: {
alignItems: 'center',
},
});
Forgive the nature of my code as I'm still pretty new to react native and only been doing it for a few months now so still getting my head around a lot of the features and systems and only just updated to the latest version of expo (36) yesterday so I could enable the fetch abort.
But it anyone has any clues as to why it seems that after the signal is called once to abort every future request then seems to be getting that same signal regardless that the user has not clicked it again and I am not storing it in state so I can't seem to understand why its persisting to the degree that I even went to the extreme of rebuilding the promises at start and end to ensure they were cleaned every time the upload is fired.
You shared way too much code, but I'll have a try at this.
First of all, I'm surprised it even worked in the first place. You're creating your abort controller like so:
const controller = new AbortController;
While it should be:
const controller = new AbortController();
Now, when it comes to the logic, I believe it's displaying an error because you're using that same controller, which was already canceled.
The trick would be to turn it into a state and update it with a new AbortController as soon as it gets aborted (probably in your AbortUpload method, right after calling controller.abort()).
I need to modify the Kurento group call example from Link
to send only audio if one participant has no camera. Right now only audio is received when a camera is used. When only a microphone is available I receive a DeviceMediaError.
I managed to filter whether a camera device is connected or not and then send only audio, but this doesn't work. Maybe the participant should've an audio tag instead of a video tag?
EDIT: It's only working on Firefox and not in Chrome. Any ideas?
in file - https://github.com/Kurento/kurento-tutorial-java/blob/master/kurento-group-call/src/main/java/org/kurento/tutorial/groupcall/UserSession.java.
change following line -
sender.getOutgoingWebRtcPeer().connect(incoming, MediaType.AUDIO);
and set offer media constraints to video:false in browser js file.
updated code -
let constraints = {
audio: true,
video: false
};
let localParticipant = new Participant(sessionId);
participants[sessionId] = localParticipant;
localVideo = document.getElementById('local_video');
let video = localVideo;
let options = {
localVideo: video,
mediaConstraints: constraints,
onicecandidate: localParticipant.onIceCandidate.bind(localParticipant),
configuration : { iceServers : [
{"url":"stun:74.125.200.127:19302"},
] }
};
localParticipant.rtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function(error) {
if (error) {
return console.error(error);
}
localVideoCurrentId = sessionId;
localVideo = document.getElementById('local_video');
localVideo.src = localParticipant.rtcPeer.localVideo.src;
localVideo.muted = true;
this.generateOffer(localParticipant.offerToReceiveVideo.bind(localParticipant));
});
server.js code
function join(socket, room, callback) {
let userSession = userRegister.getById(socket.id);
userSession.setRoomName(room.name);
room.pipeline.create('WebRtcEndpoint', {mediaProfile : 'WEBM_AUDIO_ONLY'}, (error, outgoingMedia) => {
if (error) {
console.error('no participant in room');
if (Object.keys(room.participants).length === 0) {
room.pipeline.release();
}
return callback(error);
}
// else
outgoingMedia.setMaxAudioRecvBandwidth(100);
add media profile parameter on server side while joining room.
function getEndpointForUser(userSession, sender, callback) {
if (userSession.id === sender.id) {
return callback(null, userSession.outgoingMedia);
}
let incoming = userSession.incomingMedia[sender.id];
if (incoming == null) {
console.log(`user : ${userSession.id} create endpoint to receive video from : ${sender.id}`);
getRoom(userSession.roomName, (error, room) => {
if (error) {
return callback(error);
}
room.pipeline.create('WebRtcEndpoint', {mediaProfile : 'WEBM_AUDIO_ONLY'}, (error, incomingMedia) => {
if (error) {
if (Object.keys(room.participants).length === 0) {
room.pipeline.release();
}
return callback(error);
}
console.log(`user: ${userSession.id} successfully create pipeline`);
incomingMedia.setMaxAudioRecvBandwidth(0);
incomingMedia.getMaxAudioRecvBandwidth(0);
add media profile parameter when accepting call.
hope this helps.