Vimeo video upload fails 1/10 times using Dio package in Flutter - flutter

I am using the POST method to upload video file from Flutter App using the Dio package. Vimeo's POST method first generates a link for us to upload the video to. The video is uploaded successfully most of the time. Every once in a while, it fails (like 1/10).
To Test if this is an issue on Vimeo's server I tried uploading the video from POSTMAN, 20/20 (all of them) times it uploaded successfully. So I am assuming there is something wrong with the DIO Package?
I have also posted this issue in the DIO's github issues:
https://github.com/flutterchina/dio/issues/1535#issue-1328014439
Upload video code:
if (url != null) {
print('upload link is not null!');
Strings.videoURL = url;
print('upload url is <>:');
print(Strings.videoURL);
try {
Dio uploadVideoDio = new Dio();
uploadVideoDio.options.headers["authorization"] = dotenv.env['VIMEO_ACCESS_TOKEN'];
uploadVideoDio.options.headers["content-type"] = "application/json";
uploadVideoDio.options.headers["accept"] = "application/json";
var formData = FormData.fromMap({
"file_data": await MultipartFile.fromFile(file.path)
});
await uploadVideoDio.post(
Strings.videoURL,
data: formData,
options: Options(
followRedirects: false,
responseType: ResponseType.json,
validateStatus: (status) {
print('status is :');
print(status);
// return status! < 500;
if (status == 302) {
uploadStatus = 'successful';
return true;
} else {
return false;
}
}),
);
print('file upload called');
print('upload status is ');
print(uploadStatus);
return uploadStatus;
} on DioError catch (err) {
print('error uploading actual video');
print(err.toString());
return uploadStatus;
}
} else {
print('upload link is null');
return uploadStatus;
}
Here's an update
I got in touch with the Vimeo's support team and they are investigating the issue. Their response is that
The "POST" method is not very reliable and you should use the TUS
resumable approach.
I am about to test the stability of the TUS method and will update this post afterwards

Related

What is best way to fetch files from server in flutter web?

I am tring to develop a app using Flutter Web to provide a gallery of mediafiles stored in an apache server. Currently I am using Dio to get files as bytes and then call saveAs javascript function to downloand files to client computer. While this approach works for small sized files, it gives out of memory error for big files in browser. My code to get files is as follows. Can you suggest me a better way to get files? Thanks.
response = await dio.get(
medialink,
cancelToken: cancelToken,
onReceiveProgress: (rcv, total) {
if (total != -1) {
setState(() {
progress = ((rcv / total) * 100).toStringAsFixed(0);
});
if (rcv == total) {
setState(() {
isDownloaded = true;
downloading = false;
});
}
}
else {
print("-1");
}
},
//Received data with List<int>
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
validateStatus: (status) { return status! < 500; }
),
);

Error Uploading file to server with Flutter

I have a flutter application that select and upload audio file to server with asp.net rest api.
my flutter code as follows
uploadFile() async {
print(file.path);
var postUri = Uri.parse("http://192.168.1.100:5041/api/fileup/up");
var request = new http.MultipartRequest("POST", postUri);
request.fields['user'] = 'blah';
request.files.add(new http.MultipartFile.fromBytes('file', await File.fromUri(Uri.parse(file.path)).readAsBytes(),contentType: MediaType('audio','mp3')
));
request.send().then((response) {
if (response.statusCode == 200) {
print("Uploaded!");
}else{
print(response.reasonPhrase);
}
});
}
my file.path value for above flutter code is "/data/user/0/com.mydomain.myappname/cache/file_picker/Over_the_Horizon.mp3" which is returned from file picker.
I am able to upload file with postman, but flutter code gives me 500: Internal Server Error
Postman Screenshot
tried with several codes found on stack overflow , all gave me same error
Did you tried with DIO?
You can accomplish this with DIO, like this:
FormData formData = new FormData.fromMap({
"file": await MultipartFile.fromFile(file.path,
filename: file.path.split('/').last)
});
await dio.post('http://192.168.1.100:5041/api/fileup/up', data: formData, onSendProgress: (int begin, int end) {
var initial = begin;
var done = end;
print('$initial $end');
});

Flutter upload large file with progress bar. App and Web both support

I am stuck in issue with upload large file. A flutter application compiled for Web and App (Native) when file upload from app is working fine but web it hanged. how to send large file as stream request.
I am new in flutter and working on current existing app which has a feature to upload large tutorial video files and PDF files. requirement is to show the progress bar during the upload the file, currently app has I used dio but it hanged in web version and not file not upload operation going failed.
File size approximate 400MB to 700MB
Currently using following packages
dependencies:
http: ^0.12.2
dio: ^3.0.10
Could you please help me out for this issue?
I am trying to achieve with below code but some how it not working.
https://github.com/salk52/Flutter-File-Upload-Download
It's thrown an error like "Memory buffer allocation failed ", I am unable to update the version of dio or http due to other package goes disturb. somehow I have to achieve it using httpclient or dio. I could not update the version for package because it messed up other package dependency.
Sample ref. code as below:
File size approximate around 500 MB to 700MB
For ref. following code which using in code.
Dio package example:
#Dio example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#Dio example end
#httpclient example code is there any solution with progress bar in this sample code.
Future<NormalResponse> addUpdateSubjectMaterialHttp(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
var req = http.MultipartRequest(
"POST",
Uri.parse(AppConstants.addUpdateSubjectMaterial),
);
req.headers.addAll({
'Content-type': 'application/json',
'Accept': 'application/json',
});
req.fields['ObjSubMat'] = json.encode(objSubMat);
req.fields['IsDelete'] = isDelete.toString();
req.fields['ClassesId'] = AppConstants.classesId().toString();
if (objfile != null) {
req.files.add(http.MultipartFile(
"objFile", objfile.readStream, objfile.size,
filename: objfile.name));
}
var resp = await req.send();
String result = await resp.stream.bytesToString();
objRes = NormalResponse.fromJson(json.decode(result));
print(objRes.isSuccess);
print(objRes.err);
print("Here done");
} catch (err) {
print(err);
throw err;
}
return objRes;
}
#httpclient
Http package example:
#example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#example end
You must use Future, await and async which continues the task of streams in background thread while the UI of your application works smoothly.

Flutter AZURE BLOB IMAGE UPLOAD - How to upload image captured using mobile camera to azure blob storage

I have been working for few since yesterday to try upload an image to azure blob storage taken using mobile camera form iOS/Android device.
I am able to upload the files but for some reason they being corrupted not able to open the image uploaded.
Please check the image error while opening the uploaded image
I am using flutter package http with different approach all work in uploading image file to azure blob store but it gets corrupted somehow , I tried forcing the ContentType to image/jpeg but no help.
Here is code I am using an http API -
takePicture() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
String fileName = basename(pickedFile.path);
uploadFile(fileName, image);
} else {
print('No image selected.');
}
});
}
First approach -->
http.Response response = await http.put(
uri,
headers: {
"Content-Type": 'image/jpeg',
"X-MS-BLOB-TYPE": "BlockBlob",
},
body: image.path,
);
print(response.statusCode);
Using Approach second -->
final data = image.readAsBytesSync();
var dio = Dio();
dio.options.headers['x-ms-blob-type'] = 'BlockBlob';
dio.options.headers['Content-Type'] = 'image/jpeg';
try {
final response = await dio.put(
'$url/$fileName?$token',
data: data,
onSendProgress: (int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.statusCode);
} catch (e) {
print(e);
}
Approach third -->
var request = new http.MultipartRequest("PUT", postUri);
request.headers['X-MS-BLOB-TYPE'] = 'BlockBlob';
request.headers['Content-Type'] = 'image/jpeg';
request.files.add(
new http.MultipartFile.fromBytes(
'picture',
await image.readAsBytes(),
),
);
request.send().then((response) {
uploadResponse.add(response.statusCode);
}, onError: (err) {
print(err);
});
Help here is much appreciated.
If you want to upload the image to Azure Blob Storage in the flutter application, you can use the Dart Package azblob to implement it. Regarding how to use the package, please refer to here.
For example
import 'package:image_picker/image_picker.dart';
import 'package:flutter/material.dart';
import 'package:azblob/azblob.dart';
import 'package:mime/mime.dart';
...
//use image_picker to get image
Future uploadImageToAzure(BuildContext context) async {
try{
String fileName = basename(_imageFile.path);
// read file as Uint8List
Uint8List content = await _imageFile.readAsBytes();
var storage = AzureStorage.parse('<storage account connection string>');
String container="image";
// get the mine type of the file
String contentType= lookupMimeType(fileName);
await storage.putBlob('/$container/$fileName',bodyBytes: content,contentType: contentType,type: BlobType.BlockBlob);
print("done");
} on AzureStorageException catch(ex){
print(ex.message);
}catch(err){
print(err);
}
Unfortunately, the multipart form is causing break of image. I don't know how it works on azure side, because there is little or no information about multipart uploads, but it's clearly broken because of multipart form. I replicated the problem in .net core application and whenever i am using multipart form data to upload image - it is broken. When i am using simple ByteArrayContent - it works. I couldn't find flutter equivalent to ByteArrayContent, so i am lost now :( The package mentioned by #Jim is useless for me, because i want to give clients sas url, so they have permission to upload image on client side. I do not want to store azure storage account secrets in flutter app.
EDIT. I found the solution to send raw byte data with Dio package. You can do that also with http package.
final dio = new Dio();
final fileBytes = file.readAsBytesSync();
var streamData = Stream.fromIterable(fileBytes.map((e) => [e]));
await dio.put(uploadDestinationUrl,
data: streamData,
options: Options(headers: {
Headers.contentLengthHeader: fileBytes.length,
"x-ms-blob-type": "BlockBlob",
"content-type": "image/jpeg"
}));

Could not upload image with Dio

I'm using Dio to upload images to backend. It often gives me the Reference not set response with a 500 error code. I tried uploading from another source and it seems to be working. What's wrong with this code?
Haven't put the code for performPostRequestWithToken() because other methods are using it too and it seems to be working alright.
Future<UserModel> submitProfileImage(String imagePath) async {
if (isEmpty(imagePath)) throw Exception("NULL image found");
final formdata = FormData.fromMap({
"profilePic": await MultipartFile.fromFile(
imagePath,
filename: "profilePic.png",
),
});
final usertoken = await getCurrentUserToken();
print(usertoken);
final response = await _dioHttpService.performPostRequestWithToken(
"/User/UploadImage",
formdata,
usertoken,
);
if (response.statusCode >= 200 && response.statusCode < 300) {
return UserModel.fromMap(response.data["data"]);
} else {
throw Exception(response.statusMessage);
}
}
The problem in my case was that the map key profilePic was causing the issues. This was definitely a problem from the backend because they were expecting the key to be file.
Changed that and it all worked out.