I am implementing a chatbot using nodejs and messages are not sending in order that's why I changed sendMessage() function and created promise but when I call sendMessage function using await keyword why this is making for loop very slow?
I also want to insert data into sql. Please help me
sendMessage Function
let sendMessage = (sender_psid, response) => {
return new Promise ((resolve,reject) => {
// Construct the message body
try{
let request_body = {
"recipient": {
"id": sender_psid
},
"message": {
"text": response
}
}
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v9.0/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
// console.log(body)
if (!err) {
resolve('Message Sent');
console.log('message sent!')
}
else {
reject("Unable to send Message "+err)
console.error("Unable to send message:" + err);
}
});
} catch (e){
reject (e);
}
});
};
handleMessage Function
let handleMessage = async(sender_psid, received_message) => {
for (let i = 0; i < selectedMembers.length; i++) {
let memberDetail = selectedMembers[i].split(",");
memberID = memberDetail[0];
memberName = memberDetail[1];
console.log(memberID);
// Query to insert values in Info table
query = "INSERT INTO info (task_id,task_desc,member_id,member_name,assigner_id,assigner_name) VALUES (?,?,?,?,?,?)";
values = [taskID, taskDescription, memberID, memberName, assignerID, assignerName];
// Query Execution
conn.query(query, values, function (err, result) {
if (err) throw err;
console.log("Member ID " + memberID + "Member Name " + memberName + "Inseted into info table");
});
await sendMessage(memberID, assignerName + " has assigned you a task.");
console.log(taskDescription);
await sendMessage(memberID, taskDescription);
}
sendMessage(assignerID, "Task Assigned Successfully to " + selectedMembers.length + " members.");
}
}
Related
I have a sqlite3 database request in my main.js, that is triggered by button click in renderer.js.
The request reaches my main.js. However, I cannot manage to await the results from the database. The issue occurs already in main.js, so I'm stuck even before anything is passed back to the renderer.js.
I hope someone can tell me what I am missing.
Here is my code:
renderer.js
$(document).on('click','#mybtn',function(e){
let query = "SELECT id, name FROM table1"
// send (here is the issue)
window.api.send("db-query", query)
// (next step: receive, might be wrong but not yet my problem)
window.api.receive(channel="receive-db-data", (data) => {
console.log(data);
});
});
main.js
ipcMain.on(channel='db-query', async (e, query) => {
console.log('query received: ' + query);
let data = await db_request(query).then(
function(value) {
console.log('value: ' + value);
return value;
},
function(error) {
console.log('error fetching data from db on query:' + query);
}
)
console.log("response ready: " + data); //returns undefined if 'return value' is used (otherwise nothing)
// to send back to renderer.js later
e.sender.send("db-data", data)
})
let db_request = async (query) => {
let data = []
var sqlite3 = require('sqlite3').verbose();
var dbPath = require('path').resolve(__dirname, '../../Fin.db')
var db = new sqlite3.Database(dbPath)
db.serialize(function(){
db.each(query, function(err, row) {
console.log(row)
data.push({"id": row.id, "name": row.name})
});
});
db.close();
console.log('db_request:' + data)
return data
}
And this is how my terminal looks like:
query received: SELECT id, type, name FROM table1
db_request:
value:
response ready: undefined
{ id: 1, name: 'a' }
{ id: 2, name: 'b' }
{ id: 3, name: 'c' }
You have to convert db_request result to a Promise, and the promise will be resolved when all rows are pushed to the data. When you use the await keyword, there is no need to handle a promise with .then chain.
main.js will look like this:
const sqlite3 = require('sqlite3').verbose();
const dbPath = require('path').resolve(__dirname, '../../Fin.db')
ipcMain.on(channel='db-query', async (e, query) => {
console.log('query received: ' + query)
try {
const data = await db_request(query); // remove .then
console.log('value: ' + data)
// to send back to renderer.js later
e.sender.send("db-data", data)
} catch (error) {
console.log('error fetching data from db on query:' + query);
e.sender.send("db-data", []) // send empty data or error ???
}
})
let db_request = (query) => {
const db = new sqlite3.Database(dbPath)
return new Promise((resolve, reject) => { // return a promise
// I think you dont need serialize for this case
const data = []
db.each(query, (err, row) => {
console.log(err, row)
if (!err) {
data.push({"id": row.id, "name": row.name})
}
}, (error) => {
if (error) {
reject(error)
} else {
resolve(data)
}
});
})
}
i want to fetch data from api and execute for loop to store all response data in mysql database.then again fetch data from api with different request parameter but it does not wait to complete for loop and store data i have tried async/await but noting works
app.get("/api/garudaTx", (req, res) => {
let sql = "SELECT * FROM table_name ORDER BY id ";
let query = conn.query(sql, (err, results) => {
(async function () {
for (let i = 0; i < results.length; i++) {
const element = results[i];
console.log(element.userAddress);
console.log(element.id);
try {
let response = await axios.get(
`https://api.bscscan.com/apimodule=account&action=txlist&address=${element.userAddress}&startblock=1&endblock={blockNo}&sort=asc&apikey=`
);
let last = await (async function () {
console.log(response);
if (response.status != 200 || response.data.result.length == 0) {
let code = response.status.toString();
fs.appendFile("responseError.txt", code + " ", (err) => {
if (err) throw err;
console.log("The lyrics were updated!");
});
fs.appendFile(
"responseError.txt",
element.userAddress + " ",
(err) => {
if (err) throw err;
console.log("The lyrics were updated!");
}
);
}
let body = response.data;
console.log(response.data.result.length);
const promises = [];
for (var index = 0; index < response.data.result.length; index++) {
let data = {
blockNumber: body.result[index].blockNumber,
timeStamp: body.result[index].timeStamp,
hash: body.result[index].hash,
nonce: body.result[index].nonce,
blockHash: body.result[index].blockHash,
from_address: body.result[index].from,
contractAddress: body.result[index].contractAddress,
to_address: body.result[index].to,
value: body.result[index].value,
transactionIndex: body.result[index].transactionIndex,
gas: body.result[index].gas,
gasPrice: body.result[index].gasPrice,
gasUsed: body.result[index].gasUsed,
cumulativeGasUsed: body.result[index].cumulativeGasUsed,
confirmations: body.result[index].confirmations,
};
promises.push(
new Promise((resolve) => {
let sql = "INSERT INTO table_name SET ?";
resolve(
conn.query(sql, data, (err, results) => {
if (err) throw err;
console.log(
JSON.stringify({
status: 200,
error: null,
response: results,
})
);
})
);
})
);
}
await Promise.all(promises);
})();
} catch (err) {
console.log(err);
}
}
})();
});
res.send(JSON.stringify({ status: 200, error: null, response: "success" }));
});
i am executing a for to fetch user details from database then i execute api for each user and saved response data with loop but next api is hitting before saving all data in database it does not wait to complete nested for loop
have a strange thing happening running a Google cloud function. The function starts and logs the user id and job id as expected. Then it calls firestore db and basically sits there for 1 minute, sometimes 2 before it executes the first call... It was even timing out on 240 seconds.
const AWS = require('aws-sdk');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.run = functions.https.onCall((data, context) => {
var id = data.id;
var userid = data.uid;
var retry = data.retry;
var project;
var db = admin.firestore();
var storage = admin.storage();
console.log("Starting Collect");
console.log("UID: " + userid);
console.log("id ID: " + id);
// Times out on this call
db.collection("users").doc(userid).collection("ids").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
createexport();
}).catch(function(err) {
console.log(err);
error('Loading DB Error, ' + err, false);
});
function createexport() {
db.collection("exports").doc(id).set({
status: 'Collecting',
stage: 'Export Checker',
percent: 0,
id: id,
}).then(function() {
console.log("Creating Export");
setdb();
}).catch(function(err) {
error("Error creating export in database :" + err, true)
});
}
function setdb() {
db.collection("users").doc(userid).collection("ids").doc(id).update({
status: 'Analyzing Files',
stage: 'Collecting'
}).then(function() {
getaudio();
}).catch(function(err) {
error("Error updating users id in database :" + err, true)
});
}
function getaudio() {
const from = userid + '/projects/' + project.originalproject.id + '/audio.' + project.originalproject.extension;
const to = userid + '/' + id + '/audio.' + project.originalproject.extension;
storage.bucket('---------').file(from).copy(storage.bucket('---------').file(to)).then(function() {
console.log("Collecting files");
copy2();
}).catch(function(err) {
error('Collecting Audio Error, ' + err, true);
});
}
function copy2() {
const from = userid + '/projects/' + project.originalproject.id + '/overlay.png';
const to = userid + '/' + id + '/overlay.png';
storage.bucket('--------.appspot.com').file(from).copy(storage.bucket('---------').file(to)).then(function() {
updateexport();
}).catch(function(err) {
error('Collecting Overlay Error, ' + err, true);
});
}
function updateexport() {
db.collection("exports").doc(id).update({ status: "Waiting" }).then(function() {
console.log("All files collected");
return { status: 'Success' };
}).catch(function(err) {
error("Error creating export entry in database :" + err, true)
});
}
function error(evt, evt2) {
AWS.config.update({ region: "us-east-1" });
var html;
var sub = 'Error with id ' + id;
console.log(evt);
if (evt2) {
db.collection('users').doc(userid).collection('ids').doc(id).update({
status: 'Error'
}).catch(function(err) {
console.log(err);
});
db.collection("exports").doc(id).update({
status: 'Error',
stage: 'Collecting',
error: evt,
}).catch(function(err) {
console.log(err);
});
html = `
Username: ${project.username} <br>
UserID: ${userid} <br>
Email: ${project.email} <br>
id: ${id}
`
} else {
html = `id: ${id}<br>
UserID: ${userid} <br>
Message: Error logged was: ${evt}
`
}
var params = {
Destination: {
ToAddresses: [
'errors#mail.com'
]
},
Message: {
Body: {
Html: {
Charset: "UTF-8",
Data: html
},
},
Subject: {
Charset: 'UTF-8',
Data: sub
}
},
Source: 'errors#mail.com',
ReplyToAddresses: [
project.email
],
};
var sendPromise = new AWS.SES({
apiVersion: "2010-12-01",
"accessKeyId": "-----------",
"secretAccessKey": "------------------------",
"region": "--------",
}).sendEmail(params).promise();
sendPromise.then(function(data) {
return { data: data };
}).catch(function(err) {
return { err: err };
});
}
});
Seems to me to be way too long for a database call of only a few kb. I will attach the cloud log to show time difference. After this initial slump it then performs as expected.
Cloud log image
Anyone got any ideas as to why this could be happening? Many thanks...
Your function is appearing to hang because it isn't handling promises correctly. Also, it doesn't appear to be sending a specific response to the client app. The main point of callable functions is to send a response.
I suggest reviewing the documentation, where you will learn that callable functions are required to return a promise that resolves with an object to send to the client app, after all the async work is complete.
Minimally, it will take a form like this:
return db.collection("users").doc(userid).collection("files").doc(id).get().then(function(doc) {
console.log("Loaded DB");
project = doc.data();
return { "data": "to send to the client" };
}
Note that the promise chain is being returned, and the promise itself resolves to an object to send to the client.
I live in the PHP world but I am attempting to build out a REST Api using Node.
I have been stuck all day of trying to return an array of results from a for loop. Basically I am passing an array of field_name:field_value. I want to push the result from the update into an array to return. I can get it to log in the console but no further.
Here is a sample post json data
{
"first_name":"Jeff",
"phone":"4855555555"
}
Here is the function and loop
function UpdateKey(user_id, key, value, cb) {
connection.query('UPDATE users SET ' + key + ' = ? WHERE id = ? LIMIT 1', [value, user_id], function(err, results) {
if (err) {
callback = key + " update failed.";
} else {
callback = key + " was updated.";
}
cb(callback);
});
}
for (myKey in post_data) {
UpdateKey(user_id, myKey, post_data[myKey], function(id) {
console.log(id);
});
}
res.send(JSON.stringify({ "status": 200, "error": "", "response": my_results_here }));
I have been researching async but not sure the best route here. Any help would be great!
You could collect all results in an array and send that when the arrays size equals the keys size:
const keys = Object.keys(post_data);
const response = [];
for(const myKey of keys) {
UpdateKey(user_id, myKey, post_data[myKey], function(id) {
response.push(id);
if(keys.length === response.length) {
res.send(JSON.stringify({
status: 200,
error: "",
response
}));
}
});
}
The solution You want:
const updateUserField = (userId, field, value) => {
return Promise((resolve) => {
const query = 'UPDATE users SET ' + field + ' = ? WHERE id = ?';
const data = [value, userId];
connection.query(query, data, (error) => {
if (error) return resolve(field + ' update failed');
resolve(field + ' was updated');
});
});
};
router.post('/user/:id', async (req, res) => {
const userId = req.params.id;
const data = req.body;
const response = [];
for (const field in data) {
response.push(
await updateUserField(userId, field, data[field])
);
}
res.status(200).send({
response
});
});
or in parallel:
router.post('/user/:id', async (req, res) => {
const userId = req.params.id;
const data = req.body;
const response = await Promise.all(
Object
.keys(data)
.map(field => updateUserField(userId, field, data[field]))
);
res.status(200).send({
response
});
});
Correct solution
As I understand You want to get post data and update record in users table.
So why not just do it in one query?
Try this way:
const updateUser = (userId, data) => {
return Promise((resolve, reject) => {
const query = 'UPDATE users SET ? WHERE id = ?';
connection.query(query, [data, userId], (error) => {
if (error) return reject(error);
resolve();
});
});
};
router.post('/user/:id', async (req, res) => {
try {
const userId = req.params.id;
const data = req.body;
await updateUser(userId, data);
res.status(200).send({
message: 'User account successfully updated'
})
}
catch (error) {
console.error(error);
res.status(500).send({
message: 'Failed update user account'
});
}
});
But better think about using ORM i.e. Sequelize for security, validation and etc features that eases dev's life.
When I call sendText, the promise returned by callSendAPI returns as undefined, logged on the console like so:
Promise return from callSendAPI undefined
I have read up on promises and checked a lot of stack overflow questions, but I haven't been able to grasp which part of my code is wrong. The message sends fine, but the undefined return has the effect of causing await in higher functions to not work correctly.
What am I doing incorrectly in constructing my promise which is causing it to return as undefined?
var request = require('request-promise-native');
module.exports = {
callSendAPI : function (sender_psid,response) {
return new Promise(async function(resolve,reject) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
// Send the HTTP request to the Messenger Platform
try {
var a = await request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
})
} catch(e) {
console.error("Unable to send message:" + e);
return reject(e);
}
console.log('message sent!')
resolve();
});
},
sendText : function(sender_psid,text) {
return new Promise(async function(resolve,reject) {
var response = { "text": `${text}` };
try {
var a = await module.exports.callSendAPI(sender_psid,response);
console.log("Promise return from callSendAPI " + a);
} catch(e) {
console.error(e);
return reject();
}
console.log("message sent--------------------");
resolve();
});
}
}
Here's a re-write that simplifies your implementation and correctly resolves the promise with a value:
var request = require('request-promise-native');
module.exports = {
async callSendAPI (sender_psid, response) {
// Construct the message body
let request_body = {
recipient: {
id: sender_psid
},
message: response
};
// Send the HTTP request to the Messenger Platform
try {
var a = await request({
uri: "https://graph.facebook.com/v2.6/me/messages",
qs: { access_token: PAGE_ACCESS_TOKEN },
method: "POST",
json: request_body
});
console.log('message sent!');
return a;
} catch(e) {
console.error("Unable to send message:" + e);
throw e;
}
},
async sendText (sender_psid, text) {
var response = { text: String(text) };
try {
var a = await module.exports.callSendAPI(sender_psid,response);
console.log("Promise return from callSendAPI " + a);
console.log("message sent--------------------");
return a;
} catch(e) {
console.error(e);
throw e;
}
}
};
As suggested by #jfriend00 you can simply return the promise generated by request() rather than wrapping it in a try-catch, optionally logging each scenario by chaining a .then() like this:
var request = require('request-promise-native');
module.exports = {
async callSendAPI (sender_psid, response) {
// Construct the message body
let request_body = {
recipient: {
id: sender_psid
},
message: response
};
// Send the HTTP request to the Messenger Platform
return request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json: request_body
}).then(value => {
console.log('message sent!');
return value;
}, error => {
console.error('Unable to send message:', error);
throw error;
});
},
async sendText (sender_psid, text) {
var response = { text: String(text) };
return module.exports.callSendAPI(sender_psid, response).then(value => {
console.log('Promise return from callSendAPI', value);
console.log('message sent--------------------');
return value;
}, error => {
console.error(error);
throw error;
});
}
};