using promises and async for protobufjs loadcall - javascript

I am trying to figure out the best way to re-write the following code:
var api = function(id, contract) {
var callback = function (error, root) {
if (error)
throw error;
var by = Buffer.from(contract,'base64')
var es = root.lookupType("Contract")
var esMsg = es.decode(by)
var esBytes = es.encode(esMsg).finish()
signature = id.sign(esBytes).toString('base64')
}
return new Promise((resolve, reject) => {
protobuf.load("contract.proto", callback)
})
}
var signContract = async(privateKey, contract) => {
let signature
var id = await crypto.keys.unmarshalPrivateKey(Buffer.from(privateKey, 'base64'))
result = await api(id,contract,signature)
}
function getSessionSignature (hash, time) {
return config.id + ":" + hash + ":" + time
}
module.exports = configure(({ ky }) => {
return async function * signbatch (input, options) {
var contracts = input.Contracts
for (var i = 0 ; i < contracts.length ; i++) {
contracts[i].contract = await signContract(config.PrivKey, contracts[i].contract)
}
//add signed contracts to the searchParams
searchParams.append("arg", JSON.stringify(contracts))
let res
res = await ky.post('storage/upload/signbatch', {
searchParams
}).json()
yield JSON.stringify({})
} else {
yield JSON.stringify({error:"Private key not found"})
}
}
})
My issue is how do I write the sign async code to pass in privateKey and contract variables to api var function and return the signature back to the result variable to be assigned to contracts[i].contract ? Please note that the id.sign(..) function is Promise inside the callback function.

You need to resolve the promise in the api function, the docs suggest you could use the single argument variant here, e.g.
var root = await protobuf.load("contract.proto");
... // (The code you currently by have in 'callback'
return signature;
As the generator is async, yield will emit a Promise which you can (obviously) handle with either .then or await

Related

Node JS function that return https get request final edited data

Hello everybody I have a problem with the Node JS function that I want it to return https get request final edited data, I know there are a lot of solutions for this async problem but I tried them all and still can't figure out what is wrong with my code?
here is my function without any other solutions editing:
function getMovie(apiKey, gen) {
const baseUrl = "https://api.themoviedb.org/3/discover/movie?api_key=" + apiKey + "&language=en-US&include_adult=false&include_video=false&page=1&with_genres=" + gen;
https.get(baseUrl, function (responce) {
console.log(responce.statusCode);
var d = "";
responce.on("data", function (data) {
d += data;
});
responce.on("end", () => {
const finalData = [];
const moviesData = JSON.parse(d);
const result = moviesData.results;
const maxx = result.length;
const rand = Math.floor(Math.random() * maxx);
const title = result[rand].title;
const rDate = result[rand].release_date;
const overview = result[rand].overview;
const imageRoot = result[rand].poster_path;
const movieId = result[rand].id;
const movieRating = result[rand].vote_average;
// here will push those variables to finalData array
// then return it
return finalData;
});
}).on('error', (e) => {
console.error(e);
});
}
and want after this finalData returns:
const finalResult = getMovie(apiKey, genre);
it always returns undefined, How can I fix this? please anyone ca help me with this problem
thanks in advance.
I solved this problem using promises using this code:
const rp = require('request-promise');
function getMovie(url) {
// returns a promise
return rp(url).then(body => {
// make the count be the resolved value of the promise
let responseJSON = JSON.parse(body);
return responseJSON.results.count;
});
}
getMovie(someURL).then(result => {
// use the result in here
console.log(`Got result = ${result}`);
}).catch(err => {
console.log('Got error from getMovie ', err);
});

Promise returns undefined - loop inside Promise

In my application I have a function that returns a promise. What I do inside that function is, waiting for an image in DOM to be available and extract that element to generate base64 data of it.
getCodesOfOneMerchant(merchantDataEntry: MerchantData) {
var codesOfMerchant = [];
return new Promise(async (resolve, reject) => {
for (let index = 0; index < merchantDataEntry.qrPayloadList.length; index++) {
const value = merchantDataEntry.qrPayloadList[index];
const payLoad = value.qrPayload
this.qrvalue = payLoad;
while (!document.querySelector(".qrcode img")) {
await new Promise(r => setTimeout(r, 500));
console.log("waiting for qr");
}
console.log("QR element is available");
const qrEle = document.getElementById('qrcode');
let imgBase64Data = this.getBase64Image(qrEle.firstChild.firstChild);
console.log('Base64 = ' + imgBase64Data);
var qrName = merchantDataEntry.serviceName + "-" + value.branch + "-" + value.mobile;
let userQr: UserQr = new UserQr();
userQr.name = qrName;
userQr.qr = imgBase64Data;
codesOfMerchant.push(userQr);
console.log('1')
if (index == merchantDataEntry.qrPayloadList.length - 1) {
resolve();
}
}
console.log('2')
console.log('Returning data = ' + JSON.stringify(codesOfMerchant));
return codesOfMerchant;
});
}
Following is the function which calls above one.
async downloadQrCodesOfAllSelectedMerchants() {
var qrCodesForAllMerchants = [];
const filteredData = this.merchantDataList.filter(entry => entry.qrSelected);
const promises = filteredData.map(async (value) => {
const qrCodesOfMerchant = await this.getCodesOfOneMerchant(value);
return qrCodesOfMerchant;
});
const qrCodesOfAll = await Promise.all(promises);
console.log('HELLO');
console.log(qrCodesOfAll); // this prints undefined
console.log('DONE')
}
Even though I have returned the promise inside the first method, the calling function still receives undefined. I cannot understand what is wrong there.
As you can see, I just log the data to return to the console inside the second function just before returning. Data is there.
Can someone please help me here. Thank You..!
You'll want to remove the return new Promise(async (resolve, reject) => { line and just make getCodesOfOneMerchant itself async:
async getCodesOfOneMerchant(merchantDataEntry: MerchantData) { /*
^^^^^ */
const codesOfMerchant = [];
for (const value of merchantDataEntry.qrPayloadList) {
this.qrvalue = value.qrPayload;
while (!document.querySelector(".qrcode img")) {
await new Promise(r => setTimeout(r, 500));
console.log("waiting for qr");
}
console.log("QR element is available");
const qrEle = document.getElementById('qrcode');
let imgBase64Data = this.getBase64Image(qrEle.firstChild.firstChild);
console.log('Base64 = ' + imgBase64Data);
const userQr: UserQr = new UserQr();
userQr.name = merchantDataEntry.serviceName + "-" + value.branch + "-" + value.mobile;
userQr.qr = imgBase64Data;
codesOfMerchant.push(userQr);
}
return codesOfMerchant;
}
In the callee function in the below code
const promises = filteredData.map(async (value) => {
const qrCodesOfMerchant = await this.getCodesOfOneMerchant(value);
return qrCodesOfMerchant;
});
you are already awaiting for the response of the method getCodesOfOneMerchant, which will resolve the promise there itself.
Instead, you just need to dump all the promises in the promises array and await all of them once using Promise.all(promises)
const promises = filteredData.map(value => this.getCodesOfOneMerchant(value))
const qrCodesOfAll = await Promise.all(promises);
This will give qrCodesOfAll as an array of resolved promises
Also, the executor function is returning a promise but the promise is never resolved. The returned values from the promise i.e codesOfMerchant will never be received by the callee. You will need to resolve that promise by using
resolve(codesOfMerchant)
which will now return the value of codesOfMerchant to the callee

Pagination in Zapier

I am trying following code to get all records from a paginated API in Zapier.
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
var lastCursor = null;
var output = null;
const getContent = async function (cursor) {
let actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
var apiResults = await fetch(actualUrl)
.then(resp => {
return resp.json;
});
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireContentList(results.metadata.cursor));
} else {
return results;
}
};
(async() => {
const entireList = await getEntireContentList();
console.log(entireList);
output = entireList;
callback(null, entireList);
})();
I get error as
You did not define output! Try output = {id: 1, hello: await Promise.resolve("world")};
How can I fix this?
Your problem is that though you're awaiting in that function, the top-level carries on and execution ends before your code has had a chance to run.
The good news is, Zapier wraps your code in an async function already, so you can use await at the top level (per these docs).
Try this instead:
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
let lastCursor = null;
// var output = null; // zapier does this for you already
const getContent = async function (cursor) {
const actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
const rawResponse = await fetch(actualUrl)
return resp.json() // async function, you had it as a property
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireUserList(results.metadata.cursor)); // should this be named getEntireContentList?
} else {
return results;
}
};
return {
results: await getEntireContentList()
}
I noticed this is a recursive approach. That's fine, but remember that you've got limited execution time. You also might hit memory limits (depending on how many objects you're returning), so keep an eye on that.

Node.js module.exports a function with input

I have a little encryption file that adds a encrypted random number after some inputs:
const crypto = require("crypto");
module.exports = function (x, y) {
crypto.randomBytes(5, async function(err, data) {
var addition = await data.toString("hex");
return (x + y + addition);
})
}
The returned value is undefined when I export it to another file and console.log it
const encryption = require('./encryption')
console.log(encryption("1", "2"));
What did I do wrong here?
I also have tried
module.exports = function (x, y) {
var addition;
crypto.randomBytes(5, function(err, data) {
addition = data.toString("hex");
})
return (x + y + addition);
}
No luck.
Thanks in advance.
You can use promises to handle the async functions
Try Changing your module.exports to return a promise function
const crypto = require("crypto");
module.exports = function (x, y) {
return new Promise(function (resolve, reject) {
var addition;
crypto.randomBytes(5, function (err, data) {
addition = data.toString("hex");
if (!addition) reject("Error occured");
resolve(x + y + addition);
})
});
};
You can then call the promise function using the promise chain
let e = require("./encryption.js");
e(1, 2).then((res) => {
console.log(res);
}).catch((e) => console.log(e));
Suggest you to read Promise documentation
For node version > 8, you can use simple async/await without promise chain.You have to wrap your api inside a promise using utils.promisify (added in node 8) and your function should use the keyword async.Errors can be handled using try catch
const util = require('util');
const crypto = require("crypto");
const rand = util.promisify(crypto.randomBytes);
async function getRand(x, y){
try{
let result = await rand(5);
console.log(x + y + result);
}
catch(ex){
console.log(ex);
}
}
console.log(getRand(2,3));

Why is my code not waiting for the completion of the function?

I am trying to read some data from a file and store it in a database.
This is part of a larger transaction and I need the returned ids for further steps.
async parseHeaders(mysqlCon, ghID, csv) {
var self = this;
var hIDs = [];
var skip = true;
var idx = 0;
console.log("Parsing headers");
return new Promise(async function(resolve, reject) {
try {
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(csv)
});
await lineReader.on('close', async function () {
console.log("done: ", JSON.stringify(hIDs));
resolve(hIDs);
});
await lineReader.on('line', async function (line) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx++] = await self.getParamID(mysqlCon, ghID, v, c, data);//, function(hID,sidx) { //add data in case the parameter is not in DB, yet.
}
});
} catch(e) {
console.log(JSON.stringify(e));
reject("some error occured: " + e);
}
});
}
async getParamID(mysqlCon,ghID,variable,category,data) {
return new Promise(function(resolve, reject) {
var sql = "SELECT ID FROM Parameter WHERE GreenHouseID="+ghID+" AND Variable = '" + variable + "' AND Category='" + category + "'";
mysqlCon.query(sql, function (err, result, fields) {
if(result.length === 0 || err) { //apparently not in DB, yet ... add it (Acronym and Machine need to be set manually).
sql = "INSERT INTO Parameter (GreenHouseID,Variable,Category,Control) VALUES ("+ghID+",'"+variable+"','"+category+"','"+data[3]+"')";
mysqlCon.query(sql, function (err, result) {
if(err) {
console.log(result,err,this.sql);
reject(err);
} else {
console.log("Inserting ",variable," into DB: ",JSON.stringify(result));
resolve(result.insertId); //added, return generated ID.
}
});
} else {
resolve(result[0].ID); //found in DB .. return ID.
}
});
});
}
The functions above are in the base class and called by the following code:
let headerIDs = await self.parseHeaders(mysqlCon, ghID, filePath);
console.log("headers:",JSON.stringify(headerIDs));
The sequence of events is that everything in parseHeaders completes except for the call to self.getParamID and control returns to the calling function which prints an empty array for headerIDs.
The console.log statements in self.getParamID are then printed afterward.
What am I missing?
Thank you
As you want to execute an asynchronous action for every line we could define a handler to do right that:
const once = (target, evt) => new Promise(res => target.on(evt, res));
function mapLines(reader, action) {
const results = [];
let index = 0;
reader.on("line", line => results.push(action(line, index++)));
return once(reader, "close").then(() => Promise.all(results));
}
So now you can solve that easily:
let skip = false;
const hIDs = [];
await mapLines(lineReader, async function (line, idx) {
line = line.replace(/\"/g, '');
if (line.startsWith("Variable")) { //Variable,Statistics,Category,Control
console.log("found variables");
skip = false; //Ignore all data and skip to the parameter description.
return; //Skip also the header line.
}
if (!skip) {
var data = line.split(",");
if (data.length < 2) { //Variable section done return results.
console.log("Found sub?",line);
return lineReader.close();
}
var v = data[0];
var bidx = data[0].indexOf(" [");
if (bidx > 0)
v = data[0].substring(0, bidx); //[] are disturbing mysql (E.g.; Air temperature [�C])
var c = data[2];
hIDs[idx] = await self.getParamID(mysqlCon, ghID, v, c, data);
}
});

Categories

Resources