Node.js module.exports a function with input - javascript

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));

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

using promises and async for protobufjs loadcall

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

How to correctly implement a .then promise [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
How do I convert an existing callback API to promises?
(24 answers)
Closed 5 years ago.
How could I implement a .then promise, so once this function runs I have something inside of the array?
I can console.log the results into the function and I believe it returns the results correctly, however the res.json results will show an empty array. Which I assume is because it loads quicker than the function finishes.
const {grabArticles} = require('../controller/update.js');
// variables
const router = express.Router();
router.get('/new', (err, res) => {
const results = [];
const test = grabArticles(results)
test.then((results) => {
res.json(results);
})
});
//different file
const request = require('request');
const cheerio = require('cheerio');
grabArticles = (results) => {
// const results = [];
request("https://fivethirtyeight.com/", function(error, response, html) {
const $ = cheerio.load(html);
for (x=1; x<4; x++) {
// i is the current loop number, element=this is the current data requested
$('#home-feature-' + x.toString()).each((i, element) => {
const topic = $(element).children('.post-info').children('.topic').text().trim();
const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
// console.log('topic: ' + topic + '\n' + 'title: ' + title);
const newArticle = {
topic: topic,
title: title
};
results.push(newArticle);
})
}
console.log('inside update.js' + results);
});
return results;
}
You need to return a Promise, which then resolves the results. The value of results will then be passed to your then callback as the first parameter.
Untested but it will look something like this:
//different file
const request = require('request');
const cheerio = require('cheerio');
grabArticles = (results) => {
// const results = [];
return new Promise(function(resolve) {
request("https://fivethirtyeight.com/", function(error, response, html) {
const $ = cheerio.load(html);
for (x = 1; x < 4; x++) {
// i is the current loop number, element=this is the current data requested
$('#home-feature-' + x.toString()).each((i, element) => {
const topic = $(element).children('.post-info').children('.topic').text().trim();
const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
// console.log('topic: ' + topic + '\n' + 'title: ' + title);
const newArticle = {
topic: topic,
title: title
};
results.push(newArticle);
})
}
console.log('inside update.js' + results);
//////////////////////////
/// Resolve the promise here
/// the then() will get triggered
//////////////////////////
resolve(results);
});
});
}
A very simplified version would look like this:
// This function returns a Promise
function doSomethingAysnc(){
return new Promise(function(resolve){
request('/my/url', function(data){
// When we are staisfied with ending the promise
// We resolve it so the calling function can then
// handle the rest
return resolve(data);
});
});
}
// Here we will call our async function
// Once the promise resolves
// We get our data back for further usage
doSomethingAysnc().then(function(data){
// We can the access the data here
console.log(data);
});
Rewrite your grabArticles using Promise like this.
grabArticles = (results) => {
return new Promise((resolve, reject) => {
request("https://fivethirtyeight.com/", function(error, response, html) {
const $ = cheerio.load(html);
for (x=1; x<4; x++) {
// i is the current loop number, element=this is the current data requested
$('#home-feature-' + x.toString()).each((i, element) => {
const topic = $(element).children('.post-info').children('.topic').text().trim();
const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
// console.log('topic: ' + topic + '\n' + 'title: ' + title);
const newArticle = {
topic: topic,
title: title
};
results.push(newArticle);
})
}
console.log('inside update.js' + results);
// return result using resolve, otherwise using reject(error) to reflect something wrong
resolve(results);
});
});
}

Nice way to do recursion with ES6 promises?

Here's what I've got:
function nextAvailableFilename(path) {
return new Promise(function (resolve, reject) {
FileSystem.exists(path, function (exists) {
if (!exists) return resolve(path);
var ext = Path.extname(path);
var pathWithoutExt = path.slice(0, -ext.length);
var match = /\d+$/.exec(pathWithoutExt);
var number = 1;
if (match) {
number = parseInt(match[0]);
pathWithoutExt = pathWithoutExt.slice(0, -match[0].length);
}
++number;
nextAvailableFilename(pathWithoutExt + number + ext).then(function () {
return resolve.apply(undefined, arguments);
}, function () {
return reject.apply(undefined, arguments);
});
});
});
}
But I don't like that block at the end -- isn't there a way to 'replace' the current promise with the next one in the stack rather than having one promise resolve the next like I've done here?
Here's a version that uses promise chaining and file create to avoid the race condition. I used the bluebird promise library so I can use promises with the fs library just to simplify the code and error handling:
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var path = require('path');
// Creates next available xxx/yyy/foo4.txt numeric sequenced file that does
// not yet exist. Returns the new filename in the promise
// Calling this function will create a new empty file.
function nextAvailableFilename(filename) {
return fs.openAsync(filename, "wx+").then(function(fd) {
return fs.closeAsync(fd).then(function() {
return filename;
});
}, function(err) {
if (err.code !== 'EEXIST') {
// unexpected file system error
// to avoid possible looping forever, we must bail
// and cause rejected promise to be returned
throw err;
}
// Previous file exists so reate a new filename
// xxx/yyy/foo4.txt becomes xxx/yyy/foo5.txt
var ext = path.extname(filename);
var filenameWithoutExt = filename.slice(0, -ext.length);
var number = 0;
var match = filenameWithoutExt.match(/\d+$/);
if (match) {
number = parseInt(match[0], 10);
filenameWithoutExt = filenameWithoutExt.slice(0, -match[0].length);
}
++number;
// call this function again, returning the promise
// which will cause it to chain onto previous promise
return nextAvailableFilename(filenameWithoutExt + number + ext);
});
}
I came up with a solution too that doesn't depend on bluebird.promisify. It should handle the case where file creation fails for a reason other than it already exists.
function createFile(path) {
return new Promise(function (resolve, reject) {
FileSystem.open(path, 'wx', function (err, fd) {
if (err) return reject(err);
FileSystem.close(fd, function (err) {
if (err) return reject(err);
return resolve();
});
});
});
}
// todo: make more efficient by multiplying numbers by 2 or something like http://stackoverflow.com/a/1078898/65387
function nextFile(path) {
return createFile(path).then(function () {
return path;
}, function (err) {
if (err.code !== 'EEXIST') throw err; // error other than "file exists"
var ext = Path.extname(path);
var pathWithoutExt = path.slice(0, -ext.length);
var match = /\d+$/.exec(pathWithoutExt);
var number = 2;
if (match) {
number = parseInt(match[0]) + 1;
pathWithoutExt = pathWithoutExt.slice(0, -match[0].length);
}
return nextFile(pathWithoutExt + number + ext);
});
}

Categories

Resources