twilio say something to caller (node.js) - node.js

Hey guys I am working on something and have following Problem :
ACTUAL AIM - If someone calls, I want to let the voice say: "Try to reach someone" and then call some numbers out of an array. ( cant do that atm because i need to fake a call )
ATM AIM - Thats why I at least want to say something to the one who answers the twilio call, that I can be sure it "would" work.
So i faked a call by sending the url that twilio would send (if it gets a call) via a localhost http server. So far so good, my phone gets called. But the woman dont say what I wanted her to say... She sais : Thank you for trying our documentation and then waiting music is following.
AND: The call.status is ALLWAYS queued, or I dont catch it at the right place :/ , Remember my phone is ringing so it should have at least the status ringing ...
This is what I have at the moment:
requestHandler.js:
var querystring = require("querystring");
var emergency = require("./emergency");
var twilio = require('twilio');
function callRequest(response) {
var resp = new twilio.TwimlResponse();
resp.say({voice:'woman'}, 'ahoy hoy! Testing Twilio and node.js');
console.log("call incomming ! EMERGENCY 1 1 11 !");
//emergency.handleIncommingCall();
response.writeHead(200, {"Content-Type": "text/xml"});
response.end(resp.toString());
}
exports.callRequest = callRequest;
server.js:
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, pathname, response, request);
}
http.createServer(onRequest).listen(1337);
console.log("Server has started");
}
exports.start = start;
exports.http = http;
router.js:
function route(handle, pathname, response, request) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response, request);
}else{
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/html"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
index.js:
var server = require("./server");
var router = require("./router");
var requestHandler = require("./requestHandler");
var handle = { };
handle["/demo.twilio.com/welcome/voice/"] = requestHandler.callRequest;
server.start(router.route, handle);
emergency.js:
var twilio = require('twilio');
var accountSid = 'cant tell ya';
var authToken = "cant tell ya";
var client = require('twilio')(accountSid, authToken);
var firstCascadeNumber = "cant tell ya";
var secondCascadeNumber;
var privateNumber; //enter privateNumber here
var twiml = new twilio.TwimlResponse();
function handleIncommingCall (){
//twilio should say : we contact team internet pls wait
//twilio should make music
call(1,firstCascadeNumber);
//cb if staus ist nicht rangegangen call(2)
}
function call (cascade,cascadeNumber){
client.makeCall({
url: "http://demo.twilio.com/docs/voice.xml",
to: cascadeNumber,
from: "cant tell ya"
}, function(err, call) {
if(err){
console.log("ERROR:", err.message);
}else{
console.log("calling " + cascadeNumber);
console.log("status: " + call.status);
if(cascade == 1){
//twiml.say("Hello this i a test. Thank you for calling.");
console.log("should say what i want it to say ! god damn it ");
console.log("status: " + call.status);
//if user geht ran
//startConference()
//if user geht nicht ran
//call(2,secondCascadeNumber)
}else if(cascade == 2){
//if user geht ran
//startConference()
//if user geht nicht ran
//inform caller that no one is there
}else{
console.log("Error: cascade doesnt exsist");
}
}
});
}
function openConference(call,from,to){
//call.joinConference([roomName, option, cbOnEnd])
}
exports.handleIncommingCall = handleIncommingCall;

Twilio developer evangelist here.
You're most of the way there, but you've not quite set your application out right here.
When you make the call, the callback you get only refers to whether the call started correctly. It is not a callback that you need to return TwiML to in order to tell Twilio what to do with the call.
Instead, what happens is when Twilio makes the call, it will send an HTTP request to the URL you supply when you make the call in the first place. That URL should be in your application and available to Twilio.
This blog post on using Twilio with Node.js should be able to show you what I mean by all of that and set you up with a good way of testing this locally too.
Edit
Thanks for updating your code.
Your problem is that you are not telling Twilio to ask you what to do with the call once it connects.
When you create a call with the API you need 3 parameters, the number to call, the number to call from and a URL. When Twilio connects the call it will make an HTTP request to the URL you supply asking what to do next and this is where you supply some TwiML to tell Twilio what to do with the call.
Currently you are supplying this URL: http://demo.twilio.com/docs/voice.xml
If you click through the demo Twilio URL there, you will see the TwiML that is being returned and why you hear a message you are not expecting. Because the URL is not yours, your application cannot take control of the call.
You need to send a URL that points at a route in your application, and that route needs to respond with the TwiML you want. You can expose your local server to Twilio using a tool called ngrok which will allow you to test this.
I recommend you follow the tutorial I linked before, this tutorial on using ngrok to text your incoming HTTP requests from Twilio and this tutorial on creating a click to call application with Twilio.
In the case of your application, instead of trying to handle "/demo.twilio.com/welcome/voice/" which is not a URL you have control of, you should handle, say:
var handle = { };
handle["/calls"] = requestHandler.callRequest;
and then use ngrok to create a tunnel to your application and pass the URL to client.makeCall like this:
function call (cascade,cascadeNumber){
client.makeCall({
url: "http://YOUR_NGROK_SUBDOMAIN.ngrok.io/calls",
to: cascadeNumber,
from: "cant tell ya"
}, function(err, call) {
if (err) {
console.log("Call could not be made", err);
} else {
console.log("Call created successfully. Call ID:", call.sid);
}
}
}
Let me know if that helps.

Related

Node.js Lambda Function "response is invalid" Amazon Alexa

UPDATE: I had a mistake on my http request endpoint. I had not set the appropriate authentication options so that fixed a lot of errors possibly this specific one.
My question is similar to one here:
Node.js Lambda function returns "The response is invalid" back to Alexa Service Simulator from REST call
However the solution to that question does not solve my problem. So I make an http request call to an xsjs service in Hana cloud. I am getting the 'response is invalid' error message. I can't see why. Here is my function:
// Create a web request and handle the response.
function httpGet(query, callback) {
console.log("/n QUERY: "+ query);
var host = 'datacloudyd070518trial.hanatrial.ondemand.com';
var path = '/LocationInformation/getLocationInfo.xsjs?location=';
var hostname = 'https://' + host + path + query;
var auth = 'user1:D1anafer';
var req = http.request({'hostname': hostname,
'auth': auth
}, (res) => {
var body = '';
res.on('data', (d) => {
body += JSON.stringify(d);
});
res.on('end', function () {
callback(body);
});
});
req.end();
req.on('error', (e) => {
console.error(e);
});
}
And the function that calls it:
'getNewsIntent': function () {
//self = this;
httpGet(location, function (response) {
// Parse the response into a JSON object ready to be formatted.
//var output = JSON.parse(response);
//output = output['change'];
var output = response;
var cardTitle = location;
var cardContent = output;
alexa.emit(':tellWithCard', output, cardTitle, cardContent);
});
},
Thank You
-Diana
Inside your AWS account go to your Lambda function and click on the monitoring tab, where you should see "View Logs in Cloudwatch" in the right hand corner. If you click that link and you should see the errors that are being produced.
You can also use console.log() to log any information being returned from your REST api, which will be logged in cloudwatch and can help you see where your errors are.
This is just a guess from the top of my head. To really help some detailed error message would be required like mentioned about.
But just a guess: Your http.request() is using the http module (https://nodejs.org/api/http.html) and your are accessing the a https resource. If so there is a https (https://nodejs.org/api/https.html) module or use something like axios https://www.npmjs.com/package/axios or requestjs (https://github.com/request/request) this will handle both.
Like I said just a blind guess without detailed error message and seeing your require statements but I am happy to dive deeper if you happen to have details.
HTH
Your callback from the Lambda has to return a valid status code and body. Like this:
let payload = {
statusCode: 400,
body: JSON.stringify('body'),
headers: {"Access-Control-Allow-Origin": "*"}
};
callback(null, payload);
On top of that, to call this from client side code, you have to pass the CORS header back.

Getting Digits from twilio Gather

I am trying to get the digits entered into phone. I thought res.Digits in Pin function would be the way but I get an undefined error
exports.Say = function(req, res)
{
var resp = new twilio.TwimlResponse();
resp.gather(
{
action:'http://pap-papdemo.rhcloud.com/api/Phone/Pin',
finishOnKey:'#',
method:"POST"
}, function()
{
this.say('Please enter your Phone and Pin number followed by the hash key');
});
//Render the TwiML document using "toString"
res.writeHead(200,
{
'Content-Type':'text/xml'
});
res.end(resp.toString());
};
exports.Pin = function(req, res)
{
var resp = new twilio.TwimlResponse();
console.log("***** PIN *****");
console.log("Pin: Response " + res.body.Digits);
//Render the TwiML document using "toString"
res.writeHead(200,
{
'Content-Type':'text/xml'
});
res.end(resp.toString());
};
any idea what I need to do as I need to store pin number in db
Megan from Twilio here. I saw you answered your own question but figured I'd update as an answer for others who land here.
Twilio will pass Digits as a parameter in addition to the standard TwiML Voice request parameters with its request to the 'action' URL.
Thus var pin = JSON.stringify(req.body.Digits); worked in this case.

nodejs email.send doesnt work inside function

In the code below email with subject 'OK' is sent but not email 'not OK'? The second one is inside a function.
var JSFtp = require("jsftp");
var config = require('./config/config');
var email = require('./modules/mailer');
var ftp = new JSFtp({
host: config.ftphost
});
email.send(config.emailTo, "emailText", "OK");
ftp.list(config.ftpdir, function(err, res) {
console.log(config.emailTo,res);
email.send(config.emailTo, res, "not OK");
//process.exit();
});
it appears you are fetching and scraping a log - - wrong approach.
read up on sendmail(1). Packages like Postfix, Exim, Sendmail have protocols which provide direct access to the server responses and you can respond as necessary.

Correct way to respond to client on Node.js?

This being my first attempt at building a server...
I have set up a server to handle a contact form submission that also includes a predefined captcha string.
When the server receives the contact form, if the captcha string is the one expected then I want it to simply respond with a JSON of the parsed contact form query using response.end(JSON.stringify(parsedURL));
If the captcha string is wrong, I want the server to respond "saying" the captcha was wrong, so that the client asks the user to try again. But I don't know how to do that.
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
if (captcha !== "testing")
{
// send a "bad" response to the client and include the message "bad captcha"
}
else response.end(JSON.stringify(parsedURL.query));
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg);
},
error: function(msg)
{
// the "bad captcha" response should be handled here right ?
console.log(msg); // which should be equivalent to console.log("bad captcha");
}
});
When I use response.end(JSON.stringify(parsedURL)); the client (jQuery) considers that a "success".
How should I respond from the server so that the "error" part of the ajax request on the client is executed?
Or is the "error" part supposed to handle only cases where the server doesn't respond at all, i.e. when something has gone horribly wrong server-side, like an exception, a real error, and not cases where simply my evaluation on the server doesn't have the expected outcome ?
Should I instead useresponse.end(...); in both cases as in :
ON THE SERVER :
var httpServer = http.createServer(function (request, response)
{
if (/\/contactform\?....../.test(request.url))
{
var parsedURL = url.parse(request.url, true);
var name = parsedURL.query.name;
var email = parsedURL.query.email;
var subject = parsedURL.query.subject;
var enquiry = parsedURL.query.enquiry;
var captcha = parsedURL.query.captcha;
var response = JSON.stringify(parsedURL.query);
if (captcha !== "testing") response = "bad captcha";
response.end(response);
}
}).listen(8080);
ON THE CLIENT :
$.ajax({
url: "/contactform?..............",
success: function(msg)
{
console.log(msg); // msg will either be the stringified object or "bad captcha"..
}
});
In other words, when a request is successfully received on the server but the server wants to let the client know that something was missing or whatever, should the response from the server be sent as an "error" (i.e. handled by the "error" block on the client's ajax code) or as a "success" with the appropriate message saying what actually happened?
I think what you need to do is set headers of your response.
Here is an example:
var body = 'Sorry!';
response.writeHead(404, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
Refer to http://nodejs.org/api/http.html#http_response_writehead_statuscode_reasonphrase_headers for more information.

ExpressJS - contact external API

Here is the thing :
I have a client which sends data to a server. This server has to contact an external A.P.I. and send back its response to the client. I just can't figure out how and where I can contact the external A.P.I once the server has got the client data.
I route client data like this :
app.post('/getAutoComplete', routes.read);
routes.read retrieves the data within req.body. With my nodejs version (without express framework), I then request the api this way :
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
The problem is that i'd like to use native expressJS method like app.post but I don't know how because :
Express (app) object is not available here (declared in app.js but not in the route file)
I don't know how to send POST data with app.post
Any suggestion ?
app.post('/getAutoComplete', routes.read);
// assuming routes.read lookes something like this
routes.read = function read(req, res) {
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
};
Also check out https://github.com/mikeal/request It's the de-facto module for doing web requests in node.
routes.read is a function. You can call it with extra parameters, so for example
app.post('/getAutoComplete', function(req,res) {
var q = req.query.q; // or whatever data you need
routes.read(q, function(err, response) {
if (err) throw err;
return res.json(response);
});
});
Now make the routes.read function use the first parameter as the query and when it's gathered the response from the remote API, call the second parameter with any error as the first parameter and the response as the second one.
Update This answer has already been picked as an answer, but it'd be more helpful if I showed an example of routes.read, too:
routes.read = function(q, cb) {
// pretend we calculate the result
var result = q * 10;
if (result > 100) {
// call the callback with error set
return cb("q value too high");
}
// all is well, use setTimeout to demonstrate
// an asynchronous return
setTimeout(function() { cb(null, result) }, 2000);
};

Resources