UNPKG

voxo-agi

Version:
747 lines (482 loc) 13.7 kB
'use strict'; /* eslint no-var: 0 */ var util = require('util'); var events = require('events'); var sprintf = require('sprintf-js').sprintf; var AGIReply= require('./agi-reply'); var AGIChannel = function(request, mapper) { events.EventEmitter.call(this); var self = this; self.isHangup= false; self.request = request; self.cmdId = 0; if (typeof mapper == 'function') { mapper = { default: mapper }; } else if (typeof mapper != 'object') { self.emit('error', 'Invalid mapper'); return; } // locate the script var script; if (request.network_script) { script = mapper[script]; } if (!script) { script = mapper.default; } if (!script) { self.emit('error', 'Could not find requested script'); return; } process.nextTick(function () { script(self) .then(function () { self.emit("done"); }).catch(function (error) { self.emit("error", error); }); }); this.relax= getRelax(this); }; util.inherits(AGIChannel, events.EventEmitter); AGIChannel.prototype.handleReply = function (rawReplyLine) { this.callback(new AGIReply(rawReplyLine)); }; //NEED timeout? AGIChannel.prototype.sendRequest = function (request) { var self = this; return new Promise(function (resolve) { if( self.isHangup ){ resolve(null); return; } self.callback = resolve; self.emit('request', request, ++self.cmdId); }); }; // external API AGIChannel.prototype.answer = function () { var self = this; return new Promise(function (resolve) { self.sendRequest("ANSWER") .then(function (reply) { var failure= ( !reply || reply.code !== 200 || reply.attributes.result != 0 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": failure?null:undefined }); }); }); }; AGIChannel.prototype.channelStatus = function (channelName) { var self = this; return new Promise(function (resolve) { channelName = channelName || ''; self.sendRequest(sprintf('CHANNEL STATUS %s', channelName)) .then(function (reply) { var failure= ( !reply || reply.code !== 200 || reply.attributes.result == -1 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": failure?null:parseInt(reply.attributes.result) }); }); }); }; AGIChannel.prototype.exec = function (app, params) { var self = this; return new Promise(function (resolve) { if (params == undefined) { params = []; } var paramsQuery; if (params.length === 0) { paramsQuery = ""; } else if (params.length === 1) { paramsQuery = params[0]; } else { paramsQuery = `"${params.join(",")}"`; } var query = sprintf('EXEC %s %s', app, paramsQuery); self.sendRequest(query) .then(function (reply) { var failure= ( !reply || reply.code !== 200 || reply.attributes.result == -2 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": failure?null:reply.attributes.result }); }); }); }; AGIChannel.prototype.getData = function (file, timeout, maxDigits) { var self = this; return new Promise(function (resolve) { /* failure: 200 result=-1 timeout with pressed digits: 200 result=<digits> (timeout) timeout without pressed digits: 200 result= (timeout) success: 200 result=<digits> */ timeout = (timeout == undefined) ? '' : timeout; maxDigits = (maxDigits == undefined) ? '' : maxDigits; self.sendRequest(sprintf('GET DATA "%s" %s %s', file, timeout, maxDigits)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 || reply.attributes.result == -1 ); let relevantResult = null; if (!failure) { var digits = reply.attributes.result; var arrDigit = []; for (var i = 0; i < digits.length; i++) { arrDigit.push(digits[i]); } relevantResult = { "digits": arrDigit, "timeout": reply.extra === "timeout" }; } resolve({ "failure": failure, "agiReply": reply, "relevantResult": relevantResult }); }); }); }; AGIChannel.prototype.getFullVariable = function (variable, channel) { var self = this; return new Promise(function (resolve) { channel = (channel === undefined) ? '' : channel; self.sendRequest(sprintf('GET FULL VARIABLE %s %s', variable, channel)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": reply.extra ? reply.extra : null }); }); }); }; AGIChannel.prototype.getVariable = function (variable) { var self = this; return new Promise(function (resolve) { self.sendRequest(sprintf('GET VARIABLE "%s"', variable)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": reply.extra ? reply.extra : null }); }); }); }; AGIChannel.prototype.streamFile = function (file, escapeDigits, sampleOffset) { var self = this; return new Promise(function (resolve) { escapeDigits = escapeDigits || []; //STREAM FILE FILENAME ESCAPE_DIGITS SAMPLE_OFFSET var query = `STREAM FILE "${file}" "${escapeDigits.join("")}"`; if (sampleOffset) { query += ` "${sampleOffset * 10}"`; } self.sendRequest(query) .then(function (reply) { /* failure: 200 result=-1 endpos=<sample offset> failure on open: 200 result=0 endpos=0 success: 200 result=0 endpos=<offset> */ let failure = ( !reply || reply.code !== 200 || ( reply.attributes.result == -1 || ( reply.attributes.result == 0 && reply.attributes.endpos == 0 ) ) ); var relevantResult = { "endPos": parseInt(reply.attributes.endpos) / 10 }; var digitCode = parseInt(reply.attributes.result); if (digitCode > 0) { relevantResult.digit = String.fromCharCode(digitCode); } resolve({ "failure": failure, "agiReply": reply, "relevantResult": relevantResult }); }); }); }; AGIChannel.prototype.hangup = function () { var self = this; return new Promise(function (resolve, reject) { self.sendRequest("HANGUP") .then(function (reply) { /* failure: 200 result=-1 success: 200 result=1 */ var failure = ( !reply || reply.code !== 200 || reply.attributes.result != 1 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": null }); }); }); }; AGIChannel.prototype.setVariable = function (variable, value) { var self = this; return new Promise(function (resolve, reject) { self.sendRequest(sprintf('SET VARIABLE %s %s', variable, value)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": null }); }); }); }; AGIChannel.prototype.setContext = function (context) { var self = this; return new Promise(function (resolve, reject) { self.sendRequest(sprintf('SET CONTEXT %s', context)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 || reply.attributes.result != 0 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": null }); }); }); }; AGIChannel.prototype.setExtension = function (extension) { var self = this; return new Promise(function (resolve, reject) { self.sendRequest(sprintf('SET EXTENSION %s', extension)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 || reply.attributes.result != 0 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": null }); }); }); }; AGIChannel.prototype.setPriority = function (priority) { var self = this; return new Promise(function (resolve, reject) { self.sendRequest(sprintf('SET PRIORITY %s', priority)) .then(function (reply) { var failure = ( !reply || reply.code !== 200 || reply.attributes.result != 0 ); resolve({ "failure": failure, "agiReply": reply, "relevantResult": null }); }); }); }; AGIChannel.prototype.getOption = function (file, escapeDigits, timeout) { var self = this; return new Promise(function (resolve) { escapeDigits = escapeDigits || []; //STREAM FILE FILENAME ESCAPE_DIGITS SAMPLE_OFFSET var query = `GET OPTION "${file}" "${escapeDigits.join("")}" "${timeout || "0"}"`; self.sendRequest(query) .then(function (reply) { /* failure: 200 result=-1 endpos=<sample offset> failure on open: 200 result=0 endpos=0 success: 200 result=0 endpos=<offset> */ let failure = ( !reply || reply.code !== 200 || ( reply.attributes.result == -1 || ( reply.attributes.result == 0 && reply.attributes.endpos == 0 ) ) ); var relevantResult = { "endPos": parseInt(reply.attributes.endpos) / 10 }; var digitCode = parseInt(reply.attributes.result); if (digitCode > 0) { relevantResult.digit = String.fromCharCode(digitCode); } resolve({ "failure": failure, "agiReply": reply, "relevantResult": relevantResult }); }); }); }; AGIChannel.prototype.recordFile = function ( file, format, escapeDigits, timeout, beep, silence ) { var self = this; return new Promise(function (resolve) { //RECORD FILE <filename> <format> <escape digits> <timeout> [s=<silence>] /* failure to write: 200 result=-1 (writefile) failure on waitfor: 200 result=-1 (waitfor) endpos=<offset> hangup: 200 result=0 (hangup) endpos=<offset> interrupted: 200 result=<digit> (dtmf) endpos=<offset> timeout: 200 result=0 (timeout) endpos=<offset> random error: 200 result=<error> (randomerror) endpos=<offset> */ format = format || 'wav'; escapeDigits = escapeDigits || []; var query = `RECORD FILE "${file}" "${format}" "${escapeDigits.join("")}" ${timeout || -1}`; if (beep) { query += ` BEEP`; } if(silence){ query += ` s=${silence}` } self.sendRequest(query) .then(function (reply) { var failure = ( !reply || reply.code !== 200 || ( ( reply.attributes.result == -1 && reply.extra === "writefile" ) || reply.extra === "randomerror" ) ); var relevantResult = { "recordDuration": (reply.extra === "writefile") ? 0 : parseInt(reply.attributes.endpos) / 10, "maxLengthReached": reply.extra === "timeout", "escapeDigitPressed": (reply.extra === "dtmf") ? String.fromCharCode(parseInt(reply.attributes.result)) : null, "hangup": reply.extra === "hangup" }; resolve({ "failure": false, "agiReply": reply, "relevantResult": relevantResult }); //resolve(result); }); }); }; AGIChannel.parseBuffer = function (buffer) { var request = {}; buffer.split('\n').forEach(function (line) { var items = line.split(/:\s?/); if (items.length == 2) { var name = items[0].trim(); if (name.indexOf('agi_') == 0) { name = name.substring(4); } var value = items[1].trim(); request[name] = value; } }); return request; }; function getRelax(channel) { var methodNames = [ "answer", "channelStatus", "exec", "getData", "getVariable", "recordFile", "setContext", "setExtension", "setPriority", "setVariable", "streamFile", "hangup", "getFullVariable", "getOption" ]; let relax = {} methodNames.forEach(function (methodName) { relax[methodName] = function () { var argv = arguments; return new Promise(function (resolve, reject) { channel[methodName].apply(channel, argv).then(function (resp) { if (resp.failure) { if (!channel.isHangup) { let error = new Error("AGI action error but no hangup"); error.resp = resp; reject(error); } return; } resolve(resp.relevantResult); }); }); }; }); return relax; } module.exports = AGIChannel;