Twilio node - Browser to phone StatusCallback events - node.js

I am trying to get back StatusCallback events when I dial from my browser to phone call.
When user clicks on dial in browser I am sending the following response to twilio:
const dial = twiml.dial({
callerId: Meteor.settings.private.twilio.TWILIO_CALLER_ID,
answerOnBridge: true,
record: "record-from-answer-dual",
StatusCallbackEvent: ["initiated", "ringing", "answered", "completed"],
StatusCallback,
recordingStatusCallback: recordURLCallback,
});
dial.number(toNumber);
I have registered webhook both in twilio console and also sending via command but i'm not receiving 'ringing', 'answered' events from twilio
WebApp.connectHandlers.use("/twilio-status-callback", function( req, res, next ) {
console.log('***status url callback***');
var body = "";
req.on('data', Meteor.bindEnvironment(function (data) {
body += data;
}));
req.on('end', Meteor.bindEnvironment(function () {
body = qs.parse(body)
console.log(body);
res.end();
}));
});
I am only receiving completed event, how to get other statuses to so that I can show ringing UI when it is ringing and hangup button when answered?

Twilio developer evangelist here.
In your example code you don't include an option for StatusCallback so there is no webhook for Twilio to call, only a recordingStatusCallback. Also, the Node library actually translates the keys from lower-camel-case, so the keys should be statusCallback. Try updating the code to something like this and let me know how it goes:
const dial = twiml.dial({
callerId: Meteor.settings.private.twilio.TWILIO_CALLER_ID,
answerOnBridge: true,
record: "record-from-answer-dual",
statusCallbackEvent: ["initiated", "ringing", "answered", "completed"],
statusCallback: statusURLCallback,
recordingStatusCallback: recordURLCallback,
});
dial.number(toNumber);

Related

Send data to all clients upon internal event

I have a Node.js server that manages list of users. When new user is created, all the clients should display immediately the added user in the list.
I know how to send data to clients without request - using Websocket, but in this implementation, Websocket is not allowed.
Is it possible to update all the client's user-list without using Websocket, when new user is added in the server?
// Client side
const subscribe = function(callback) {
var longPoll = function() {
$.ajax({
method: 'GET',
url: '/messages',
success: function(data) {
callback(data)
},
complete: function() {
longPoll()
},
timeout: 30000
})
}
longPoll()
}
// Server Side
router.get('/messages', function(req, res) {
var addMessageListener = function(res) {
messageBus.once('message', function(data) {
res.json(data)
})
}
addMessageListener(res)
})
Long polling is where the client requests new data from the server, but the server does not respond until there is data. In the meantime, the client has an open connection to the server and is able to accept new data once the server has it ready to send.
Ref: http://hungtran.co/long-polling-and-websockets-on-nodejs/
There is a third way: Push Notifications
Your application should register in a Push Notification Server (public or proprietary) and then your server will be able to send messages asynchronously
You can use server-sent events with an implementation like sse-express:
// client
let eventSource = new EventSource('http://localhost:80/updates');
eventSource.addEventListener('connected', (e) => {
console.log(e.data.welcomeMsg);
// => Hello world!
});
// server
let sseExpress = require('./sse-express');
// ...
app.get('/updates', sseExpress, function(req, res) {
res.sse('connected', {
welcomeMsg: 'Hello world!'
});
});

How to return both immediate and delayed response to slack slash command?

I'm trying to use a hook.io microservice to make a slack slash command bot. According to the docs I should be able to send an immediate response then a seperate POST later. But I cant get the immediate response and the later POST to both work.
Here is my test code.
module['exports'] = function testbot(hook) {
var request = require('request');
// The parameters passed in via the slash command POST request.
var params = hook.params;
data = {
"response_type": "ephemeral",
"text": "Immediate Response"
}
hook.res.setHeader('Content-Type', 'application/json');
console.log("returning immediate response")
hook.res.write(JSON.stringify(data), 'utf8', delay(params));
//calling end() here sends the immediate response but the POST never happens.
// but if end() is called below instead slack gives a timeout error but the POST succeeds.
//hook.res.end()
//test with 3.5 second delay
function delay(params) {
setTimeout(function () {post_response(params)},3500);
}
function post_response(params) {
console.log("posting delayed response")
// Set up the options for the HTTP request.
var options = {
// Use the Webhook URL from the Slack Incoming Webhooks integration.
uri: params.response_url,
method: 'POST',
// Slack expects a JSON payload with a "text" property.
json: {"response_type":"in_channel", "text":"Delayed response","parse":"full"}
};
// Make the POST request to the Slack incoming webhook.
request(options, function (error, response, body) {
// Pass error back to client if request endpoint can't be reached.
if (error) {
console.log(error);
hook.res.end(error.message);
} else {
console.log("post OK");
}
// calling end() here sends the POST but the immediate response is lost to a slack timeout error.
hook.res.end()
})
};
}
As detailed in the comments calling res.end() early means the immediate response gets sent but the POST never happens whereas delaying the res.end() until after POST means the delayed response is sent but it generates a timeout error from slack in the meantime.
I'm a javascript newbie so hopefully there is a simple solution that I've overlooked.
Once you call res.end() inside hook.io, the script will immediately abort and end processing. It's the equivalent of calling process.exit. If you fail to end the request, hook.io will eventually hit it's own Time-out Limit.
hook.io should be capable of responding back to Slack within the three seconds Slack requires.
Here is a guide which may help: Making a Custom Slack Slash Command with hook.io
Bad form to answer one's own question I know but the following worked for me using webtask so I include it here in case others find it useful.
var express = require('express');
var Webtask = require('webtask-tools');
var bodyParser = require('body-parser');
var request = require('request');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//visiting above url in browser is handled by get
app.get('/', function (req, res) {
console.log(req.query)
res.send('OK');
});
//post from slack handled here
app.post('/', function (req, res) {
var params = req.body;
console.log(params);
var data = {
"response_type": "ephemeral",
"text": "Immediate Response"
}
res.setHeader('Content-Type', 'application/json');
res.send(data);
// deliberate delay longer than Slack timeout
// in order to test delayed response.
setTimeout(function () { post_response(params) }, 3500);
});
function post_response(params) {
console.log("posting delayed response")
// Set up the options for the HTTP request.
var options = {
// Use the Webhook URL supplied by the slack request.
uri: params.response_url,
method: 'POST',
// Slack expects a JSON payload with a "text" property.
json: { "response_type": "in_channel", "text": "Delayed response", "parse": "full" }
};
// Make the POST request to the Slack incoming webhook.
request(options, function (error, response, body) {
if (error) {
console.log(error);
} else {
console.log("post OK");
}
})
};
module.exports = Webtask.fromExpress(app);

Why is my Twilio nodejs transcribing attempt calling the client twice?

It is calling the client twice and making 1 37 second (in twilio dashboard) phonecall with two transcripts one 22 seconds long the other 5 seconds long, anyone have any ideas?
The phonecall when I make a straight phonecall and record lasts 19 seconds. Thats what my transcript should be 19 seconds longs. Its looping around somewhere.
I used real credentials and real phone numbers.
var twilio = require('twilio');
var client = require('twilio')(accountSid, authToken);
const VoiceResponse = require('twilio').twiml.VoiceResponse;
client.calls.create({
url: 'http://107.170.228.177:80/sendT',
to: '+17000000',
from: '+10000000'
})
app.post('/sendT', urlencodedParser, function(req, res) {
console.log('made to send t')
const rt = new VoiceResponse();
rt.record({
transcribe: true,
transcribeCallback: '/rT'
});
res.status(200);
res.send(rt.toString());
console.log('RT string' + rt.toString());
})
app.post('/rT', urlencodedParser, function(req, res) {
console.log('made to receiveT post');
var ttemp = req['body'].TranscriptionText;
console.log('transcription text ' + ttemp);
var masterFile = __dirname + "/master/t.json";
fs.writeFile(masterFile, ttemp, function(err) {}) //
res.status(200);
res.send();
});
NodeJS output
RT string<?xml version="1.0" encoding="UTF-8"?><Response><Record transcribe="true" transcribeCallback="/rT"/></Response>
made to send t
RT string<?xml version="1.0" encoding="UTF-8"?><Response><Record transcribe="true" transcribeCallback="/rT"/></Response>
made to send t
RT string<?xml version="1.0" encoding="UTF-8"?><Response><Record transcribe="true" transcribeCallback="/rT"/></Response>
made to receiveT post
*call transcript*
made to receiveT post
*call transcript*
Twilio developer evangelist here.
What is happening here is very specific to the <Record> TwiML that you are using.
When the recording is finished being made, Twilio will make an HTTP request to the action attribute that you set on the <Record> to see what to do with the call now. In the case of no action attribute, Twilio will make that request to the current document URL, that is your /sendT endpoint in this case.
This is what it causing the loop, the <Record> then appears again to Twilio and times out after 5 seconds, at which point the call is decided to be over. Now you get two recordings, including 5 seconds of silence.
To fix this, you should either add an action attribute that points to an endpoint that just returns the TwiML to <Hangup/>.
app.post('/sendT', urlencodedParser, function(req, res) {
const rt = new VoiceResponse();
rt.record({
transcribe: true,
transcribeCallback: '/rT',
action: '/hangup'
});
res.status(200);
res.send(rt.toString());
})
app.post('/hangup', function(req, res) {
const hangup = new VoiceResponse();
hangup.hangup();
res.status(200);
res.send(hangup);
})
Or, you can keep no action URL and just check the request to see if it has already made a recording and hang up conditionally based on that.
app.post('/sendT', urlencodedParser, function(req, res) {
const rt = new VoiceResponse();
if (typeof req.body.RecordingUrl !== 'undefined') {
rt.hangup();
} else {
rt.record({
transcribe: true,
transcribeCallback: '/rT',
action: '/hangup'
});
}
res.status(200);
res.send(rt.toString());
})
Let me know if this helps at all.

Twilio not sending status callbacks

I'm trying to get status callbacks for various room events, but twilio is not sending any events to my callback URL, I've used the following code to create a room using the documentation i found here
app.get('/createRoom', function (req, res) {
var client = new Twilio(twilioApiKey, twilioApiSecret, {
accountSid: twilioAccountSid
});
client.video.rooms.create({
uniqueName: myRoomName,
statusCallback: 'myCallbackURL'
}).then((room) => {
//
});
});

Express: Post Request handler doesn't stop calling a function

My express app should call a function once, but it repeatedly calls it an infinite number of times when handling a POST request. I can't figure out why it's called more than once.
This app works with Slack Events API and receives an event from Slack as a post request when a message is posted to a specific Slack channel. Once the app receives the event, it responds with a 200-status response to alert Slack it received it. Then the app extracts the text property from the request and calls postMessage with the text to post the message to a different channel. Posting the message to a different channel won't kick off another event.
The problem is that postMessage() gets called infinitely until I manually crash the app
Here I setup the app and wait for post requests:
const express = require('express');
var bodyParser = require('body-parser');
var app = express();
var jsonParser = bodyParser.json();
// Wait for post requests, then extract it's text
app.post('/', jsonParser, function (req, res) {
if (!req.body){
return res.sendStatus(400);
} else {
postMessage(req.body.event.text); //Should be called once
}
// Respond to Slack Event API we received their request
res.writeHead(200, {'Content-Type': 'application/json'});
res.end();
});
}
app.listen(config('PORT'), (err) => {
if (err) throw err
console.log(`App LIVES on PORT ${config('PORT')}`);
});
The body of the request is structured like:
body = {
event: {
text: "important message"
}
}
The function that keeps getting called. This will post a message to a Slack channel:
function postMessage(message){
var messagePath = 'https://slack.com/api/chat.postMessage?token=xxx&message=' + message;
request(messagePath, function(error, response, body){
if (!error && response.statusCode == 200){
console.log('message sent successfully');
} else {
console.log('error == ' + error);
}
});
}
The postMessage method does get called with the correct text. The problem is that it's called more than once.
I thought Slack's API was possibly sending the same request multiple times but from their documentation they will wait 3 seconds between sending requests. My app will call postMessage() about a hundred times in a second, so I don't think it's being overloaded with requests from Slack
Thank you in advance!
My guess is that your bot, which is listening to posted messages and then responding to those messages, is responding to itself when it posts. This will lead to an infinite loop.
The fix is to write a check to make sure the bot is not responding to itself. Inspect req.body.event and see if a username is being sent with each message. Then you can write something like this:
app.post('/', jsonParser, function (req, res) {
if (!req.body || !req.body.event){
return res.sendStatus(400);
} else if (req.body.event.user_name !== '<OUR_USER_NAME>') { // Make sure we are not responding to ourselves
postMessage(req.body.event.text); // Should be called once
}
// Respond to Slack Event API we received their request
res.writeHead(200, {'Content-Type': 'application/json'});
res.end();
});

Resources