UNPKG

asteriskagi

Version:
400 lines (387 loc) 17.4 kB
/** * Asterisk AGI (FastAGI) Server for Nodejs / Channel * @module node-asteriskagi * @license MIT * @author Corey S. McFadden <cmcfadden@clearlyip.com> * @copyright This project is not affiliated with, endorsed by, or sponsored by Digium Inc. or Sangoma Technologies Corp, holders of the "Asterisk" trademark, which is used here for identification purposes only. */ import * as net from "net"; import events from "events"; export class AGIChannel extends events.EventEmitter { private _socket!: net.Socket; public remoteServer: string | false; public channel?: string = ""; public language?: string = "en"; public uniqueid?: string = ""; public version?: string = ""; public callerid?: string = ""; public calleridname?: string = ""; public callingpres?: string = ""; public callingani2?: string = ""; public callington?: string = ""; public callingtns?: string = ""; public dnid?: string = ""; public rdnis?: string = ""; public context?: string = ""; public extension?: string = ""; public priority?: string = ""; public enhanced?: string = ""; public accountcode?: string = ""; public threadid?: string = ""; public currently?: string | false; constructor(props: { socket: net.Socket; remoteServer: string | false; channel?: string; language?: string; uniqueid?: string; version?: string; callerid?: string; calleridname?: string; callingpres?: string; callingani2?: string; callington?: string; callingtns?: string; dnid?: string; rdnis?: string; context?: string; extension?: string; priority?: string; enhanced?: string; accountcode?: string; threadid?: string; }) { super(); this._socket = props.socket; this.remoteServer = props.remoteServer; this.channel = props.channel || ""; this.language = props?.language || "en"; this.uniqueid = props?.uniqueid || ""; this.version = props?.version || ""; this.callerid = props?.callerid || ""; this.calleridname = props?.calleridname || ""; this.callingpres = props?.callingpres || ""; this.callingani2 = props?.callingani2 || ""; this.callington = props?.callington || ""; this.callingtns = props?.callingtns || ""; this.dnid = props?.dnid || ""; this.rdnis = props?.rdnis || ""; this.context = props?.context || ""; this.extension = props?.extension || ""; this.priority = props?.priority || ""; this.enhanced = props?.enhanced || ""; this.accountcode = props?.accountcode || ""; this.threadid = props?.threadid || ""; this.currently = false; // Current operation } // Commands mapped to Exec AddQueueMember = (args: string) => this.Exec("AddQueueMember", args); AgentLogin = (args: string) => this.Exec("AgentLogin", args); AgentRequest = (args: string) => this.Exec("AgentRequest", args); AGI = (args: string) => this.Exec("AGI", args); AlarmReceiver = (args: string) => this.Exec("AlarmReceiver", args); AMD = (args: string) => this.Exec("AMD", args); AttendedTransfer = (args: string) => this.Exec("AttendedTransfer", args); AudioSocket = (args: string) => this.Exec("AudioSocket", args); Authenticate = (args: string) => this.Exec("Authenticate", args); Background = (args: string) => this.Exec("Background", args); BackGround = (args: string) => this.Exec("BackGround", args); BackgroundDetect = (args: string) => this.Exec("BackgroundDetect", args); BlindTransfer = (args: string) => this.Exec("BlindTransfer", args); Bridge = (args: string) => this.Exec("Bridge", args); BridgeAdd = (args: string) => this.Exec("BridgeAdd", args); BridgeWait = (args: string) => this.Exec("BridgeWait", args); Busy = (args: string | undefined) => this.Exec("Busy", args); CallCompletionCancel = (args: string) => this.Exec("CallCompletionCancel", args); CallCompletionRequest = (args: string) => this.Exec("CallCompletionRequest", args); CELGenUserEvent = (args: string) => this.Exec("CELGenUserEvent", args); ChangeMonitor = (args: string) => this.Exec("ChangeMonitor", args); ChanIsAvail = (args: string) => this.Exec("ChanIsAvail", args); ChannelRedirect = (args: string) => this.Exec("ChannelRedirect", args); ChanSpy = (args: string) => this.Exec("ChanSpy", args); ClearHash = (args: string) => this.Exec("ClearHash", args); ConfBridge = (args: string) => this.Exec("ConfBridge", args); ConfKick = (args: string) => this.Exec("ConfKick", args); Congestion = (args: string | undefined) => this.Exec("Congestion", args); ContinueWhile = (args: string) => this.Exec("ContinueWhile", args); ControlPlayback = (args: string) => this.Exec("ControlPlayback", args); DAHDIScan = (args: string) => this.Exec("DAHDIScan", args); DateTime = (args: string) => this.Exec("DateTime", args); DBdeltree = (args: string) => this.Exec("DBdeltree", args); DeadAGI = (args: string) => this.Exec("DeadAGI", args); Dial = (args: string) => this.Exec("Dial", args); Dictate = (args: string) => this.Exec("Dictate", args); Directory = (args: string) => this.Exec("Directory", args); DISA = (args: string) => this.Exec("DISA", args); DumpChan = (args: string) => this.Exec("DumpChan", args); EAGI = (args: string) => this.Exec("EAGI", args); Echo = () => this.Exec("Echo", undefined); Else = (args: string) => this.Exec("Else", args); ElseIf = (args: string) => this.Exec("ElseIf", args); EndIf = () => this.Exec("EndIf", undefined); EndWhile = () => this.Exec("EndWhile", undefined); ExecIf = (args: string) => this.Exec("ExecIf", args); ExecIfTime = (args: string) => this.Exec("ExecIfTime", args); ExitIf = (args: string) => this.Exec("ExitIf", args); ExitWhile = () => this.Exec("ExitWhile", undefined); ExtenSpy = (args: string) => this.Exec("ExtenSpy", args); ExternalIVR = (args: string) => this.Exec("ExternalIVR", args); Festival = (args: string) => this.Exec("Festival", args); FollowMe = (args: string) => this.Exec("FollowMe", args); ForkCDR = (args: string | undefined) => this.Exec("ForkCDR", args); Gosub = (args: string) => this.Exec("Gosub", args); GosubIf = (args: string) => this.Exec("GosubIf", args); Goto = (args: string) => this.Exec("Goto", args); GotoIf = (args: string) => this.Exec("GotoIf", args); GotoIfTime = (args: string) => this.Exec("GotoIfTime", args); HangupCauseClear = (args: string) => this.Exec("HangupCauseClear", args); If = (args: string) => this.Exec("If", args); ImportVar = (args: string) => this.Exec("ImportVar", args); Incomplete = (args: string) => this.Exec("Incomplete", args); Log = (args: string) => this.Exec("Log", args); Macro = (args: string) => this.Exec("Macro", args); MacroExclusive = (args: string) => this.Exec("MacroExclusive", args); MacroExit = (args: string) => this.Exec("MacroExit", args); MacroIf = (args: string) => this.Exec("MacroIf", args); MessageSend = (args: string) => this.Exec("MessageSend", args); Milliwatt = (args: string | undefined) => this.Exec("Milliwatt", args); MinivmAccMess = (args: string) => this.Exec("MinivmAccMess", args); MinivmDelete = (args: string) => this.Exec("MinivmDelete", args); MinivmGreet = (args: string) => this.Exec("MinivmGreet", args); MinivmMWI = (args: string) => this.Exec("MinivmMWI", args); MinivmNotify = (args: string) => this.Exec("MinivmNotify", args); MinivmRecord = (args: string) => this.Exec("MinivmRecord", args); MixMonitor = (args: string) => this.Exec("MixMonitor", args); Monitor = (args: string) => this.Exec("Monitor", args); Morsecode = (args: string) => this.Exec("Morsecode", args); MP3Player = (args: string) => this.Exec("MP3Player", args); MSet = (args: string) => this.Exec("MSet", args); MusicOnHold = (args: string | undefined) => this.Exec("MusicOnHold", args); NoCDR = (args: string) => this.Exec("NoCDR", args); ODBC_Commit = (args: string) => this.Exec("ODBC_Commit", args); ODBC_Rollback = (args: string) => this.Exec("ODBC_Rollback", args); ODBCFinish = (args: string) => this.Exec("ODBCFinish", args); Originate = (args: string) => this.Exec("Originate", args); Page = (args: string) => this.Exec("Page", args); Park = (args: string) => this.Exec("Park", args); ParkAndAnnounce = (args: string) => this.Exec("ParkAndAnnounce", args); ParkedCall = (args: string) => this.Exec("ParkedCall", args); PauseMonitor = (args: string) => this.Exec("PauseMonitor", args); PauseQueueMember = (args: string) => this.Exec("PauseQueueMember", args); Pickup = (args: string) => this.Exec("Pickup", args); PickupChan = (args: string) => this.Exec("PickupChan", args); PlayTones = (args: string) => this.Exec("PlayTones", args); PrivacyManager = (args: string) => this.Exec("PrivacyManager", args); Proceeding = () => this.Exec("Proceeding", undefined); Progress = () => this.Exec("Progress", undefined); Queue = (args: string) => this.Exec("Queue", args); QueueLog = (args: string) => this.Exec("QueueLog", args); QueueUpdate = (args: string) => this.Exec("QueueUpdate", args); RaiseException = (args: string) => this.Exec("RaiseException", args); Read = (args: string) => this.Exec("Read", args); ReadExten = (args: string) => this.Exec("ReadExten", args); ReceiveFAX = (args: string) => this.Exec("ReceiveFAX", args); ReceiveMF = (args: string) => this.Exec("ReceiveMF", args); ReceiveSF = (args: string) => this.Exec("ReceiveSF", args); ReceiveText = (args: string) => this.Exec("ReceiveText", args); Record = (args: string) => this.Exec("Record", args); Reload = (args: string | undefined) => this.Exec("Reload", args); RemoveQueueMember = (args: string) => this.Exec("RemoveQueueMember", args); ResetCDR = (args: string) => this.Exec("ResetCDR", args); RetryDial = (args: string) => this.Exec("RetryDial", args); Return = (args: string) => this.Exec("Return", args); Ringing = (args: string) => this.Exec("Ringing", args); SayAlpha = (args: string) => this.Exec("SayAlpha", args); SayAlphaCase = (args: string) => this.Exec("SayAlphaCase", args); SayDigits = (args: string) => this.Exec("SayDigits", args); SayMoney = (args: string) => this.Exec("SayMoney", args); SayNumber = (args: string) => this.Exec("SayNumber", args); SayOrdinal = (args: string) => this.Exec("SayOrdinal", args); SayPhonetic = (args: string) => this.Exec("SayPhonetic", args); SayUnixTime = (args: string) => this.Exec("SayUnixTime", args); SendDTMF = (args: string) => this.Exec("SendDTMF", args); SendFAX = (args: string) => this.Exec("SendFAX", args); SendMF = (args: string) => this.Exec("SendMF", args); SendSF = (args: string) => this.Exec("SendSF", args); SendText = (args: string) => this.Exec("SendText", args); Set = (args: string) => this.Exec("Set", args); SetAMAFlags = (args: string) => this.Exec("SetAMAFlags", args); SMS = (args: string) => this.Exec("SMS", args); SoftHangup = (args: string) => this.Exec("SoftHangup", args); SpeechActivateGrammar = (args: string) => this.Exec("SpeechActivateGrammar", args); SpeechBackground = (args: string) => this.Exec("SpeechBackground", args); SpeechCreate = (args: string) => this.Exec("SpeechCreate", args); SpeechDeactivateGrammar = (args: string) => this.Exec("SpeechDeactivateGrammar", args); SpeechDestroy = (args: string) => this.Exec("SpeechDestroy", args); SpeechLoadGrammar = (args: string) => this.Exec("SpeechLoadGrammar", args); SpeechProcessingSound = (args: string) => this.Exec("SpeechProcessingSound", args); SpeechStart = (args: string) => this.Exec("SpeechStart", args); SpeechUnloadGrammar = (args: string) => this.Exec("SpeechUnloadGrammar", args); StackPop = (args: string) => this.Exec("StackPop", args); StartMusicOnHold = (args: string) => this.Exec("StartMusicOnHold", args); Stasis = (args: string) => this.Exec("Stasis", args); StopMixMonitor = (args: string | undefined) => this.Exec("StopMixMonitor", args); StopMonitor = (args: string | undefined) => this.Exec("StopMonitor", args); StopMusicOnHold = () => this.Exec("StopMusicOnHold", undefined); StopPlayTones = () => this.Exec("StopPlayTones", undefined); StoreDTMF = (args: string) => this.Exec("StoreDTMF", args); StreamEcho = (args: string | undefined) => this.Exec("StreamEcho", args); System = (args: string) => this.Exec("System", args); TestClient = (args: string) => this.Exec("TestClient", args); TestServer = (args: string) => this.Exec("TestServer", args); ToneScan = (args: string | undefined) => this.Exec("ToneScan", args); Transfer = (args: string) => this.Exec("Transfer", args); TryExec = (args: string) => this.Exec("TryExec", args); TrySystem = (args: string) => this.Exec("TrySystem", args); UnpauseMonitor = () => this.Exec("UnpauseMonitor", undefined); UnpauseQueueMember = (args: string) => this.Exec("UnpauseQueueMember", args); UserEvent = (args: string) => this.Exec("UserEvent", args); VMAuthenticate = (args: string) => this.Exec("VMAuthenticate", args); VMSayName = (args: string) => this.Exec("VMSayName", args); VoiceMail = (args: string) => this.Exec("VoiceMail", args); VoiceMailMain = (args: string | undefined) => this.Exec("VoiceMailMain", args); VoiceMailPlayMsg = (args: string) => this.Exec("VoiceMailPlayMsg", args); Wait = (args: string) => this.Exec("Wait", args); WaitDigit = (args: string | undefined) => this.Exec("WaitDigit", args); WaitExten = (args: string | undefined) => this.Exec("WaitExten", args); WaitForCondition = (args: string) => this.Exec("WaitForCondition", args); WaitForNoise = (args: string | undefined) => this.Exec("WaitForNoise", args); WaitForRing = (args: string | undefined) => this.Exec("WaitForRing", args); WaitForSilence = (args: string | undefined) => this.Exec("WaitForSilence", args); WaitForTone = (args: string | undefined) => this.Exec("WaitForTone", args); WaitUntil = (args: string | undefined) => this.Exec("WaitUntil", args); While = (args: string) => this.Exec("While", args); Zapateller = (args: string) => this.Exec("Zapateller", args); /** * Answer Channel */ async Answer() { return await this.send("ANSWER"); } /** * Wildcard command handler * @param {string} command * @param {string|undefined} args */ async Exec(command: string, args: string | undefined) { try { this.currently = command; await this.send(`EXEC ${command} ${args}`); this.currently = false; return; } catch (err) { return false; } } /** * Get AGI Variable * @param {string} variable * @returns */ async getVariable(variable: string) { try { return await this.send("GET VARIABLE " + variable); } catch (err) { this.emit("error", "getVariable ERROR: " + err); return false; } } /** * Hang up channel */ async Hangup() { await this.send("HANGUP"); } /** * Do Nothing (No Operation) * @param {string} args - text */ async NoOp(args: string) { return await this.send(`NOOP ${args}`); } /** * Sends audio file on channel. * @param {string} filename */ async Playback(filename: string) { try { this.currently = "Playback"; await this.send("STREAM FILE " + filename + ' ""'); this.currently = false; return; } catch (err) { this.emit("error", "Playback ERROR: " + err); return false; } } /** * Send FastAGI command to specified socket * @param {string} command */ async send(command: string) { return new Promise((resolve, reject) => { try { this._socket.once("data", (data) => { const response: any = this._parseResponse(data.toString().trim()); if (response.code == "520") { this.emit("error", response.data); resolve(false); return; } if (response.result < 0) { this.emit("error", "Dead channel detected."); this._socket && this._socket.end(); resolve(false); } const match = response.data.match(/\((.*?)\)/); resolve(match ? match[1] : response.data || response.result); }); if (this._socket.writable) { this._socket.write(command + "\n", "utf8"); } else { this.emit("error", "Dead channel detected."); this._socket && this._socket.end(); resolve(false); } } catch (err) { this.emit("error", "AGI Send Error:" + err); resolve(false); return; } }); } /** * Verbose log line * @param args - Text to log */ async Verbose(args: string) { return await this.send(`VERBOSE ${args}`); } /** * Parse AGI response codes * @param {string} str * @returns object - Response code,result,data */ _parseResponse(str: string) { try { let match = str.match(/(\d+)\s+result=(-?\d+)(?:\s+(.*))?/); if (match) { return { code: match[1], result: Number(match[2]) || 0, data: match[3] || "", }; } match = str.match(/(\d+)-(.*)/); return match ? { code: match[1], result: 0, data: match[2], } : { code: "", result: "", data: str }; } catch (err) { return { code: "", result: "", data: str }; } } }