3 var _ = require('lodash');
5 var agi = require('agi');
6 var util = require('util');
7 var moment = require('moment');
8 var xml = require('xml2js');
9 var wait = require('wait.for');
10 var sr = require('simple-random');
11 var path = require('path');
12 var config = require('../config/environment');
13 var sh = require('shelljs');
15 var db = require("odbc")();
17 var SquareProject = require('../models').SquareProject;
18 var Variable = require('../models').Variable;
19 var SquareOdbc = require('../models').SquareOdbc;
20 var Settings = require('../models').Settings;
21 var User = require('../models').User;
22 var VoiceQueue = require('../models').VoiceQueue;
23 var Trunk = require('../models').Trunk;
24 var Interval = require('../models').Interval;
25 var Upload = require('../models').Upload;
26 var ReportSquare = require('../models').ReportSquare;
27 var ReportSquareDetail = require('../models').ReportSquareDetail;
28 // var TempTable = require('../models').TempTable;
29 // var FakeTable = require('../models').FakeTable;
30 var users, trunks, variables, intervals, projects, sounds, queues, dbConnections, generalUniqueId;
32 var weekDaysCollection = {
41 var monthsCollection = {
57 methods.answer = function(context, vertex, callback) {
58 console.log('--ANSWER BLOCK--');
59 console.log('Answering the call...');
60 context.send('ANSWER\n', function(err, res) {
65 methods.custom_app = function(context, vertex, callback) {
66 console.log('--CUSTOM APP BLOCK--');
67 console.log('Executing custom app "' + vertex.application + '"...');
68 context.exec(vertex.application, vertex.options, function(err, res) {
76 methods.dial = function(context, vertex, callback) {
77 console.log('--INTERNAL_DIAL BLOCK--');
81 var sip = _.find(users, {
82 id: parseInt(vertex.sip_id)
84 console.log('Calling ' + util.format('SIP/%s', sip.name) + '...');
85 var parameters = [util.format('SIP/%s', sip.name), vertex.timeout, vertex.opts, vertex.url];
86 context.exec('DIAL', parameters.join(','),
92 methods.ext_dial = function(context, vertex, callback) {
93 console.log('--EXTERNAL_DIAL BLOCK--');
97 var trunk = _.find(trunks, {
98 id: parseInt(vertex.trunk_id)
100 console.log('Calling ' + util.format('SIP/%s', trunk.name) + '...');
101 var parameters = [util.format('SIP/%s@%s', vertex.phone, trunk.name), vertex.timeout, vertex.opts, vertex.url];
102 context.exec('DIAL', parameters.join(','),
108 methods.queue = function(context, vertex, callback) {
109 console.log('--QUEUE BLOCK--');
113 var queue = _.find(queues, {
114 name: vertex.queue_id
116 var announceOverride = getFilePath(vertex.file_id);
117 var parameters = [queue.name, vertex.opts, vertex.url, announceOverride, vertex.timeout, vertex.agi, vertex.macro, vertex.gosub, '', vertex.position];
118 console.log('Joining ' + queue.name + ' queue...');
119 context.exec('QUEUE', parameters.join(','), function(err, res) {
124 methods.voicemail = function(context, vertex, callback) {
125 console.log('--VOICEMAIL BLOCK--');
126 var parameters = [util.format('%s@%s', vertex.boxnumber, vertex.context), vertex.opts];
127 console.log('Starting voicemail recording...');
128 context.exec('VOICEMAIL', parameters.join(','), function(err, res) {
133 // methods.callback = function(context, vertex, callback) {
134 // context.send('ANSWER\n', function(err, res) {
135 // callback(err, res);
139 methods.math = function(context, vertex, callback) {
140 console.log('--MATH BLOCK--');
141 console.log('Calculating expression...');
142 var result = eval(vertex.operation);
143 console.log('Saving result in variable...');
144 setVariable(context, vertex.variable_id, result, callback);
147 // methods.background = function(context, vertex, callback) {
148 // var parameters = [getFilePath(vertex.file_id), vertex.opts];
149 // context.exec('BACKGROUND', parameters.join('|'), function(err, res) {
150 // callback(err, res);
154 methods.playback = function(context, vertex, callback) {
155 console.log('--PLAYBACK BLOCK--');
156 var audiofile = getFilePath(vertex.file_id);
157 // var audiofile = '/var/www/html/files/sounds/d0269ff87187df665ece75538e4cddfd';
158 var parameters = [audiofile, vertex.opts];
159 console.log('Executing playback...');
160 context.exec('PLAYBACK', parameters.join(','), function(err, res) {
165 methods.menu = function(context, vertex, callback) {
166 console.log('--MENU BLOCK--');
168 console.log('There are ' + vertex.retry + ' retries');
169 if (vertex.retry > 0) {
171 // var announce = getFilePath(vertex.file_id);
172 var announce = '/var/www/html/files/sounds/b19642d2f71e9cfffbd783fcc79c7415';
173 // console.log(announce);
174 console.log('Announcing and waiting for user entry...');
175 context.send(util.format('GET DATA %s %s %s\n', announce, parseInt(vertex.response) * 1000, vertex.digit),
178 uniqueid: context.uniqueid,
180 application: vertex.tag,
181 data: res.result || null
184 .create(squareDetail)
185 .catch(function(err) {
186 console.log('Error saving ' + vertex.tag + ':' + vertex.label + ' block log', err);
188 if (res.result !== ' (timeout)') {
189 var variableId = parseInt(vertex.variable_id);
191 console.log('Saving user entry in a variable...');
192 setVariable(context, variableId, res.result);
194 res.data = res.result;
197 console.log('Menu timeout!');
208 console.log('Run out of retries!');
218 methods.saynumber = function(context, vertex, callback) {
219 console.log('--SAYNUMBER BLOCK--');
220 console.log('Saying number...');
221 context.send(util.format('SAY NUMBER %s "%s"\n', vertex.number, vertex.escape_digits),
227 methods.sayphonetic = function(context, vertex, callback) {
228 console.log('--SAYPHONETIC BLOCK--');
229 console.log('Saying phonetic...');
230 context.send(util.format('SAY PHONETIC %s "%s"\n', vertex.text, vertex.escape_digits),
236 methods.tts = function(context, vertex, callback) {
237 console.log('--GOOGLE_TTS BLOCK--');
238 var parameters = [path.join(config.root, 'server/config/agi_scripts', 'googletts.agi'), encodeURIComponent(vertex.text), vertex.google_tts_language];
239 // var parameters = ['/var/www/html/agisquare/agiscripts/googletts.agi', encodeURIComponent(vertex.text), vertex.google_tts_language];
240 console.log('Calling Google TTS API...');
241 context.exec('AGI', parameters.join(','),
247 methods.ispeechtts = function(context, vertex, callback) {
248 console.log('--ISPEECH_TTS BLOCK--');
249 // var parameters = [path.join(config.root, 'server/config/agi_scripts', 'ispeech-tts.agi'), encodeURIComponent(vertex.text), vertex.ispeech_tts_language, '', '', vertex.key];
250 var parameters = ['/var/www/html/agisquare/agiscripts/ispeech-tts.agi', encodeURIComponent(vertex.text), vertex.ispeech_tts_language, '', '', vertex.key];
251 console.log('Calling iSpeech TTS API...');
252 context.exec('AGI', parameters.join(','),
258 methods.getdigits = function(context, vertex, callback) {
259 console.log('--GETDIGITS BLOCK--');
261 console.log('There are ' + vertex.retry + ' retries');
262 if (vertex.retry > 0) {
264 var announce = getFilePath(vertex.file_id);
265 // var announce = '/var/www/html/files/sounds/b19642d2f71e9cfffbd783fcc79c7415';
266 console.log('Announcing and waiting for user entry...');
267 context.send(util.format('GET DATA %s %s %s\n', announce, parseInt(vertex.response) * 1000, vertex.maxdigit),
270 uniqueid: context.uniqueid,
272 application: vertex.tag,
273 data: res.result || null
276 .create(squareDetail)
277 .catch(function(err) {
278 console.log('Error saving ' + vertex.tag + ':' + vertex.label + ' block log', err);
280 if (res.result && res.result.length >= parseInt(vertex.mindigit)) {
281 if (res.result !== '-1') {
282 console.log('There is a result, is over the minimum length and not due to an hangup!');
283 var variableId = parseInt(vertex.variable_id);
285 console.log('Saving user entry in a variable...');
286 setVariable(context, variableId, res.result);
295 console.log('Channel hangup!');
303 console.log('No entry or not long enough!');
313 console.log('Run out of retries!');
322 methods.record = function(context, vertex, callback) {
323 console.log('--RECORD BLOCK--');
327 // name: vertex.name,
328 // filename: saveName
330 // .then(function() {
331 console.log('Starting call recording...');
332 context.send(util.format('RECORD FILE %s wav "%s" %s %s %s %s\n', path.join(config.root, 'server/files/recordings', saveName), vertex.escape_digits, vertex.timeout, null, true, null), function(
334 if (res.code === 200 && res.result !== '-1') {
335 console.log('Saving recording filename in RECORDING_SAVENAME variable...');
336 context.send(util.format('SET VARIABLE %s %s\n', 'RECORDING_SAVENAME', saveName), function(err, res) {
344 // .catch(function(err) {
349 methods.gotoiftime = function(context, vertex, callback) { //single or multiple intervals
350 console.log('--GOTOIFTIME BLOCK--');
357 var interval = _.find(intervals, {
358 id: parseInt(vertex.interval_id)
360 if (!interval.IntervalId) {
361 gotoIntervals = _.filter(intervals, {
362 IntervalId: parseInt(interval.id)
366 console.log('Is a group of intervals!');
367 if (gotoIntervals.length) {
368 console.log('There are ' + gotoIntervals.length + ' intervals!');
370 console.log('Checking if at least one interval is valid...');
371 gotoIntervals.forEach(function(elem, index) {
372 subInterval = splitInterval(elem.interval);
373 if (isIntervalValid(subInterval)) {
374 console.log('Interval ' + index + ' is valid!');
379 console.log('There are no sub intervals, so it will be always true!');
383 console.log('Is a single interval!');
384 var splittedInterval = splitInterval(interval.interval);
385 if (isIntervalValid(splittedInterval)) {
386 console.log('The interval is valid!');
390 console.log('The final result for the intervals is "' + valid + '"!');
399 methods.vswitch = function(context, vertex, callback) {
400 console.log('--VARIABLE_SWITCH BLOCK--');
401 console.log('Getting the variable value and searching the right exit...');
403 data: getVariable(context, vertex.variable_id)
408 // methods.goal = function(context, vertex, callback) {
412 // goalname: vertex.goalname
414 // .then(function(res) {
415 // callback(null, res);
417 // .catch(function(err) {
418 // callback(err, null);
422 methods.system = function(context, vertex, callback) {
423 console.log('--SYSTEM BLOCK--');
425 uniqueid: context.uniqueid,
427 application: vertex.tag,
428 data: _.trim(vertex.command) || null
431 .create(squareDetail)
432 .catch(function(err) {
433 console.log('Error saving ' + vertex.tag + ':' + vertex.label + ' block log', err);
435 console.log('Executing the system command...');
436 sh.exec(_.trim(vertex.command), function(code, output) {
437 var formattedOutput = output.replace(/(\r\n|\n|\r)/gm, "");
438 console.log('Program output:', formattedOutput);
439 console.log('Saving the output in a variable...');
440 setVariable(context, vertex.variable_id, '"' + formattedOutput + '"', callback);
444 methods.agi = function(context, vertex, callback) {
445 console.log('--AGI BLOCK--');
446 console.log('Executing the AGI command...');
447 context.exec('AGI', vertex.command, vertex.args,
453 methods.subproject = function(context, vertex, callback) {
454 console.log('--SUBPROJECT BLOCK--');
458 var project = _.find(projects, {
459 id: parseInt(vertex.project_id)
461 console.log('Moving to project ""' + project.name + '"...');
462 context.exec('AGI', util.format('agi://192.168.2.147/square,%s', project.name),
468 methods.ispeechasr = function(context, vertex, callback) {
469 console.log('--ISPEECH_ASR BLOCK--');
470 // var parameters = ['/var/www/html/agisquare/agiscripts/ispeech-asr.agi', vertex.ispeech_asr_language, '', (vertex.model === '0' ? '' : vertex.model), '1', '#', '', vertex.key];
471 var parameters = [path.join(config.root, 'server/config/agi_scripts', 'ispeech-asr.agi'), vertex.ispeech_asr_language, '', (vertex.model === '0' ? '' : vertex.model), '1', '#', '', vertex.key];
472 console.log('Calling Google ASR API...');
473 context.exec('AGI', parameters.join(','),
479 methods.database = function(context, vertex, callback) {
480 console.log('--DATABASE BLOCK--');
481 if (!dbConnections) {
482 getDbConnections(false);
484 // console.log(vertex);
485 var connection = _.find(dbConnections, {
486 id: parseInt(vertex.odbc_id)
488 console.log('Trying to get ODBC connection...');
490 uniqueid: context.uniqueid,
492 application: vertex.tag,
493 data: vertex.query || null
496 .create(squareDetail)
497 .catch(function(err) {
498 console.log('Error saving ' + vertex.tag + ':' + vertex.label + ' block log', err);
500 db.open(connection.dsn, function(err) {
502 console.log('Connection opening error: ', err);
509 console.log('Connection succeded, executing query...');
510 db.query(vertex.query, function(err, data) {
512 console.log('Query error: ', err);
519 console.log('Query executed, closing connection...');
520 db.close(function(err) {
522 console.log('Connection closing error: ', err);
529 console.log('Connection closed, saving resulting rows in a variable...');
530 setVariable(context, vertex.variable_id, data, callback);
539 methods.gotoc = function(context, vertex, callback) {
540 console.log('--GOTO BLOCK--');
541 console.log('Going to extension ' + vertex.extension + ' ...');
542 context.exec('DIAL', util.format('Local/%s@%s', vertex.extension, vertex.context),
548 methods.gotoif = function(context, vertex, callback) {
549 console.log('--GOTOIF BLOCK--');
554 console.log('Evaluating condition...');
555 res.data = String(eval(vertex.condition) ? 'true' : 'false');
556 console.log('The result is ' + res.data);
560 methods.hangup = function(context, vertex, callback) {
561 console.log('--HANGUP BLOCK--');
562 console.log('Hangin up the call...');
566 methods.noop = function(context, vertex, callback) {
567 console.log('--NOOP BLOCK--');
568 var output = (vertex.output) ? '\"' + vertex.output + '\"' : '\"' +
570 console.log('NOOP value is ' + output);
571 context.exec('NOOP', output,
577 methods.saydigits = function(context, vertex, callback) {
578 console.log('--SAYDIGITS BLOCK--');
579 console.log('Saying digits...');
580 context.send(util.format('SAY DIGITS %s "%s"\n', vertex.digits, vertex.escape_digits),
586 methods.set = function(context, vertex, callback) {
587 console.log('--SET BLOCK--');
588 console.log('Saving value in a variable...');
589 setVariable(context, vertex.variable_id, vertex.variable_value, callback);
592 function getVertices(root) {
593 return _.reduce(root, function(result, edge, tag) {
595 if (tag === 'mxcell') {
599 if (_.isArray(edge)) {
600 _.forIn(edge, function(value, key) {
601 result[value.$.id] = value.$;
602 result[value.$.id].tag = tag;
607 result[edge.$.id] = edge.$;
608 result[edge.$.id].tag = tag;
614 function getTargetBySource(root, source, value) {
615 return _.result(_.find(root.mxcell, function(edge) {
616 if (edge.$.edge && edge.$.source) {
617 if (edge.$.source === source) {
618 if (edge.$.value && edge.$.value !== value) {
628 function replaceAllVariables(context, vertex, callback) {
630 for (var key in obj) {
631 var res = obj[key].match(/{+(.*?)}/gi);
634 for (var variable in res) {
635 var value = wait.forMethod(context, 'getVariable',
636 res[variable].substring(1, res[variable].length - 1));
637 if (value.code === 200 && value.result !== '0') {
638 var string = value.result.substring(value.result.lastIndexOf("(") + 1,
639 value.result.lastIndexOf(")"))
640 obj[key] = obj[key].replace(res[variable], string);
641 // console.log('Replace', res[variable], string);
650 function xstart(context) {
651 var root = context.root;
652 var vertices = context.vertices;
655 if (!_.isArray(root.start)) {
656 var source = root.start.$.id;
659 var vertex = vertices[source].replaced ? vertices[source] : replaceAllVariables(context, vertices[source]);
661 if (_.isFunction(methods[vertex.tag])) {
662 res = wait.for(methods[vertex.tag], context, vertex);
664 res = wait.for(methods.noop, context, vertex);
666 if (res.code === 200 && res.result !== '-1') {
667 var target = getTargetBySource(root, source, res.data);
668 if (target) {} else {
669 if (vertex.tag === 'menu') {
670 if (vertex.retry > 0) {
671 target = getTargetBySource(root, source, 'i');
672 if (target) {} else {
677 if (vertex.tag === 'getdigits' && vertex.retry > 0) {
690 console.log('No target found, hangup!');
696 function xfinally(context) {
697 var root = context.root;
698 var vertices = context.vertices;
701 if (!_.isArray(root.finally)) {
702 var source = root.finally.$.id;
705 var vertex = replaceAllVariables(context, vertices[source]);
707 if (_.isFunction(methods[vertex.tag])) {
708 res = wait.for(methods[vertex.tag], context, vertex);
710 res = wait.for(methods.noop, context, vertex);
712 if (res.code === 200 && res.result !== '-1') {
713 var target = getTargetBySource(root, source, res.data);
714 if (target) {} else {
715 if (vertex.tag === 'menu') {
716 if (vertex.retry > 0) {
717 target = getTargetBySource(root, source, 'i');
718 if (target) {} else {
723 if (vertex.tag === 'getdigits' && vertex.retry > 0) {
736 console.log('No target found, stopping "Finally" branch!');
743 function main(context) {
745 context.on('error', function(err) {
746 console.log('//Error:', err);
749 context.on('close', function() {
750 console.log('//Context close');
753 context.on('hangup', function() {
754 if (context.finally) {
755 context.finally = false;
756 console.log('//Starting "Finally" branch!');
757 wait.launchFiber(xfinally, context);
759 ReportSquare.update({
760 leaveAt: moment().format("YYYY-MM-DD HH:mm:ss")
763 uniqueid: context.uniqueid
766 .catch(function(err) {
767 console.log('Error saving exit time from IVR', err);
769 console.log('//Context Hangup');
773 context.on('response', function(res) {
774 //console.log('Response:', res);
777 context.on('variables', function(vars) {
779 console.log('Received new call from: ' + vars.agi_callerid +
780 ' with uniqueid: ' + vars.agi_uniqueid);
782 network: vars.agi_network,
783 network_script: vars.agi_network_script,
784 request: vars.agi_request,
785 channel: vars.agi_channel,
786 language: vars.agi_language,
788 uniqueid: vars.agi_uniqueid,
789 version: vars.agi_version,
790 callerid: vars.agi_callerid,
791 calleridname: vars.agi_calleridname,
792 callingpres: vars.agi_callingpres,
793 callingani2: vars.agi_callingani2,
794 callington: vars.agi_callington,
795 callingtns: vars.agi_callingtns,
797 rdnis: vars.agi_rdnis,
798 context: vars.agi_context,
799 extension: vars.agi_extension,
800 priority: vars.agi_priority,
801 enhanced: vars.agi_enhanced,
802 accountcode: vars.agi_accountcode,
803 threadid: vars.agi_threadid,
804 project_name: vars.agi_arg_1,
805 joinAt: moment().format("YYYY-MM-DD HH:mm:ss")
810 .catch(function(err) {
811 console.log('Error saving enter time for IVR', err);
814 if (vars.agi_arg_1) {
820 attributes: ['id', 'production']
822 .then(function(project) {
824 if (project.production) {
825 xml.parseString(project.production, {
828 }, function(err, result) {
829 var root = result.mxgraphmodel.root;
832 context.finally = true;
833 context.uniqueid = vars.agi_uniqueid;
834 context.vertices = getVertices(root);
835 wait.launchFiber(xstart, context);
837 console.log('No root in project!');
842 console.log('No project published!');
846 console.log('No project found!');
850 .catch(function(err) {
851 console.log('Error:', err);
855 console.log('No project argument!');
861 function splitInterval(interval) {
862 var finalInterval = {};
863 var splittedInterval = interval.split(',');
865 splittedInterval.forEach(function(element, index) {
868 if (element !== '*') {
869 intValues = element.split('-');
870 finalInterval.t_from = moment(intValues[0], 'HH:mm');
871 finalInterval.t_to = moment(intValues[1], 'HH:mm');
873 finalInterval.t_from = null;
874 finalInterval.t_to = null;
878 if (element !== '*') {
879 intValues = element.split('-');
880 finalInterval.wd_from = weekDaysCollection[intValues[0]];
881 finalInterval.wd_to = intValues[1] ? weekDaysCollection[intValues[1]] : null;
883 finalInterval.wd_from = null;
884 finalInterval.wd_to = null;
888 if (element !== '*') {
889 intValues = element.split('-');
890 finalInterval.md_from = intValues[0];
891 finalInterval.md_to = intValues[1] ? intValues[1] : null;
893 finalInterval.md_from = null;
894 finalInterval.md_to = null;
898 if (element !== '*') {
899 intValues = element.split('-');
900 finalInterval.m_from = monthsCollection[intValues[0]];
901 finalInterval.m_to = intValues[1] ? monthsCollection[intValues[1]] : null;
903 finalInterval.m_from = null;
904 finalInterval.m_to = null;
913 return finalInterval;
916 function isIntervalValid(interval) {
917 var hour = moment().format("HH:mm");
918 var day = moment().format("E");
919 var monthDay = moment().format("D");
920 var month = moment().format("M");
921 var tValid, wdValid, mdValid, mValid;
922 var monthsNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
923 var weekDaysNumbers = [1, 2, 3, 4, 5, 6, 7];
924 var daysOfMonthsNumbers = [];
925 for (var i = 1; i <= 31; i++) {
926 daysOfMonthsNumbers.push(i);
928 tValid = (interval.t_from && interval.t_to) ? moment(hour, "HH:mm").isBetween(moment(interval.t_from, "HH:mm"), moment(interval.t_to, "HH:mm")) : true;
929 if (interval.wd_from) {
930 if (interval.wd_to) {
931 var validWeekdays = _.filter(weekDaysNumbers, function(elem) {
932 return (elem >= interval.wd_from) || (elem <= interval.wd_to);
934 wdValid = (validWeekdays.indexOf(parseInt(day)) !== -1) ? true : false;
936 wdValid = (parseInt(day) === interval.wd_from) ? true : false;
941 if (interval.md_from) {
942 if (interval.md_to) {
943 var validMonthsdays = _.filter(daysOfMonthsNumbers, function(elem) {
944 return (elem >= interval.md_from) || (elem <= interval.md_to);
946 mdValid = (validMonthsdays.indexOf(parseInt(monthDay)) !== -1) ? true : false;
948 mdValid = (parseInt(monthDay) === interval.md_from) ? true : false;
953 if (interval.m_from) {
955 var validMonths = _.filter(monthsNumbers, function(elem) {
956 return (elem >= interval.m_from) || (elem <= interval.m_to);
958 mValid = (validMonths.indexOf(parseInt(month)) !== -1) ? true : false;
960 mValid = (parseInt(month) === interval.m_from) ? true : false;
966 return tValid && wdValid && mdValid && mValid;
970 function setVariable(context, id, value, callback) {
971 console.log('Setting variable...');
975 var variable = _.find(variables, {
978 console.log('Sending set variable, value is ', value);
979 context.send(util.format('SET VARIABLE %s %s\n', variable.name, value), function(err, res) {
986 function getVariable(context, id) {
990 var variable = _.find(variables, {
993 var value = wait.forMethod(context, 'getVariable', variable.name);
994 if (value.code === 200 && value.result !== '0') {
995 return value.result.substring(value.result.lastIndexOf("(") + 1,
996 value.result.lastIndexOf(")"));
1001 function getFilePath(id) {
1006 var file = _.find(sounds, {
1009 return util.format('%s/%s', file.converted_path, file.save_name);
1014 function getUsers(synch) {
1017 .then(function(result) {
1018 users = _.clone(result);
1020 synchUpdates(User, users, 'id');
1023 .catch(function(err) {
1028 function getQueues(synch) {
1031 .then(function(result) {
1032 queues = _.clone(result);
1034 synchUpdates(VoiceQueue, queues, 'name');
1037 .catch(function(err) {
1042 function getTrunks(synch) {
1045 .then(function(result) {
1046 trunks = _.clone(result);
1048 synchUpdates(Trunk, trunks, 'id');
1051 .catch(function(err) {
1056 function getVariables(synch) {
1059 .then(function(result) {
1060 variables = _.clone(result);
1062 synchUpdates(Variable, variables, 'id');
1065 .catch(function(err) {
1070 function getDbConnections(synch) {
1073 .then(function(result) {
1074 dbConnections = _.clone(result);
1076 synchUpdates(SquareOdbc, dbConnections, 'id');
1079 .catch(function(err) {
1084 function getIntervals(synch) {
1087 .then(function(result) {
1088 intervals = _.clone(result);
1090 synchUpdates(Interval, intervals, 'id');
1093 .catch(function(err) {
1098 function getProjects(synch) {
1101 .then(function(result) {
1102 projects = _.clone(result);
1104 synchUpdates(SquareProject, projects, 'id');
1107 .catch(function(err) {
1112 function getSounds(synch) {
1115 .then(function(result) {
1116 sounds = _.clone(result);
1118 synchUpdates(Upload, sounds, 'id');
1121 .catch(function(err) {
1126 function synchUpdates(Model, collection, key) {
1128 Model.afterCreate(function(doc) {
1129 condition[key] = doc[key];
1130 updateCollection(collection, condition, doc);
1132 Model.afterUpdate(function(doc) {
1133 condition[key] = doc[key];
1134 updateCollection(collection, condition, doc);
1136 Model.afterDestroy(function(doc) {
1137 condition[key] = doc[key];
1138 _.remove(collection, condition);
1142 function updateCollection(collection, condition, doc) {
1143 var oldItem = _.find(collection, condition);
1144 var index = collection.indexOf(oldItem);
1146 _.merge(collection[index], doc);
1148 collection.unshift(doc);
1152 function getPort() {
1155 .then(function(result) {
1156 agiPort = result.agi_port;
1158 .catch(function(err) {
1163 module.exports = function() {
1164 console.log('Starting Cally Square AGI...');
1166 var server = agi.createServer(main).listen(agiPort ? agiPort : 4573);
1174 getDbConnections(true);