In my worker I am converting a base64 string I get from the request to a blob with some function. However, when I try to PUT the blob into my bucket, I get "Network Connection Lost" error. I can successfully PUT just the base64 string or any other string but not a blob. Here is my worker:
// Function to convert b64 to blob (working fine)
function b64toBlob(b64Data, contentType, sliceSize=512) {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
switch (request.method) {
case 'PUT':
const contentType = 'application/pdf';
const b64Data = request.body;
const blob = b64toBlob(b64Data, contentType);
try {
await env.qa_sub_agreements_bucket.put(key, blob, { // Failing here
httpMetadata: request.headers,
})
return new Response(blob) // Successfully returns the blob when above PUT is commented out
} catch (e) {
console.error(e.message, e.stack); // Logs out "Error: Network Connection Lost"
}
Hard to say definitively because the Worker posted doesn't appear to be totally complete. An eagle-eyed coworker spotted that it looks like the problem may be that you're invoking atob on a ReadableStream and likely that conversion is what's throwing the exception.
I am using AWS SDK to upload a file to S3. Locally works fine, but on the deployed server it gives this error: Received an unexpected EOF or 0 bytes from the transport stream.
Here is the code:
var location = $"some-location";
using (var stream = request.File.OpenReadStream())
{
var putRequest = new PutObjectRequest
{
Key = location,
BucketName = configuration["AWS:BucketName"],
InputStream = stream,
AutoCloseStream = true,
ContentType = request.File.ContentType
};
var putResponse = await amazonS3.PutObjectAsync(putRequest);
response.IsValid = putResponse.HttpStatusCode == System.Net.HttpStatusCode.OK;
}
request.File is FormFile and passed in from controller like this:
public async Task<UploadResponse> Upload(IFormFile formFile)
{
if (formFile is null || formFile.Length <= 0)
{
throw new ArgumentNullException(nameof(formFile));
}
//TODO: Validate File Extension
UploadResponse response;
UploadCommand command = new UploadCommand();
command.File = formFile;
response = await mediator.Send(command);
return response;
}
I want to upload multiple images into the Rest API. I tried the below code to upload a single image to the rest API. That is working fine, for multiple image selection I'm using multi_image_picker link, how can I modified below code to upload multiple images? Thank you
Future<String> uploadSingleImage(File file,String userid) async
{
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key ) ?? 0;
String fileName = file.path.split("/").last;
var stream =
new http.ByteStream(DelegatingStream.typed(file.openRead()));
// get file length
var length = await file.length(); //imageFile is your image file
Map<String, String> headers = {
"Accept": "application/json",
"Authorization": "Bearer $value"
}; // ignore this headers if there is no authentication
// string to uri
var uri = Uri.parse(serverUrl + "/api/v1/upload_parent_image");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// multipart that takes file
var multipartFileSign = new http.MultipartFile('photo',
stream,
length,
filename: fileName
);
// add file to multipart
request.files.add(multipartFileSign);
//add headers
request.headers.addAll(headers);
//adding params
request.fields['id'] = userid;
// request.fields['firstName'] = 'abc';
// request.fields['lastName'] = 'efg';
// send
var response = await request.send();
print(response.statusCode);
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
your Image list
List<String> photos = ["path of image1","path of image2", "path of image3",];
List<http.MultipartFile> newList = [];
for (var img in photos!) {
if (img != "") {
var multipartFile = await http.MultipartFile.fromPath(
'Photos',
File(img).path,
filename: img.split('/').last,
);
newList.add(multipartFile);
}
}
request.files.addAll(newList);
You could pass a list of files to your method, loop over to build each MultipartFile objects and add them to your MultipartRequest
Future<String> uploadMultipleImage(List<File> files, String userid) async {
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
// string to uri
var uri = Uri.parse(serverUrl + "/api/v1/upload_parent_image");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
for (var file in files) {
String fileName = file.path.split("/").last;
var stream = new http.ByteStream(DelegatingStream.typed(file.openRead()));
// get file length
var length = await file.length(); //imageFile is your image file
// multipart that takes file
var multipartFileSign = new http.MultipartFile('photo', stream, length, filename: fileName);
request.files.add(multipartFileSign);
}
Map<String, String> headers = {
"Accept": "application/json",
"Authorization": "Bearer $value"
}; // ignore this headers if there is no authentication
//add headers
request.headers.addAll(headers);
//adding params
request.fields['id'] = userid;
// request.fields['firstName'] = 'abc';
// request.fields['lastName'] = 'efg';
// send
var response = await request.send();
print(response.statusCode);
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
Well you are almost close to send multiple files at a time let me post some code
Future<String> uploadSingleImage(File file,File file2,String userid) async
{
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key ) ?? 0;
String fileName = file.path.split("/").last;
var stream =
new http.ByteStream(DelegatingStream.typed(file.openRead()));
// get file length
var length = await file.length(); //imageFile is your image file
Map<String, String> headers = {
"Accept": "application/json",
"Authorization": "Bearer $value"
}; // ignore this headers if there is no authentication
// string to uri
var uri = Uri.parse(serverUrl + "/api/v1/upload_parent_image");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// multipart that takes file
var multipartFileSign = new http.MultipartFile('photo',
stream,
length,
filename: fileName
);
// add file to multipart
request.files.add(multipartFileSign);
// Now Adding file 2 in request
String fileName2 = file2.path.split("/").last;
var stream2 =
new http.ByteStream(DelegatingStream.typed(file2.openRead()));
var lengthOfFile2 = await file2.length();
// multipart that takes file
var multipartFile2 = new http.MultipartFile('file2_key_here',
stream2,
lengthOfFile2,
filename: fileName2
);
// add file2 to multipart
request.files.add(multipartFile2);
//add headers
request.headers.addAll(headers);
//adding params
request.fields['id'] = userid;
// request.fields['firstName'] = 'abc';
// request.fields['lastName'] = 'efg';
// send
var response = await request.send();
print(response.statusCode);
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
I have shared my code that i used to upload mutliple image with this packages
multi_image_picker: ^4.8.0
flutter_absolute_path: ^1.0.6
flutter_image_compress:
path_provider
http
flutter compress and path provider are used to compress the size
Http request code
static Future<String> uploadMultipleImage({List<File> files}) async {
// string to uri
var uri = Uri.parse("your api url");
print("image upload URL - $uri");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
for (var file in files) {
String fileName = file.path.split("/").last;
var stream = new http.ByteStream(DelegatingStream.typed(file.openRead()));
// get file length
var length = await file.length(); //imageFile is your image file
print("File lenght - $length");
print("fileName - $fileName");
// multipart that takes file
var multipartFileSign = new http.MultipartFile('images[]', stream, length,
filename: fileName);
request.files.add(multipartFileSign);
}
Map<String, String> headers = {
"Accept": "application/json",
"Authorization":
"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMiwiZXhwIjoxNjE3NTQyNDE0LCJpc3MiOiJsb2NhbGhvc3QiLCJpYXQiOjE2MTcxODI0MTR9.dGRbINOdx_tf417fpsjdQ5CR7uGULs98FjLGm2w4kRY"
}; // ignore this headers if there is no authentication
print("headers - $headers}");
//add headers
request.headers.addAll(headers);
//adding params
request.fields['heading'] = "heading";
request.fields['description'] = "description";
request.fields['mobile'] = "mobile";
request.fields['email'] = "email";
request.fields['category'] = "1";
request.fields['location_type'] = "1";
request.fields['location'] = "location";
request.fields['lat'] = "12";
request.fields['lng'] = "123";
request.fields['price'] = "1231";
request.fields['sub_category'] = "3";
// send
var response = await request.send();
print(response.statusCode);
var res = await http.Response.fromStream(response);
if (response.statusCode == 200 || response.statusCode == 201) {
print("Item form is statuscode 200");
print(res.body);
var responseDecode = json.decode(res.body);
if (responseDecode['status'] == true) {
return res.body;
} else {
return res.body;
}
}
}
My UI screen where I call the method
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_absolute_path/flutter_absolute_path.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:lookapt_olx_app/service/ApiService.dart';
import 'package:lookapt_olx_app/utils/Utils.dart';
import 'package:lookapt_olx_app/utils/colorUtils.dart';
import 'package:lookapt_olx_app/utils/fontUtils.dart';
import 'package:lookapt_olx_app/widgets/appbar_widget.dart';
import 'package:lookapt_olx_app/widgets/commonWidget.dart';
import 'package:lookapt_olx_app/widgets/textFieldWidget.dart';
import 'package:lookapt_olx_app/widgets/textWidgets.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
import 'package:rounded_loading_button/rounded_loading_button.dart';
import 'addNewPostController.dart';
import 'multiImagePicker.dart';
import 'package:path_provider/path_provider.dart' as path_provider;
class AddNewPostScreen extends StatefulWidget {
Map<String, dynamic> parameters;
String categoryId;
AddNewPostScreen({this.parameters, this.categoryId = ""});
#override
_AddNewPostScreenState createState() => _AddNewPostScreenState();
}
class _AddNewPostScreenState extends State<AddNewPostScreen> {
#override
void initState() {
super.initState();
print("add new post");
print(widget.parameters['name']);
print(widget.categoryId.toString());
}
List<Asset> images = [];
String _error = "";
Widget buildGridView() {
if (images != null)
return GridView.count(
crossAxisCount: 3,
crossAxisSpacing: 10,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
else
return Container(color: Colors.white);
}
Future<void> loadAssets() async {
setState(() {
images = List<Asset>();
});
List<Asset> resultList;
String error;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 3,
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
if (error == null) _error = 'Selected images';
});
}
/*
Usage
final dir = await path_provider.getTemporaryDirectory();
final targetPath = dir.absolute.path + "/temp.jpg";
File imgFile = await testCompressAndGetFile(
File(_capturedImage.path), targetPath);
* */
Future<File> testCompressAndGetFile(File file, String targetPath) async {
print("testCompressAndGetFile");
final result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
targetPath,
quality: 30,
minWidth: 1024,
minHeight: 1024,
// rotate: 90,
);
print(file.lengthSync());
print(result.lengthSync());
return result;
}
_uploadImageFun() async {
print("Note - _getImagePaths called");
List<File> fileImageArray = [];
images.forEach((imageAsset) async {
final filePath =
await FlutterAbsolutePath.getAbsolutePath(imageAsset.identifier);
File tempFile = File(filePath);
print(filePath);
print("filePath.length - ${filePath.length}");
print(tempFile);
print("tempFile.length() - ${tempFile.lengthSync()}");
if (tempFile.existsSync()) {
DateTime now = DateTime.now();
final dir = await path_provider.getTemporaryDirectory();
final targetPath =
dir.absolute.path + "/lookaptPostImage${now.microsecond}.jpg";
File imgFile =
await testCompressAndGetFile(File(tempFile.path), targetPath);
print("Compressed image");
print(imgFile.lengthSync());
fileImageArray.add(imgFile); //with image compress
}
if (fileImageArray.length == images.length) {
var res = await ApiService.uploadMultipleImage(files: fileImageArray);
print("image upload response");
print(res);
var resp = json.decode(res);
if (resp['status'] == true) {
SuccessToastWidget(context, message: resp['message']);
} else {
FailedToastWidget(context, message: resp['message']);
}
}
});
print("Test Prints");
print(fileImageArray.length);
return fileImageArray;
}
final RoundedLoadingButtonController _loginBtnController =
new RoundedLoadingButtonController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppBarWidget(title: widget.parameters['name'] ?? ""),
body: _body(),
);
}
AddNEwPostController _addNEwPostController = new AddNEwPostController();
Widget _body() {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
child: ListView(
children: [
InkWell(
onTap: loadAssets,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
color: Colors.grey.shade400,
child: ListTile(
leading: Icon(
Icons.add_box_outlined,
size: 30,
color: Colors.black,
),
trailing: MyTextWidgets.textWidgetSemiBold(
str: "Pick Images", fontSize: 20),
),
),
),
),
RoundedLoadingButton(
child: MyTextWidgets.textWidgetBold(
fontSize: 16, str: "Next", color: MyColors.white.redC),
controller: _loginBtnController,
onPressed: () {
_getImagePaths();
},
width: MediaQuery.of(context).size.width,
borderRadius: 10,
color: MyColors.appGreenColor.redC,
height: 44,
),
Center(
child: _error == ""
? Container()`enter code here`
: MyTextWidgets.textWidgetLight(str: _error)),
Container(
child: buildGridView(),
height: 100,
width: MediaQuery.of(context).size.width - 100,
),
],
),
);
}
}
NOTE:
My ui code may not run in your code so only copy the required code from the Screen code.
Http request code will work fine just copy and past it
Thank for you support!
I am posting this solution with dio and image_picker dependency. And it will definitely work. I have spent 2 days for this solution.
FormData formData = new FormData.fromMap({
"name": "Max",
"location": "Paris",
"age": 21,
"image[]": [
await MultipartFile.fromFile(
_imageFile.path,
),
await MultipartFile.fromFile(
_imageFile.path,
),
],
});
print(FormData1().then((value) {
print(value);
}));
response = await dio.post(
"http://143.110.244.110/radius/frontuser/eventsubmitbutton",
data: formData,
onSendProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + '%');
}
},
);
print(response);
I've created an api to upload images to my s3 bucket, but currently the images which I upload to s3 seem to be unreadable so I'm guessing they're corrupted?
Here is my code below:
const AWS = require('aws-sdk')
const s3= new AWS.S3()
const crypto = require("crypto")
const sha1 = data => {
return crypto.createHash("sha1").update(data).digest("hex")
}
const getFile = (ext, buffer, type) => {
let encryptedFileName = sha1(new Buffer(new Date().toString()))
//let timeBasedFileName = new Date().valueOf()
let fileName = encryptedFileName+'.'+ext
let bucketPath = "bucketname/folder/"+type //eg: bucket1/animals/fish
let fileFullPath = bucketPath+"/"+fileName //eg: bucket1/animals/fish/salmon.jpg
let params = {
Bucket: 'mybucket',
Body: buffer,
ContentType: ext==='jpg'||ext==='jpeg'?'image/jpeg':'image/'+ext,
Key: fileName
}
let uploadFile = {
size: buffer.toString('ascii').length,
type: ext==='jpg'||ext==='jpeg'?'image/jpeg':'image/'+ext,
name: fileName,
full_path: fileFullPath
}
return {params,uploadFile}
}
exports.handler = (event, context, callback) => {
let base64String = event.base64String
let ext = base64String.substring("data:image/".length, base64String.indexOf(";base64"))
if (ext===null || (ext!=='jpg' && ext!=='jpeg' && ext!=='gif' && ext!=='png')) {return context.fail('Base64 string is not a supported file type.')}
//pass base64 string into buffer
let buffer = new Buffer(base64String, 'base64')
let file = getFile(ext, buffer, event.type)
//callback(null, 'working fine')
let params = file.params
s3.putObject(params, function(err,data) {
// example response: {"filename":"0242CCB0-CE2E-4C75-A02E-FC054DA9E743.png","status":1,"message":"save success"}
let response = {"statusCode": 400, "filename": "", status: 0, message: "save fail"}
if (err) {callback(err, null)}
response.statusCode=200
response.filename=file.uploadFile.name
response.status=1
response.message="save success"
callback(null, response)
})
}
I'm basically converting a base64 image string into a buffer & uploading it.
What did I do wrong here?
I'm able to create the JSZip object in my code, but I'm having trouble saving that to local storage in my windows 8 app. The examples I'm able to find set the browser's location.href to trigger a download, which isn't really an option for me.
I've included my code below. The zip file I end up with is invalid and can't be opened. Any help would be appreciated.
For reference: JSZip
function _zipTest() {
var dbFile = null;
var zipData = null;
Windows.Storage.StorageFile.getFileFromPathAsync(config.db.path)
.then(function (file) {
dbFile = file;
return Windows.Storage.FileIO.readBufferAsync(file);
})
.then(function (buffer) {
//Read the database file into a byte array and create a new zip file
zipData = new Uint8Array(buffer.length);
var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
dataReader.readBytes(zipData);
dataReader.close();
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
return localFolder.createFileAsync(dbFile.displayName.concat('.zip'), Windows.Storage.CreationCollisionOption.replaceExisting)
})
.then(function (file) {
//Write the zip data to the new zip file
var zip = new JSZip();
zip.file(dbFile.displayName, zipData);
var content = zip.generate();
return Windows.Storage.FileIO.writeTextAsync(file, content);
});
}
you can do something on these lines. This code seem to generate valid .zip file in the temp folder.
var zip = new JSZip();
var storage = Windows.Storage;
storage.StorageFile.getFileFromApplicationUriAsync(new Windows.Foundation.Uri('ms-appx:///images/logo.png')).then(function ongetfile(file)
{
var blob = MSApp.createFileFromStorageFile(file);
var url = URL.createObjectURL(blob, { oneTimeOnly: true });
return WinJS.xhr({ url: url, responseType: 'arraybuffer' });
}).then(function onreadbuffer(req)
{
var b = req.response;
zip.file('logo.png', b);
return storage.ApplicationData.current.temporaryFolder.createFileAsync('a.zip', storage.CreationCollisionOption.replaceExisting);
}).then(function onnewfile(out)
{
var content = zip.generate({ type: 'uint8array' });
return storage.FileIO.writeBytesAsync(out, content);
}).then(null, function onerror(error)
{
// TODO: error handling
});