Unable to upload Nativescript images to S3 - amazon-s3

I have a nativescript-vue application where I want to take a camera taken image and upload to my S3 bucket.
I installed the plugin:
tns plugin add nativescript-aws-sdk
I have in my app.js:
import { S3 } from "nativescript-aws-sdk/s3";
S3.init({ endPoint: '/images/person', accessKey: config.AWS_ACCESS_KEY, secretKey: config.AWS_SECRET_KEY, type: 'static' });
Vue.use(S3);
then in my function to upload an image:
uploadPicture() {
console.log('uploadPicture called..');
const s = new S3();
console.log('S3 inited..' + JSON.stringify(s));
But this results in:
CONSOLE LOG file:///node_modules/#nativescript/core/image-source/image-source.js:331:16: 'fromNativeSource() is deprecated. Use ImageSource constructor instead.'
CONSOLE LOG file:///app/components/Photo.vue:303:0: 'uploadPicture called..'
CONSOLE LOG file:///app/components/Photo.vue:304:0: 'S3 const..undefined'
So there is something with the S3.init() that is causing an error. I do not see many examples of this plugin online so either nobody has issues with it or its not being used?
Anyone who can see what I am doing wrong, can you kindly point me in the right direction?
Update:
Moved the import from vue file to app.js:
import { S3 } from "nativescript-aws-sdk/s3";
S3.init({ endPoint: '/images/person', accessKey: config.AWS_ACCESS_KEY, secretKey: config.AWS_SECRET_KEY, type: 'static' });
And in my Vue file:
import { S3 } from 'nativescript-aws-sdk/s3';
const s3 = new S3();
const imageUploaderId = s3.createUpload({
file: that.cameraImage,
bucketName: config.AWS_BUCKET_NAME,
key: `ns_${isIOS ? 'ios' : 'android'}`+fileName,
acl: 'public-read',
completed: (error, success) => {
if (error) {
console.log(`S3 Download Failed :-> ${error.message}`);
}
if (success) {
console.log(`S3 Download Complete :-> ${success.path}`);
}
},
progress: progress => {
console.log(`Progress : ${progress.value}`);
}
}).catch((err) => {
console.error("createUpload() caught error: " + JSON.stringify(err));
});
s3.pause(imageUploaderId);
s3.resume(imageUploaderId);
s3.cancel(imageUploaderId);
But nothing seems to happen - no errors or progress.

You've declared S3 twice, once globally:
import S3 from "nativescript-aws-sdk/s3";
and I'm guessing a local version inside the uploadPicture() method:
const S3 = require('nativescript-aws-sdk/s3').S3;
The import S3 has to do the init, not the later as per: https://market.nativescript.org/plugins/nativescript-aws-sdk

Related

Error while uploading Multiple Files with different File Names With Skipper in Sails Js

I am trying to upload multiple type of files to S3 in sails js
Files are as Follow : VehicleImages, VehicleVideos, VehicleDocuments
I am passing these three type of files with attribute name with same name as these files to my server via multipart/form-data
My approach is to upload one type of file lets say VehicleImages by using await
Then upload the next and then the next.
I am unable to do so since i get the error :
{
"cause": {
"code": "EMAXBUFFER",
"message": "EMAXBUFFER: An upstream (`vehicleDocuments`) timed out before it was
plugged into a receiver. It was still unused after waiting 4500ms.
You can configure this timeout by changing the `maxTimeToBuffer`
option.\n\nNote that this error might be occurring due to an earlier
file upload that is finally timing out after an unrelated server
error."
},
"isOperational": true,
"code": "EMAXBUFFER"
}
This is my code for policies folder
VehicleController: {
create: ["isLoggedIn", "vehicleImages", "vehicleKey", "vehicleDocuments"],
update: ["isLoggedIn", "vehicleImages", "vehicleKey", "vehicleDocuments"],
"*": "isLoggedIn",
},
This is the helper function that i am using in my policies
fn: async function (inputs) {
const { req, res, proceed, fieldName, folderName, setParams } = inputs;
const skipperUpstream = req.file(fieldName);
const file = skipperUpstream._files[0];
if (!file) {
// `skipperUpstream.__proto__` is `Upstream`. It provides `noMoreFiles()` to stop receiving files.
// It also clears all timeouts: https://npmdoc.github.io/node-npmdoc-skipper/build/apidoc.html#apidoc.element.skipper.Upstream.prototype.noMoreFiles
skipperUpstream.noMoreFiles();
return proceed();
}
let timestamp = Date.now();
let uploadedFiles = await sails.upload(req.file(fieldName), {
adapter: require("skipper-s3"),
key: process.env.AWS_ACCESS_KEY_ID,
secret: process.env.AWS_SECRET_ACCESS_KEY,
bucket: process.env.AWS_BUCKET_NAME,
region: "us-east-2",
headers: {
"x-amz-acl": "public-read",
},
// maxBytes: sails.config.custom.maxFileSize,
// change folder and file name
dirname: folderName,
saveAs: function (__newFileStream, next) {
next(undefined, timestamp + __newFileStream.filename);
},
});
sails.log("filesUploaded In Helper", uploadedFiles);
if (uploadedFiles) {
uploadedFiles.forEach((file) => {
file.fd =
process.env.AWS_BUCKET_URL +
((folderName ? folderName + "%5C" : "") +
timestamp +
file.filename.replaceAll("\\", "%5C"));
});
sails.log("filesUploaded", uploadedFiles[0]);
req.files = uploadedFiles;
setParams && setParams(uploadedFiles);
}
return proceed();
},
My aim to upload large files (images, videos, documents) from react application to s3 bucket . How can I do this?

aws amplify throws TypeError: Cannot read property 'byteLength' of undefined on device emulator only

I'm using the aws-amplify library to upload images from devices to aws amplify storage.
My config is :
Amplify.configure({
Auth: {
identityPoolId: 'xxxxxxxxxxxxxxxx',
region: 'xxxxxxxx',
userPoolId: 'xxxxxxxxxxxx',
userPoolWebClientId: 'x'
},
Storage: {
AWSS3: {
bucket: 'xxxxx-name',
region: 'xxxxxxxx',
}
}
});
and the Storage.put Method for uploading files.
On the browser, it works perfect, i can upload images.
But from the device (Android emulator) with cordova-plugin-camera it throws a cannot read property 'bytelength' of undefined.
Here is code used for mobile devices :
navigator.camera.getPicture(
data => {
Storage.put("test.jpeg", dataConvertedToBlob).then((res) => {
this.imageSrc = res.toString();
});
},
(err) => { // on fail
console.error('Could not access device camera.');
},
{
quality: 100,
destinationType: Camera.DestinationType.DATA_URL,
encodingType: Camera.EncodingType.JPEG,
sourceType: Camera.PictureSourceType.CAMERA,
mediaType: Camera.MediaType.PICTURE,
cameraDirection: Camera.Direction.BACK,
}
})
I tried a lot of convertion methods like sending to the put method blob, convert image to javascript File, sending base64 data, none of them worked on device
Any ideas ?

nativescript & S3

Part 2 of a earlier question on uploading camera images from my iOS to my S3 account
I have an S3 bucket with the default ACL and policy. I finally got my nativescript-aws-sdk to build and but I am struggling to see what I need to do to actually use it..
I have this:
app.js:
import { S3 } from "nativescript-aws-sdk/s3";
S3.init({ endPoint: '/images/person', accessKey: config.AWS_ACCESS_KEY, secretKey: config.AWS_SECRET_KEY, type: 'static' });
person.vue:
<script>
import { takePicture, requestPermissions } from "nativescript-camera";
import config from "../../config.json";
import { S3 } from 'nativescript-aws-sdk/s3';
const s3 = new S3();
...
requestPermissions()
.then( () => {
takePicture({ width: that.width, height: that.height, keepAspectRatio: that.keepAspectRatio, saveToGallery: that.saveToGallery, allowsEditing: that.allowsEditing })
.then((imageAsset) => {
that.cameraImage = imageAsset;
...
}
uploadPicture() {
console.log('uploadPicture called..');
var currentDate = new Date();
var timestamp = currentDate.getTime();
let fileName = this.person.lastName+ timestamp + '.jpg';
console.log('working with image file: ' + fileName);
console.log('working with image : ' + that.cameraImage);
const imageUploaderId = s3.createUpload({
file: that.cameraImage,
bucketName: config.AWS_BUCKET_NAME,
key: `ns_${isIOS ? 'ios' : 'android'}`+fileName,
acl: 'public-read',
completed: (error, success) => {
if (error) {
console.log(`S3 Download Failed :-> ${error.message}`);
}
if (success) {
console.log(`S3 Download Complete :-> ${success.path}`);
}
},
progress: progress => {
console.log(`Progress : ${progress.value}`);
}
}).catch((err) => {
console.error("createUpload() caught error: " + JSON.stringify(err));
});
console.log('working with iimageUploaderId: ' + imageUploaderId);
// s3.pause(imageUploaderId);
// s3.resume(imageUploaderId);
// s3.cancel(imageUploaderId);
}
However, I feel like I must be doing something wrong because the createUpload doesn't seem to complete as my error logs are:
CONSOLE LOG file:///app/components/Person.vue:304:0: 'uploadPicture called..'
CONSOLE LOG file:///app/components/Person.vue:308:0: 'working with image file: Flintstone1585334134497.jpg'
So am I missing something?

Is there a reason why my Nativescript app won't upload to S3 using 'nativescript-aws-sdk'?

I am trying to follow the demo from https://github.com/triniwiz/nativescript-aws-sdk to upload an image but when I run my app, it returns this error
ERROR Error: java.lang.NoClassDefFoundError: Failed resolution of:
Lorg/apache/commons/logging/LogFactory;
JS: com.amazonaws.AmazonWebServiceClient.<clinit>(AmazonWebServiceClient.java:65)
JS: com.tns.Runtime.callJSMethodNative(Native Method)
JS: com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1209)
JS: com.tns.Runtime.callJSMethodImpl(Runtime.java:1096)
JS: com.tns.Runtime.callJSMethod(Runtime.java:1083)
JS: com.tns.Runtime.callJSMethod(Runtime.java:1063)
JS: com.tns.Runtime.callJSMethod(Runtime.java:1055)
JS: android.view.View.performClick(View.java:7327)
JS: android.widget.TextView.performClick(TextView.java:14160)
JS: android.view.View.performClickInternal(View.java:7299)
JS: android.view.View.access$3200(View.java:846)
JS: android.view.View$PerformClick.run(View.java:27773)
JS: android.os.Handler.handleCallback(Handler.java:873)
JS: android.os.Handler.dispatchMessage(Hand...
for reference here is what our component.ts file looks like:
export class BrowseComponent implements OnInit {
constructor() {
// Use the component constructor to inject providers.
}
ngOnInit(): void {
// Use the "ngOnInit" handler to initialize data for the view.
S3.init(<any>{
endPoint: '',
accessKey: 'our accessKey',
secretKey: 'our secretKey',
type: 'static' }); // <= Try calling this before the app starts
}
export function uploadFile() {
const s3 = new S3();
const imageUploaderId = s3.createUpload({
file: '~src/app/assets/Lena.jpg',
bucketName: 'our bucketName',
key: `ns__Lena.jpg`,
acl: 'public-read',
completed: (error, success) => {
if (error) {
console.log(`Download Failed :-> ${error.message}`);
}
if (success) {
console.log(`Download Complete :-> ${success.path}`);
}
},
progress: progress => {
console.log(`Progress : ${progress.value}`);
}
});
s3.pause(imageUploaderId);
s3.resume(imageUploaderId);
s3.cancel(imageUploaderId);
}
Any help would be appreciate plz. Thanks!
It looks like this has been an issue for some time.
From a totally naïve perspective, I would suggest installing log4j in your app, since that's the package that is failing to be found. The proper solution is obviously have to have the plugin do that for you, but doing it yourself should fix the problem.

Preload / Pre-populate PouchDB in React Native Application

Is it possible to preload / pre-populate a database in my React Native application and then the first time it is run, simply do a sync? I already have most, if not all of the database information before the app is distributed, it would be awesome if it just had to do a quick sync when the app is run. Any ideas how I would go about doing that?
I found this - https://pouchdb.com/2016/04/28/prebuilt-databases-with-pouchdb.html but it doesn't mention React Native
Using:
pouchdb-find: ^7.0.0
pouchdb-react-native: ^6.4.1
react: 16.3.1
react-moment: ^0.7.9
react-native: ~0.55.2
Thanks for any pointers.
Update Here is the code I'm using to try the loading of a dump file. This code exists in /screens/Home.js
The dump file is located in /client/dbfile/database.txt
var db = new PouchDB("cs1");
db.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
db.load("/client/dbfile/database.txt").then(function() {
return db.put({ _id: "_local/initial_load_complete" });
});
})
.then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return db.allDocs({ include_docs: true });
})
.then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
this.localDB = db;
When this runs my console displays this - showing there have been 0 rows added.
Object {
"offset": 0,
"rows": Array [],
"total_rows": 0,
}
Possible Unhandled Promise Rejection (id: 0):
Object {
"message": undefined,
"name": "unknown",
"status": 0,
}
In my project I have couple of db docs I distribute with app (translations JSON is the one good example).
So at app init I just try to read translations doc from db, if there is none - I import content from js module and store in db.
Then translations changes just being replicated from server to local db.
//transmob.js
const transMobFile = {
//content goes here
);
module.exports = transMobFile
//dbInit.js
import transMobFile from 'data/transMob';
..
PDB.getDoc('TransMob')
.then((doc)=> {
if (!doc) {
global.locales = transMobFile.localesMob; // locales
global.translations = transMobFile.langMob; // translations
return PDB.saveDoc('TransMob', transMobFile)
}
})
You can use react-native-fs to load a file from /android/app/src/main/assets. Just put the file into the assets folder and read it with RNFS.readFileAssets.
import PouchDB from 'pouchdb-core';
PouchDB
.plugin(require('pouchdb-find'))
.plugin(require('pouchdb-load'));
import RNFS from 'react-native-fs';
const localDB = new PouchDB("cs1", {adapter: 'asyncstorage'});
localDB.get("_local/initial_load_complete")
.catch(function(err) {
console.log("loading dumpfile");
if (err.status !== 404) {
// 404 means not found
throw err;
}
RNFS.readFileAssets('yourdb.txt', 'utf8')
.then((contents) => {
localDB.load(contents).then(function() {
return localDB.put({ _id: "_local/initial_load_complete" });
}).then(function() {
// at this point, we are sure that
// initial replication is complete
console.log("loading is complete!");
return localDB.allDocs({ include_docs: true }).then(
function(res) {
// display all docs for debugging purposes (empty)
console.log(res);
});
}, function(err) {
console.log(err);
});
})
})
You'll need to rebuild your project, reloading is not sufficient.
My project crashes when I attempt to load a 30MB file, so I probably will split it into a few smaller files. Check out https://github.com/pouchdb-community/pouchdb-load to see how this works if needed.
I found that the db.load() function from the pouchdb-load module requires a URL. I was pointing it to a file path on the device's filesystem. I placed my database.txt file on my server, changed it to use the url and it worked.
In my mind this isn't ideal because if they install the app and have slow wireless, it still has to pull the file from the server. It is still much faster than performing a full-on replicate when the app opens for the first time however.