In react native Fetch(localUri) throws error: network request failed. Only on file sizes larger then 195 mb - react-native

--expo managed react native application--
--android--
--internal distribution--
I am uploading local mp4's to an s3 bucket with aws-sdk.
It requires I put data into blob format before I push to s3 with AWS.S3.putObject(params).
const uploadFile = async (file) => {
let blob
let response
try{
response = await fetch(location);
}
catch(e){console.log('fetch error', e)}
try {
blob = await response.blob();
}
catch(e){console.log('Blobify Error:', e)}
The above code works to fetch and blob mp4 video files from a local uri, as the aws sdk requires blobs. For some reason if the mp4 file is greater than ~190mb, the same code fails with a network request failed error, generated from the fetch request. To be clear the code fails during the local fetch before it can be passed to the aws-sdk to uploaded.
After reading several tutorials and feedback, although no one has mentioned the size issues I am experiencing. I experimented with rewriting the code using xmlHttpRequest() as below. It also succeeds for all files below ~190 megabytes and fails for anything above 190mb. Once again it fails locally before it can be .blob() and passed to aws-sdk.
let makeBlob
try{
makeBlob = (url)=> {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onerror = reject;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('GET', url);
xhr.responseType = 'blob'; // convert type
xhr.send();
})
}
}catch(e){console.error('blob fail:', e)}
So as a recap separate protocols for fetching a uri both fail in the same way, I would accept other options for converting my uri to blob format or some ideas of what is causing this failure.

Related

React Native - xhr.upload.onprogress showing inaccurate result

I am using xhr to upload images and videos in a React Native mobile app (currently only tested on Android).
The actual upload works correctly however the xhr.upload.onprogress callback is reporting inaccurate data. For example, when uploading a large file (~70mb) this returns 0%, then 69%, then 98%, then 100% - this is returned over the first few seconds even though the actual file upload takes ~1-2 minutes.
Here is my code:
const formData = new FormData();
formData.append("FileInput", {
uri: uri,
type: "video/" + ext,
name: fileName,
});
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.onload = () => {
const response = JSON.parse(xhr.response);
resolve(true);
};
xhr.onerror = (e) => {
console.log(e, "upload failed");
};
xhr.ontimeout = (e) => {
console.log(e, "upload timeout");
};
xhr.send(formData);
if (xhr.upload) {
xhr.upload.onprogress = ({ total, loaded }) => {
uploadProgress = Math.round((loaded / total) * 100);
console.log(uploadProgress, total, loaded);
};
}
Any pointers to what might be going on here would be really appreciated.
UPDATE: I have also implemented this upload using axios and get exactly the same issue where the onUploadProgress reports 100% very quickly even though the actual upload takes much longer.
const config = {
onUploadProgress: (progressEvent) => {
uploadProgress = Math.round(progressEvent.loaded / progressEvent.total) * 100;
console.log(uploadProgress);
},
headers: { "Content-Type": "multipart/form-data" },
};
const upload = await axios.post(url, formData, config);
Ok, I've figured this out. Just in case this helps someone else:
The issue was occurring when running a development bundle on a metro server - axios/xhr was reporting on the status of the upload of the file to the metro proxy rather than to it's final destination on the net.
When I created an apk build everything was working correctly.

AWS Upload Fails on 2nd and next few tries to s3 with s3.upload function

I am using the following code to upload multiple images to s3 bucket using AWS API gateway.
And a strange issue is happening that when I upload image for the first time it uploads fine but when I try to upload again it fails the upload to s3 bucket.
After some time when I try again it works and again fails.
const s3Client = new AWS.S3({
credentials: {
accessKeyId: process.env.AWS_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_S3_SECRET_ACCESS_KEY,
region: ''
},
});
And when it fails it does not print any logs which are after s3Client.upload() function call. Not sure How to debug this? I have tried to add progress check but it never goes into that check when upload fails.
Maybe its upload frequency limit on s3? I didn't find any such limit on aws docs though.
if (contentType && contentType.includes('multipart/form-data;')) {
const result = await parser.parse(event);
body = await schema.parseAsync(JSON.parse(result.JsonData))
console.log('DEBUG>>>>> HandlerTS File: JSON.parse(result.JsonData): ', body)
console.log('DEBUG>>>>> HandlerTS File: Result: ', result)
if (result.files) {
result.files.forEach(f => {
console.log("DEBUG>>>>> Uploading file")
console.log(f)
s3Client.upload(
{
Bucket: bucket,
Key: `${body.name}/${f.filename}`,
Body: f.content,
},
(err, data) => {
console.log(err, data);
},
).on("httpUploadProgress", (progress) => {
const uploaded = Math.round(progress.loaded / progress.total * 100);
console.log('DEBUG>>>>>>>>>> checking http upload progress ', uploaded)
}).send(function (err, data) {
if (err) {
// an error occurred, handle the error
console.log('DEBUG>>>>>>>>>>>>>> Error Upload')
console.log(err, err.stack);
return;
}
const fileUrl = data.Location;
console.log('DEBUG>>>>>>>>>>>>>> File URL:', fileUrl);
});
})
}
P.s: I am using API gateway and lambda functions.

Send image in attachments by URL in Circuit JS SDK

I'm using a Circuit JS SDK and want to send message with attached image. I found on documentation that I should set the item.attachments to File[] object. But how can I do it if I have only image URL (like https://abc.cde/fgh.png)?
To be able to post an image in a conversation, the image needs to be uploaded to Circuit which is done internally in the addTextItem API as you already found out. And yes this API takes an array of File objects.
You will need to download the image via XMLHttpRequest as blob and then construct a File object.
const xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.open('GET',<url of image> , true);
xhr.onreadystatechange = async () => {
if (xhr.readyState == xhr.DONE) {
const file = new File([xhr.response], 'image.jpg', { lastModified: Date.now() });
const item = await client.addTextItem(convId.value, {
attachments: [file]
});
}
};
xhr.send();
Here is a jsbin https://output.jsbin.com/sumarub

How does one upload an m4a audio file to Firebase Storage using react-native and expo?

I am building an app using react-native and expo. One feature of the app allows a user to record audio and then upload it to Firebase Storage. I manage to successfully record the audio and also manage to retrieve the cached file as a blob but when trying to upload it to Firebase Storage it fails with error code 400, "Bad Request. Could not create object". What baffles me is that I use the same process to upload images which works perfectly. Why does it fail for audio files?
I manage to record the audio successfully and I retrieve the cached file (as a blob) using XMLHttpRequest. The resultant blob that outputs when I log it to the console looks something like this:
Blob {
"_data": Object {
"blobId": "lengthy blob id",
"name": "recording-XXXXXX.m4a",
"offset": 0,
"size": 371097,
"type": "audio/x-m4a",
},
}
When I try uploading to Firebase Storage using ref.put(blob) it returns with a 400 error: "Bad Request. Could not create object". I have also tried supplying the contentType as part of the metadata to see if that will make a difference but to no avail.
This is how I fetch my file:
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = () => {
resolve(xhr.response);
};
xhr.onerror = (e) => {
reject(new TypeError('Network request failed'));
};
xhr.responseType = 'blob';
xhr.open('GET', uri, true);
xhr.send(null);
});
To upload the blob to Firebase Storage I do the following:
const clientuid = 123;
const siteid = 'ABC';
const audioName = `${Date.now}.m4a`;
this.setState({ uploading: true });
const ref = firebase.storage().ref().child(`audio/${clientuid}/${siteid}/${audioName}`);
ref.put(blob)
.then(async (snapshot) => {
const fullUrl = await snapshot.ref.getDownloadURL();
// Upload the Url to Firebase realtime database...
Alert.alert('Upload Successful');
.catch((error) => {
console.log(error.serverResponse);
Alert.alert('Failed to create object!');
})
.finally(() => {
blob.close()
this.setState({ uploading: false });
});
The upload fails with the following error.serverResponse:
{
"error": {
"code": 400,
"message": "Bad Request. Could not create object",
"status": "CREATE_OBJECT"
}
}
In your case I think you can also create the blob by fetching the file with the file path.
let res = await fetch(filePath);
let blob = await res.blob
In my case this always works.

Fetch Put API to upload image using signed url

I am using puppeteer and I have a requirement where I have to upload screenshot on S3.
I am using fetch PUT api with signed url and my image is png format.
Everytime I am getting an error 'failed to fetch'. I have tried keeping image inmemory and in local storage but neither of them working.
await page.evaluate(async(signedUrl,screenshot) =>{
(function generateXHRRequest(){
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.stringify(xhr.response));
}
};
xhr.open("PUT", signedUrl);
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('Accept', 'image/png');
xhr.setRequestHeader('Access-Control-Allow-Origin','*');
xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true');
xhr.send(screenshot.data);
})();
},signedUrl,screenshot);
})
I have captured screenshot and kept it in memory. Now passing that to the above function.
Here byte array is copied to file as text and from S3 , when i download file manually, '.txt' file is downloaded.