const Web3 = require('web3');
const fs = require('fs')
const web3 = new Web3("http://localhost:7545");
const contract_address = "0x7484d32e891817702c5d7c764dBF7e592000b415";
async function web3Contract() {
const contract_abi = fs.readFileSync('./build/contracts/Bottle.json', 'utf8')
const Bottle = await new web3.eth.Contract(JSON.parse(contract_abi).abi, contract_address);
Bottle.methods.setName("Palm").send();
Bottle.methods.getGreeting().call();
}
async function run() {
try {
await web3Contract();
} catch (err) {
console.log('Your error is this - ' + err);
}
}
run();
I'm getting a error "UnhandledPromiseRejectWarning". I been googling this for hours and can't seem to fix this. Please guide me in the right direction. Thank you.
Pointer 1: Don't evaluate JSON.parse(contract_abi).abi as a parameter. If you do there is no way checking what it is - and it is possibly causing the error. Better:
const contract_abi = fs.readFileSync('./build/contracts/Bottle.json', 'utf8');
const abi = JSON.parse(contract_abi).abi;
console.log( abi); // do you get this far?
const Bottle = await new web3.eth.Contract(abi, contract_address);
Pointer 2: Don't log the string value of an error object when debugging - you will only get its toString() result which looks to be the same as logging error.message. Better:
console.log('Your error is this - ', err);
Supplying err as a second argument causes node to log additional properties of the error object including error.stack which provides trace information.
Related
I'm trying to get the current block number from Binance Smart Chain (BSC).
In the documentation, provider.getBlockNumber() returns a Promise object.
Here are my attempts to consume and print the current block number into console.
I'm using Node.js v16.5.0 and Ethers.js 5.4.1.
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
const blockNumber = async function() {
return await provider.getBlockNumber();
}
console.log(blockNumber());
process.exit();
This returns Promise { <pending> } on the console.
This block of code:
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
async function blockNumber() {
const blockNumber = await provider.getBlockNumber();
return blockNumber();
}
blockNumber().then(data => {console.log(data)});
process.exit();
output exactly nothing in the console, almost as there's nothing wrong in the code.
Expected output should be a number, like 9380976.
Where did I go wrong?
EDIT 1: Added process.exit() because that's supposed to be in the original post.
ANSWER by #purple:
var ethers = require("ethers");
var url = "wss://bsc-ws-node.nariox.org:443";
const provider = new ethers.providers.WebSocketProvider(url);
async function blockNumber() {
const blockNumber = await provider.getBlockNumber();
return blockNumber;
}
blockNumber().then(data => {
console.log(data)
process.exit();
});
Result:
> node app
*pauses for a bit, then prints*
9397167
>
Did you mean return blockNumber; instead of return blockNumber();?
I am reading a json file from within a zip file using jszip. I can open it and get the information that I want into the console from my function. I can't however get that information out of my javascript function. Maybe I am doing it wrong. Don't usually code using js.
const JSZip = require("jszip");
const fs = require("fs");
var myReturn;
function readJsons(bookPath,bookName,fileName,filePath,keyOption){
fs.readFile(bookPath + bookName, function(err, data) {
if (err) throw err;
JSZip.loadAsync(data).then(function (zip) {
// Read the contents of the '.txt' file
zip.file(filePath + fileName).async("string").then(function (data) {
var mydata = JSON.parse(data);
//gets the value of the key entered
myReturn = JSON.stringify(mydata[0][keyOption]); //value here should be "test book"
console.log(myReturn); //printed in console is "test book" works to here
return myReturn;
});
});
});
}
console.log(readJsons('simplelbook.zip','','frontMatter.json','','bookName'));
The problem is that you are returning inside the callback, so you aren't returning in the actual function. The solution would be using async/await instead:
const JSZip = require("jszip");
const fs = require("fs");
const util = require("util"); // require the util module
const readFile = util.promisify(fs.readFile); // transform fs.readFile into a more compatible form
async function readJsons(bookPath, bookName, fileName, filePath, keyOption) {
try {
// this part does the same thing, but with different syntax
const data = await readFile(bookPath + bookName);
const zip = await JSZip.loadAsync(data);
const jsonData = await zip.file(filePath + fileName).async("string");
const mydata = JSON.parse(jsonData);
const myReturn = JSON.stringify(mydata[0][keyOption]);
return myReturn; // return the data, simple as that
} catch (e) {
console.error(e); // error handling
}
}
(async () => { // self executing async function so we can use await
console.log(
await readJsons("simplelbook.zip", "", "frontMatter.json", "", "bookName")
);
})()
Notice I have imported the util module to turn fs.readFile into a function that is more suited for async/await :)
I get the error Error in function [undefined:: object is not iterable (cannot read property Symbol(Symbol.iterator))] (I typed out the error in function) when running a User onDelete Firebase Cloud Function, which is a near mirror of my User onCreate function (that works like a charm):
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const FS = admin.firestore();
const FA = admin.auth();
exports.newUser = functions.auth.user().onCreate(async(user)=>{
const fTime = admin.firestore.Timestamp.now()
const day = fTime.toDate().toLocaleDateString().replace('/','-').replace('/','-')
const time = fTime.toDate().toLocaleTimeString('en',{hour12:false})+'.'+fTime.toDate().getMilliseconds()
try {
const act1 = FS.doc(`users/${user.uid}`).create({email:user.email})
const act2 = FS.doc(`globalEvents/${day}`).set({[time]:{time:fTime,source:'Function newUser',description:`Account created for [${user.uid} - ${user.email}]`}},{merge:true})
const promise = await Promise.all(act1,act2)
return promise
}
catch (err) {
return FS.doc(`globalEvents/${day}`).set({[time]:{time:fTime,source:'Function newUser',description:`Error in function [${err.code}:: ${err.message}]`}},{merge:true})
}
})
exports.delUser = functions.auth.user().onDelete(async(user)=>{
const fTime = admin.firestore.Timestamp.now()
const day = fTime.toDate().toLocaleDateString().replace('/','-').replace('/','-')
const time = fTime.toDate().toLocaleTimeString('en',{hour12:false})+'.'+fTime.toDate().getMilliseconds()
try {
const act1 = FS.doc(`users/${user.uid}`).delete()
const act2 = FS.doc(`globalEvents/${day}`).set({[time]:{time:fTime,source:'Function delUser',description:`Account deleted for [${user.uid} - ${user.email}]`}},{merge:true})
const promise = await Promise.all(act1,act2)
return promise
}
catch (err) {
return FS.doc(`globalEvents/${day}`).set({[time]:{time:fTime,source:'Function delUser',description:`Error in function [${err.code}:: ${err.message}]`}},{merge:true})
}
})
For those recognized with Firebase Cloud Functions I have "admin.initializeApp();" in the index.js, and the above in a user.js linked by exports.newUser = users.newUser" & "exports.delUser = users.delUser
Due to the async nature of how I've laid it out (again, the onCreate works perfectly) it will still delete the user's document, but triggers the catch and creates the following document:
12:48:24.981
description
"Error in function [undefined:: object is not iterable (cannot read property Symbol(Symbol.iterator))]"
source
"Function delUser"
time
November 8, 2020 at 7:48:24 AM UTC-5
This is because Promise.all() accepts a single argument, which must be an iterable of Promises, such as an Array.
Passing an array, as follows, await Promise.all([act1, act2]), instead of doing await Promise.all(act1,act2), will solve the problem.
I am just trying a simple get command with Firestore, using this code from Google it doesn't work because it's not waiting for the promise?
Earlier I had put only a snippet of code, this is the entirety of index.js -- I'm using Firestore with Dialogflow to build a Google Assistant app and trying to call a function from the welcome intent that gets a field from Firestore, then writes that field to a string (named question1), and then this string should be spoken by the assistant as part of the ssml response. I've been on this for at least 30 hours already, can't seem to comprehend promises in regards to intents, firestore, etc. I've tried about 10 different solutions, this one works, only it says "undefined" in other variations I have tried it would say undefined several times but after 2-3 passes the get command would be complete and then the variable would be read out. I'm just trying to figure out how to get the get command and variable set before moving onto the SSML response. Can anyone point me in the right direction?
'use strict';
const functions = require('firebase-functions'); //don't forget this one
// Import Admin SDK
var admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
const collectionRef = db.collection('text');
const Firestore = require('#google-cloud/firestore');
var doc;
var question1;
const url = require('url');
const {
dialogflow,
Image,
Permission,
NewSurface,
} = require('actions-on-google');
const {ssml} = require('./util');
const config = functions.config();
const WELCOME_INTENT = 'Default Welcome Intent';
const app = dialogflow({debug: true});
async function dbaccess(rando) {
console.log("dbaseaccess started")
var currentquestion2 = 'question-' + rando.toString();
var cityRef
try { return cityRef = db.collection('text').doc(currentquestion2).get();
console.log("get command completed")
//do stuff
question1 = cityRef.data().n111
} catch(e) {
//error!
}
console.log("one line above return something");
return rando;
}
app.fallback((conv) => {
// intent contains the name of the intent
// you defined in the Intents area of Dialogflow
const intent = conv.intent;
switch (intent) {
case WELCOME_INTENT:
var rando = Math.floor(Math.random() * 3) + 1;
dbaccess(rando);
const ssml =
'<speak>' +
question1 +
'</speak>';
conv.ask(ssml);
break;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have 2 options: you can use async/await or you can use Promise.then() depending on how you want the code to execute.
Async/await:
async function databasetest {
var cityRef;
try{
cityRef = await db.collection('cities').doc('SF');
// do stuff
} catch(e) {
// error!
}
Promise.then():
db.collection('cities').doc('SF').then((cityRef) => {
cityRef.get()
.then(doc => { /* do stuff */ })
.catch(err => { /* error! */ });
});
maybe a little of work around could help you, I'm not sure yet how you are trying to implement it.
function databasetest () {
var cityRef = db.collection('cities').doc('SF');
return cityRef.get()
}
// so you can implement it like
databasetest().then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc.data());
}
})
.catch(err => {
console.log('Error getting document', err);
});
More context would help to understand your use case better :)
I have a simple function to where I get the word count from an url. The script works if I have a low amount of urls. I only limit async 4 at a time. I watch my ram and cpu and it doesn't go near the max on my machine. Let's say after about 70ish urls there is no error. The script just sets there. I have it in a try catch block and it never catches. Any help would be appreciated.
I have tried lodash forEach instead of async and I get the same issue.
const async = require('async')
const wordcount = require('wordcount')
const afterLoad = require('after-load')
const htmlToText = require('html-to-text')
function getWordCount(urls, cb) {
async.eachLimit(urls, 4, function(url, cbe) {
try {
let html = afterLoad(url) // https://www.npmjs.com/package/after-load
let text = htmlToText.fromString(html)
let urlWordCount = wordcount(text) // https://www.npmjs.com/package/wordcount
console.log(url, urlWordCount)
cbe(null)
} catch(err) {
console.log(err)
urlWordCount = 0
console.log(url, urlWordCount, err)
cbe(null)
}
}, function(err) {
console.log("finished getting wordcount", err)
if (err) {
cb(err)
} else {
cb(null)
}
})
}
getWordCount(["https://stackoverflow.com/", "https://caolan.github.io/async/docs.html#eachLimit"], function(err){
console.log(err)
})
I think the issue is in the synchronous implementation of that after-load module, but it's indeed hard to judge unless you get an actual error (you could put some console.logs here and there on every line and see where your code actually gets stuck - or use a debugger for the same purpose).
What I'd propose though is to use proper asynchronous code - I run the example below with a set of 1000 urls and it did not get stuck - with usage of [scramjet] it's also more readable:
const {StringStream} = require('scramjet');
const wordcount = require('wordcount');
const fetch = require('node-fetch');
const htmlToText = require('html-to-text');
const {promisify} = require('util');
StringStream.fromArray(["https://stackoverflow.com/", "https://caolan.github.io/async/docs.html#eachLimit"])
.setOptions({maxParallel: 4})
.parse(async url => ({
url,
response: await fetch(url)
}))
.map(async ({url, response}) => {
const html = await response.text();
const text = htmlToText.fromString();
const count = wordcount(text);
return {
url,
count
};
})
.each(console.log)
;
I actually run this from a file with the URL's by changing the first lines to:
StringStream.from(fs.createReadStream('./urls-list.txt'), 'utf-8')
.lines()
.setOptions({maxParallel: 4})
// and so on.