Applying asynchronous functions to facebook chatbot messages in specific order - node.js

I'm doing a chatbot for facebook and I have a problem with the order of sending messages
I send in the chat:
-Hi
The bot responds in the console:
-Hello!
-How can I help you?
but in the chat responds like this:
-How can I help you?
-Hello!
I tried to apply async and await, but it didn't work.
let postWebhook = (req, res) => {
// Parse the request body from the POST
let body = req.body;
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(function (entry) {
// Gets the body of the webhook event
let webhook_event = entry.messaging[0];
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
// Check if the event is a message or postback and
// pass the event to the appropriate handler function
if (webhook_event.message) {
handleMessage(sender_psid, webhook_event.message);
}
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
}};
let handleMessage = async (sender_psid, received_message) => {
let response;
if (received_message.text) {
addUrl(`url/facebook?mensage=${received_message.text}&usuario=${user}&session=${sender_psid}&origem=${chanel}`)
.then(res => res.json())
.then(async json => {
for (var i = 0; i < json.length; i++) {
console.log(json[i].text || json[i].title)
response = {json[i].text || json [i] tittle}
await callSendAPI(sender_psid, response) //function to verify user and send message
}
})
await callSendAPI(sender_psid, response);
}
};
How can I ensure the correct order?

Well you can simplify this way:
const callSendAPII = (sender_psid, response) => {
return new Promise((resolve, reject) => {
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
request({
uri: 'https://graph.facebook.com/v12.0/me/messages',
qs: {"access_token": MY_IG_PAGE_TOKEN},
method: 'POST',
json: request_body,
}, (error, response, body) => {
if (error) {
reject(error);
} else {
resolve(response);
}
});
})
now just apply await in the calling function:
await callSendAPII(sender_psid, response)

Related

weather app: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am trying to build a weather app using node that takes
{
"cities": [
"toronto",
"mumbai",
"london"
]
}
as input and returns
{
"weather": {
"toronto": "24C",
"mumbai": "34C",
"london": "14C"
}
}
this as output
app.post('/getWeather',(req,res)=>{
const city = req.body.city;
city.map(city=>{
const url=`http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}`;
request(url, function(err, response, body) {
// On return, check the json data fetched
if (err) {
res.render('index', { weather: null, error: 'Error, please try again' });
} else {
let weather = JSON.parse(body);
console.log(weather);
Since the question does not have all of the code, I cannot give a definite answer, but I assume that the code either tries to sent response for the each city separately and/or does not wait for all the API calls to finish.
To fix the issue, async/await needs to be used (since the response depends on several API calls), and response must be sent after its completely assembled.
An example based on the given code:
app.post("/getWeather", async (req, res) => {
const cities = req.body.cities;
const reqs = cities.map((city) => {
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}`;
return new Promise((resolve, reject) => {
request(url, function (err, response, body) {
if (err) {
reject(err);
} else {
let weather = JSON.parse(body);
resolve(weather);
}
});
});
});
const responses = await Promise.all(reqs);
const result = {};
for (const response of responses) {
if (response.ok) {
result[response.city] = response.temp;
}
}
res.json(result);
});

I try get text from hosted text file into skill handler, but when I test skill show an error "SpeechletResponse was null"

I develop Alexa Skill in Alexa developer, I begin to learn about this, my skill try get text from a promise connects to hosted text file, the request is succesfully. But skills shows an error.
I need help to resolve this error on alexa skill. Share my code
This is my handler
const InformacionIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'InformacionIntent';
},
async handle(handlerInput) {
const response = await
reader.readFile('res.cloudinary.com','/fdgdfg/raw/upload/v1656032273/fofo_mbbjr0.txt');
console.log(response);
return handlerInput.responseBuilder
.speak("Okay. Here is what I got back from my request. " + response)
.reprompt("What would you like?")
.getResponse();
},
};
the async function into handler is:
const https = require('https');
var text = '';
module.exports = {
readFile: (host,path) => {
return new Promise(((resolve, reject) => {
var options = {
host: host,
path: path,
method: 'GET',
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
response.on('data', (chunk) => {
text += chunk;
});
response.on('end', () => {
//let lr = new LineByLineReader(response);
// lr.on('error', function (err) {
return text;
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
};
And this is error response:
{
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.13227b68-28b0-49d1-b29e-3ac7324093df",
"timestamp": "2022-06-24T06:22:07Z",
"locale": "es-MX",
"reason": "ERROR",
"error": {
"type": "INVALID_RESPONSE",
"message": "SpeechletResponse was null"
}
}
The async function doesn't trigger the error, because log show response.
Couple of things to check.
Make sure that handler is getting invoked. A sample request JSON would help. Also perhaps add a console.log('InformacionIntentHandler') line in your handle function so you can verify in your logs.
How long is it taking for the async operation to complete? You only have a few (~8) seconds before the request to your skill times out. If using a Lambda function, you may also need to increase the timeout configured there.

Node js firebase notification return the json response in a function format

So I have the following notification function,
async function sendNotification(registrationToken, title, body) {
const message = {
to: registrationToken,
notification: {
title: title,
body: body
}
};
await fcm.send(message, (err, response) => {
if (err) {
return err;
}
else {
return response;
}
});
};
When I call the function like this in the api
let result = await sendNotification('','','');
result is always undefined. How do I solve this issue?

Node.js Facebook messenger chatbot - sender PSID is not defined

i developed a chatbot with nodejs and deployed it to heroku. but the webhook is not working properly since its gets an error saying sender PSID is not defined. what should I do? I need help from experts.. I haven't used wit.ai in my project but only node.js. and here i haven't posted post backs handlings as its too long!
my controllers.js as below.. (messages are in Sinhalese language)
import dotenv from 'dotenv';
dotenv.config();
import request from 'request';
const PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN;
const MY_VERIFY_TOKEN = process.env.MY_VERIFY_TOKEN;
let test = (req, res) => {
return res.send("hello again")
}
let getWebhook = (req, res) => {
// Your verify token. Should be a random string.
let VERIFY_TOKEN = MY_VERIFY_TOKEN
// Parse the query params
let mode = req.query['hub.mode'];
let token = req.query['hub.verify_token'];
let challenge = req.query['hub.challenge'];
// Checks if a token and mode is in the query string of the request
if (mode && token) {
// Checks the mode and token sent is correct
if (mode === 'subscribe' && token === VERIFY_TOKEN) {
// Responds with the challenge token from the request
console.log('WEBHOOK_VERIFIED');
res.status(200).send(challenge);
} else {
// Responds with '403 Forbidden' if verify tokens do not match
res.sendStatus(403);
}
}
}
let postWebhook = (req, res) => {
let body = req.body;
// Parse the request body from the POST
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(function (entry) {
// Gets the body of the webhook event
let webhook_event = entry.messaging[0];
console.log(webhook_event);
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
} else {
// Return a '404 Not Found' if event is not from a page subscription
res.sendStatus(404);
}
}
// Handles messages events
function handleMessage(sender_psid, received_message) {
let response;
// Checks if the message contains text
if (received_message.text) {
// Create the payload for a basic text message, which
// will be added to the body of our request to the Send API
response = {
"text": `ආයුබෝවන්! ඔබ මේ සම්බන්ද වන්නේ chatbot IN සේවාව වෙතයි.!ඔබට මේ පිළිබද වැඩිදුර දැනගැනීමට අවශ්‍යද?`,
"quick_replies":[
{
"content_type":"text",
"title":"Yes",
"payload":"<POSTBACK_PAYLOAD>",
},{
"content_type":"text",
"title":"No",
"payload":"<POSTBACK_PAYLOAD>",
}
]
}
}
}
// Send the response message
callSendAPI(sender_psid, response);
// Sends response messages via the Send API
function 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
request({
"uri": "https://graph.facebook.com/v11.0/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
} else {
console.error("Unable to send message:" + err);
}
});
}
module.exports = {
test: test,
getWebhook: getWebhook,
postWebhook: postWebhook
}
Thanks!

how to wait for a result in rxjs for a lambda function

I am trying to write an async lambda function which is calling a function for sign up a user in cognito.
my problem is that in my lambda function, it is not waiting for the result and finish the execution. would you mind check what is my issue? I am new to rxjs. please help me.
mylambda function
exports.handler = async (event, context) => {
//poolData and params will fetch from event
let source = await signup(poolData, params);
console.log(source);
});
my signup function
function signup(poolData, body) {
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const { username, password, attributes } = body;
const attributesList = [];
if (Array.isArray(attributes)) {
attributesList.push(
...attributes.map(item => new AmazonCognitoIdentity.CognitoUserAttribute(item))
);
}
let source = Observable.create(observer => {
let output = (err, res) => {
if (err)
{
observer.error(err);
}
else
{
const cognitoUser = res.user;
const data = {
username: cognitoUser.getUsername(),
};
observer.next(data);
}
observer.complete();
}
userPool.signUp(username, password, attributesList, null, output);
});
let respond;
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
source.subscribe(subscriber);
}
module.exports = signup;
This behavior is totally normal.
So first thing first, an observable is not a promise which means you are not able to await a response with the await keyword, also I don't see anything to be returned from the signup function, which will probably lead to undefined to be logged anyways.
So how to fix that, one way to fix this issue is to use toPromise() which will turn your observable into a promise which then can be awaited wherever needed.
The other way (which is the rxjs way) will be to return from the signup function the observable and inside your handler function to subscribe for the response.
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
exports.handler = (event, context) => {
//poolData and params will fetch from event
signup(poolData, params).subscribe(subscriber);
})

Resources