Skip to content

Instantly share code, notes, and snippets.

@mheadd
Created October 21, 2010 15:18
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save mheadd/638661 to your computer and use it in GitHub Desktop.
Save mheadd/638661 to your computer and use it in GitHub Desktop.
Node.js script to execute FastAGI application
// Include required modules.
var net = require('net');
var sys = require('sys');
// Create a TCP server and listen on FastAGI port.
var server = net.createServer();
server.listen(4573, '127.0.0.7');
// Add a listener for new connections.
server.addListener('connection', fastAGI);
// An array to hold AGI variables submitted from Asterisk.
var agiVars = new Array();
// An array to hold the set of commands we want to send back to Asterisk.
var commands = new Array();
// Return value provided by Asterisk after AGI commands are executed.
var returnValue;
/******************************************************************************
* Asterisk AGI Commands.
******************************************************************************
*/
// Method to stream an audio file.
function streamFile(file, escapeDigits, offset) {
var command = "STREAM FILE " + file + " \"" + escapeDigits + "\"" ;
if(typeof(offset) != 'undefined') { command += " " + offset; }
command += "\n";
commands.push(command);
}
// Method to say a number.
function sayNumber(number, escapeDigits) {
var command = "SAY NUMBER " + number + " \"" + escapeDigits + "\"" + "\n" ;
commands.push(command);
}
// Method to tell Asterisk to hangup the channel.
function hangup(channel) {
var command = "HANGUP";
if(typeof(channel) != 'undefined') { command += " " + channel; }
command += "\n";
commands.push(command);
}
/******************************************************************************
* Helper methods.
******************************************************************************
*/
// Method to access AGI variables submitted from Asterisk.
function getagiVars(data) {
var values = data.toString().split("\n");
for(i=1; i < values.length; i++) {
var temp = values[i].split(":");
agiVars[temp[0]] = temp[1];
}
}
// Method to extract the return value from Asterisk response.
function getReturnValue(data) {
returnValue = data.substr((data.indexOf("=")+1),1);
}
// Method to prepare the response before sending commands to Asterisk
// Call before stream.write().
function prepareResponse() {
commands.reverse();
}
// Method to render commands one at a time from the commands array.
function renderCommands() {
return commands.pop();
}
// Prototype method to create size property for agiVars array.
Array.prototype.size = function () {
var size = this.length ? --this.length : -1;
for (var item in this) {
size++;
}
return size;
}
// Method to execute AGI logic.
function fastAGI(stream) {
stream.setEncoding('utf8');
stream.addListener('connect', function() {
sys.puts("Got a connection from Asterisk!");
});
stream.addListener('data', function(data) {
// When Asterisk starts the AGI script, it will pass channel variables.
if(!agiVars.size()) {
// Populate agiVars array.
getagiVars(data);
// Write some debug output.
sys.puts("Getting a call from: " + agiVars["agi_calleridname"]);
// Set up the commands to send back to Asterisk, populate the commands array.
streamFile("hello-world", "#");
streamFile("tt-monkeys", "#");
streamFile("goodbye", "#");
hangup();
// Prepare the response (just reverses the commands array).
prepareResponse();
// Start sending commands.
stream.write(renderCommands());
}
// With subnsequent responses, Asterisk will send a response code with return value.
else {
// Check the return value from Asterisk.
getReturnValue(data);
// After we tell Asterisk to streak audio files, we get a 0 return.
if(returnValue == 0) {
stream.write(renderCommands()); // Send the next command.
}
// After we tell Asterisk to hangup, we get a 1 return.
else {
stream.end();
}
}
});
// We don't see this event until we call stream.end().
stream.addListener('end', function() {
sys.puts("Goodbye Asterisk.");
agiVars = new Array();
commands = new Array();
});
stream.addListener('error', function() {
stream.end();
});
}
@mheadd
Copy link
Author

mheadd commented Oct 21, 2010

Launch the node TCP server for FastAGI:

~$ node path/to/fastagi.js

Add a context for FastAGI testing:

[fastagi-test]
exten => _5XXX,1,Answer()
exten => _5XXX,n,AGI(agi://127.0.0.1/hello)
exten => _5XXX,n,Hangup()

Include this in your default context:

include => fastagi-test

When you dial a 4-digit extension beginning with 5 the test will execute.

@HERRKIN
Copy link

HERRKIN commented Jul 11, 2014

hello, I am looking forward to learn fastAGI with node but there are some things that confuse me. in your script I dont see where you have logic for hello or how I can have multiple scripts (ip/script1, ip/script2 etc) I am trying to find some information about how to make a fastAGI server in node but I have found very little information.

@lorneb
Copy link

lorneb commented Dec 9, 2014

Hi the ip address in your code DO NOT Match, you have 127.0.0.1 and 127.0.0.7, just thought I'd save others from the time waste, but thanks for the kick start example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment