@tiledesk/tiledesk-voice-twilio-connector 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1029 -0
- package/package.json +45 -0
- package/routes/manageApp.js +400 -0
- package/template/configure.html +355 -0
- package/template/css/configure.css +422 -0
- package/template/css/error.css +67 -0
- package/template/css/style.css +315 -0
- package/template/error.html +92 -0
- package/tiledesk/KVBaseMongo.js +102 -0
- package/tiledesk/TiledeskChannel.js +335 -0
- package/tiledesk/TiledeskSubscriptionClient.js +135 -0
- package/tiledesk/TiledeskTwilioTranslator.js +563 -0
- package/tiledesk/VoiceChannel.js +115 -0
- package/tiledesk/constants.js +38 -0
- package/tiledesk/utils-message.js +64 -0
- package/tiledesk/utils.js +16 -0
- package/winston.js +41 -0
package/index.js
ADDED
|
@@ -0,0 +1,1029 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const express = require("express");
|
|
3
|
+
const bodyParser = require("body-parser")
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
const winston = require("./winston");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const pjson = require('./package.json');
|
|
9
|
+
const axios = require("axios").default;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
router.use(bodyParser.json()); // support json encoded bodies
|
|
13
|
+
router.use(express.urlencoded({ extended: true })); // support encoded bodies
|
|
14
|
+
router.use(express.static(path.join(__dirname, 'template')));
|
|
15
|
+
|
|
16
|
+
//template
|
|
17
|
+
const manageApp = require('./routes/manageApp');
|
|
18
|
+
const manageRoute = manageApp.router;
|
|
19
|
+
router.use('/manage', manageRoute);
|
|
20
|
+
|
|
21
|
+
// tiledesk clients
|
|
22
|
+
const { TiledeskChannel } = require("./tiledesk/TiledeskChannel");
|
|
23
|
+
const { TiledeskTwilioTranslator } = require('./tiledesk/TiledeskTwilioTranslator');
|
|
24
|
+
|
|
25
|
+
//voice clients
|
|
26
|
+
const { VoiceChannel } = require("./tiledesk/VoiceChannel");
|
|
27
|
+
let voiceChannel = null;
|
|
28
|
+
|
|
29
|
+
// mongo
|
|
30
|
+
const { KVBaseMongo } = require('./tiledesk/KVBaseMongo');
|
|
31
|
+
const kvbase_collection = 'kvstore';
|
|
32
|
+
const db = new KVBaseMongo(kvbase_collection);
|
|
33
|
+
|
|
34
|
+
// redis
|
|
35
|
+
var redis = require('redis')
|
|
36
|
+
var redis_client;
|
|
37
|
+
|
|
38
|
+
//UTILS
|
|
39
|
+
const utils_message = require('./tiledesk/utils-message.js')
|
|
40
|
+
const CHANNEL_NAME = require('./tiledesk/constants').CHANNEL_NAME
|
|
41
|
+
const TYPE_MESSAGE = require('./tiledesk/constants').TYPE_MESSAGE
|
|
42
|
+
const CALL_STATUS = require('./tiledesk/constants').CALL_STATUS
|
|
43
|
+
const utils = require('./tiledesk/utils.js')
|
|
44
|
+
|
|
45
|
+
let API_URL = null;
|
|
46
|
+
let BASE_URL = null;
|
|
47
|
+
let REDIS_HOST = null;
|
|
48
|
+
let REDIS_PORT = null;
|
|
49
|
+
let REDIS_PASSWORD = null;
|
|
50
|
+
let BRAND_NAME = null;
|
|
51
|
+
|
|
52
|
+
let twilio = require('twilio');
|
|
53
|
+
const VoiceResponse = require('twilio').twiml.VoiceResponse;
|
|
54
|
+
const { MessagingResponse } = require('twilio').twiml;
|
|
55
|
+
|
|
56
|
+
router.get("/", async (req, res) => {
|
|
57
|
+
res.send("Welcome to Tiledesk-voice-twilio connector");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// TILEDESK WEBHOOK: message from tiledesk to user (chatbot/agent messagges)
|
|
62
|
+
router.post("/tiledesk", async (req, res) => {
|
|
63
|
+
let tiledeskMessage = req.body.payload
|
|
64
|
+
let project_id = tiledeskMessage.id_project
|
|
65
|
+
|
|
66
|
+
//const CONTENT_KEY = "vxml-" + project_id;
|
|
67
|
+
//let settings = await db.get(CONTENT_KEY)
|
|
68
|
+
|
|
69
|
+
const tdChannel = new TiledeskChannel({
|
|
70
|
+
API_URL: API_URL,
|
|
71
|
+
redis_client: redis_client
|
|
72
|
+
});
|
|
73
|
+
tdChannel.setProjectId(project_id)
|
|
74
|
+
|
|
75
|
+
await tdChannel.addMessageToQueue(tiledeskMessage)
|
|
76
|
+
|
|
77
|
+
res.send("(vxml) Message received from Voice VXML Proxy");
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// TWILIO WEBHOOK : message from user to tiledesk
|
|
83
|
+
router.post('/webhook/:id_project', async (req, res) => {
|
|
84
|
+
winston.debug('(voice) called POST /webhook/:id_project ', req.params)
|
|
85
|
+
|
|
86
|
+
let project_id = req.params.id_project;
|
|
87
|
+
let callSid = req.body.CallSid;
|
|
88
|
+
let from = req.body.From;
|
|
89
|
+
let to = req.body.To;
|
|
90
|
+
|
|
91
|
+
if(!from || !to){
|
|
92
|
+
return res.status(404).send({error: "Error: Missing from/to parameters"})
|
|
93
|
+
}
|
|
94
|
+
from = utils.getNumber(from); //remove '+' from number
|
|
95
|
+
to = utils.getNumber(to); //remove '+' from number
|
|
96
|
+
|
|
97
|
+
const CONTENT_KEY = CHANNEL_NAME + "-" + project_id;
|
|
98
|
+
let settings = await db.get(CONTENT_KEY);
|
|
99
|
+
if(!settings){
|
|
100
|
+
return res.status(404).send({error: "VOICE Channel not already connected"})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let vxmlAttributes = {
|
|
104
|
+
voiceName: "Polly.Bianca",
|
|
105
|
+
voiceLanguage: "it-IT",
|
|
106
|
+
callSid: callSid
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const tdChannel = new TiledeskChannel({
|
|
110
|
+
API_URL: API_URL,
|
|
111
|
+
redis_client: redis_client,
|
|
112
|
+
});
|
|
113
|
+
tdChannel.setProjectId(project_id)
|
|
114
|
+
|
|
115
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
116
|
+
BASE_URL: BASE_URL
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
let user = await tdChannel.signIn(from, settings);
|
|
120
|
+
if(!user){
|
|
121
|
+
res.status(401).send({message: "Cannot able to signIn with current caller phone :" + from});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//let conversation_id = await tdChannel.getConversation(ani, callId, user.token);
|
|
126
|
+
let conversation_id = await tdChannel.generateConversation(from, callSid, user.token);
|
|
127
|
+
winston.debug("(voice) conversation returned:"+ conversation_id);
|
|
128
|
+
|
|
129
|
+
//save data to redis
|
|
130
|
+
let session_data = {
|
|
131
|
+
from: from,
|
|
132
|
+
to: to,
|
|
133
|
+
callSid: callSid,
|
|
134
|
+
project_id: project_id,
|
|
135
|
+
user: user,
|
|
136
|
+
conversation_id: conversation_id
|
|
137
|
+
}
|
|
138
|
+
if (!redis_client) {
|
|
139
|
+
return res.status(500).send({ message: "Redis not ready. Check redis connection..." })
|
|
140
|
+
}
|
|
141
|
+
//for (const [key, value] of Object.entries(redis_data)){
|
|
142
|
+
// await redis_client.hSet('tiledesk:vxml:'+callId, key, JSON.stringify(value))
|
|
143
|
+
//}
|
|
144
|
+
//await redis_client.expire('tiledesk:vxml:'+callId, 86400)
|
|
145
|
+
|
|
146
|
+
await redis_client.set('tiledesk:vxml:'+callSid+':session', JSON.stringify(session_data), {'EX': 86400});
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
let tiledeskMessage= {
|
|
150
|
+
text:'/start',
|
|
151
|
+
senderFullname: from,
|
|
152
|
+
type: 'text',
|
|
153
|
+
attributes: {
|
|
154
|
+
subtype: 'info',
|
|
155
|
+
payload: {
|
|
156
|
+
... req.query //send all attributes back to chatbot
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
channel: { name: CHANNEL_NAME }
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
let message = await tdChannel.send(tiledeskMessage, user.token, conversation_id)
|
|
163
|
+
if(!message){
|
|
164
|
+
return res.status(503).send({ message: "Bad response: Quota exceeded" })
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
//generate Tiledesk wait message
|
|
169
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
170
|
+
let waitTiledeskMessage = await tdChannel.generateWaitTdMessage(from, delayTime)
|
|
171
|
+
//update delayIndex for wait command message time
|
|
172
|
+
await voiceChannel.saveDelayIndexForCallId(from)
|
|
173
|
+
|
|
174
|
+
// send standard wait vxml message
|
|
175
|
+
let messageToVXML = await tdTranslator.toVXML(waitTiledeskMessage, callSid, vxmlAttributes)
|
|
176
|
+
winston.debug('(voice) messageVXML-->'+ messageToVXML)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// Render the response as XML in reply to the webhook request
|
|
180
|
+
res.set('Content-Type', 'text/xml');
|
|
181
|
+
res.status(200).send(messageToVXML);
|
|
182
|
+
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
router.post('/nextblock/:callSid/', async(req, res) => {
|
|
187
|
+
winston.info("(vxml) called POST /nextblock" , req.body);
|
|
188
|
+
winston.info("(vxml) called POST /nextblock query", req.query);
|
|
189
|
+
|
|
190
|
+
let usertext = req.body.SpeechResult;
|
|
191
|
+
let confidence = req.body.Confidence
|
|
192
|
+
let callSid = req.params.callSid;
|
|
193
|
+
|
|
194
|
+
let sessionInfo;
|
|
195
|
+
let project_id, conversation_id, user;
|
|
196
|
+
let from, to;
|
|
197
|
+
|
|
198
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
199
|
+
//let redis_data = await redis_client.hGetAll('tiledesk:vxml:'+callId);
|
|
200
|
+
if (!redis_data) {
|
|
201
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
202
|
+
}
|
|
203
|
+
sessionInfo = JSON.parse(redis_data)
|
|
204
|
+
project_id = sessionInfo.project_id;
|
|
205
|
+
from = sessionInfo.from;
|
|
206
|
+
to = sessionInfo.to;
|
|
207
|
+
conversation_id = sessionInfo.conversation_id;
|
|
208
|
+
user = sessionInfo.user;
|
|
209
|
+
|
|
210
|
+
let vxmlAttributes = {
|
|
211
|
+
voiceName: "Polly.Bianca",
|
|
212
|
+
voiceLanguage: "it-IT",
|
|
213
|
+
callSid: callSid,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const tdChannel = new TiledeskChannel({
|
|
217
|
+
API_URL: API_URL,
|
|
218
|
+
redis_client: redis_client
|
|
219
|
+
})
|
|
220
|
+
tdChannel.setProjectId(project_id);
|
|
221
|
+
|
|
222
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
223
|
+
BASE_URL: BASE_URL
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
//manage SPEECH FORM with <record>
|
|
228
|
+
|
|
229
|
+
//se coda vuota (esiste)
|
|
230
|
+
//manda vxml wait
|
|
231
|
+
//se usertext vuoto e coda ha almeno un elemento
|
|
232
|
+
// genera vxml su quel messaggio
|
|
233
|
+
//se usertet non vuoto e coda non esiste
|
|
234
|
+
//crea coda e manda messaggio su conversazione
|
|
235
|
+
|
|
236
|
+
let message = {}, queue = []
|
|
237
|
+
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
238
|
+
winston.debug('/NEXT controllo coda--> ', queue.length, usertext)
|
|
239
|
+
if(queue.length === 0 && (usertext === '' || !usertext)){
|
|
240
|
+
winston.debug('QUEUE is empty--> ',queue)
|
|
241
|
+
|
|
242
|
+
//CASE: queue is empty --> generate Tiledesk wait message and manage delayTime
|
|
243
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
244
|
+
message = await tdChannel.generateWaitTdMessage(from, delayTime)
|
|
245
|
+
//update delayIndex for wait command message time
|
|
246
|
+
await voiceChannel.saveDelayIndexForCallId(from)
|
|
247
|
+
|
|
248
|
+
} else if(queue.length > 0 && (usertext === '' || !usertext)){
|
|
249
|
+
|
|
250
|
+
//CASE: queue has at least one message to reproduce --> get message from tiledesk queue and reset delayTime
|
|
251
|
+
message = queue[0]
|
|
252
|
+
winston.debug('QUEUE --> ',queue[0])
|
|
253
|
+
//remove message from queue
|
|
254
|
+
await tdChannel.removeMessageFromQueue(conversation_id, message._id)
|
|
255
|
+
//reset delayIndex for wait command message time
|
|
256
|
+
await voiceChannel.clearDelayTimeForCallId(callSid)
|
|
257
|
+
|
|
258
|
+
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
259
|
+
winston.debug('QUEUE after remove --> ',queue.length)
|
|
260
|
+
}else{
|
|
261
|
+
//CASE:usertext is not empty and queue is empty --> send message to tiledesk and manage delayTime
|
|
262
|
+
let tiledeskMessage= {
|
|
263
|
+
text:usertext,
|
|
264
|
+
senderFullname: from,
|
|
265
|
+
type: 'text',
|
|
266
|
+
channel: { name: CHANNEL_NAME }
|
|
267
|
+
};
|
|
268
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
269
|
+
winston.debug("message sent : ", tdMessage);
|
|
270
|
+
//generate Tiledesk wait message
|
|
271
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
272
|
+
message = await tdChannel.generateWaitTdMessage(from, delayTime)
|
|
273
|
+
//update delayIndex for wait command message time
|
|
274
|
+
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/*
|
|
278
|
+
if(usertext === '' || !usertext){
|
|
279
|
+
//get message from queue
|
|
280
|
+
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
281
|
+
winston.debug('QUEUE --> ',queue.length)
|
|
282
|
+
if(queue.length === 0){
|
|
283
|
+
//CASE: queue is empty --> generate Tiledesk wait message
|
|
284
|
+
message = await tdChannel.generateWaitTdMessage(ani, callId)
|
|
285
|
+
winston.debug('QUEUE is empty--> ',queue)
|
|
286
|
+
}else{
|
|
287
|
+
//CASE: queue has at least one message to reproduce --> get message from tiledesk queue
|
|
288
|
+
message = queue[0]
|
|
289
|
+
winston.debug('QUEUE --> ',queue[0])
|
|
290
|
+
//remove message from queue
|
|
291
|
+
await tdChannel.removeMessageFromQueue(conversation_id, message._id)
|
|
292
|
+
|
|
293
|
+
queue = await tdChannel.getMessagesFromQueue(conversation_id)
|
|
294
|
+
winston.debug('QUEUE after remove --> ',queue.length)
|
|
295
|
+
}
|
|
296
|
+
}else{
|
|
297
|
+
//send message to tiledesk
|
|
298
|
+
let tiledeskMessage= {
|
|
299
|
+
text:usertext,
|
|
300
|
+
senderFullname: ani,
|
|
301
|
+
type: 'text',
|
|
302
|
+
channel: { name: CHANNEL_NAME }
|
|
303
|
+
};
|
|
304
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
305
|
+
winston.debug("message sent : ", tdMessage);
|
|
306
|
+
//generate Tiledesk wait message
|
|
307
|
+
message = await tdChannel.generateWaitTdMessage(ani, callId)
|
|
308
|
+
}
|
|
309
|
+
*/
|
|
310
|
+
|
|
311
|
+
// convert response to vxml
|
|
312
|
+
let messageToVXML = await tdTranslator.toVXML(message, callSid, vxmlAttributes)
|
|
313
|
+
winston.debug("(vxml) VXML to SEND: "+ messageToVXML);
|
|
314
|
+
|
|
315
|
+
// Render the response as XML in reply to the webhook request
|
|
316
|
+
res.set('Content-Type', 'text/xml');
|
|
317
|
+
res.status(200).send(messageToVXML);
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
router.post('/menublock/:callSid', async (req, res) => {
|
|
322
|
+
winston.info("(voice) called POST /menu", req.body);
|
|
323
|
+
winston.info("(voice) called POST /menu query" , req.query);
|
|
324
|
+
|
|
325
|
+
let message_text = '';
|
|
326
|
+
let attributes = {};
|
|
327
|
+
let button = {}
|
|
328
|
+
|
|
329
|
+
let callSid = req.params.callSid;
|
|
330
|
+
let buttons_menu = req.query.menu_options;
|
|
331
|
+
let buttonNoMatch = req.query.button_action;
|
|
332
|
+
let previousIntentName = req.query.intentName;
|
|
333
|
+
|
|
334
|
+
let menu_choice = req.body.Digits || '';
|
|
335
|
+
|
|
336
|
+
/** use case: DTMF MENU **/
|
|
337
|
+
if(buttons_menu){
|
|
338
|
+
buttons_menu.split(';').some((option)=> {
|
|
339
|
+
option = option.split(':')
|
|
340
|
+
if(option[0] === menu_choice){
|
|
341
|
+
button.value = option[0]
|
|
342
|
+
button.action = '#' + option[1]
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
/* case noMatch input: Digits is not in a valid menu option*/
|
|
349
|
+
if(Object.keys(button).length === 0){
|
|
350
|
+
button.value = menu_choice
|
|
351
|
+
button.action = '#' + buttonNoMatch
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
message_text = button.value.toString();
|
|
355
|
+
attributes = {
|
|
356
|
+
action: button.action
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
}else{
|
|
360
|
+
/** use case: DTMF Speech **/
|
|
361
|
+
message_text = menu_choice.toString(); //.replace(/(\d)/g, '$1 '); //convert number to string and then add a space after each number
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
winston.debug("(vxml) button menu: ", button);
|
|
365
|
+
winston.debug("(vxml) message_text menu: "+ message_text);
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
let sessionInfo;
|
|
369
|
+
let project_id, conversation_id, user;
|
|
370
|
+
let from, to;
|
|
371
|
+
|
|
372
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
373
|
+
if (!redis_data) {
|
|
374
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
375
|
+
}
|
|
376
|
+
sessionInfo = JSON.parse(redis_data)
|
|
377
|
+
project_id = sessionInfo.project_id;
|
|
378
|
+
from = sessionInfo.from;
|
|
379
|
+
to = sessionInfo.to;
|
|
380
|
+
conversation_id = sessionInfo.conversation_id;
|
|
381
|
+
user = sessionInfo.user;
|
|
382
|
+
|
|
383
|
+
let vxmlAttributes = {
|
|
384
|
+
voiceName: "Polly.Bianca",
|
|
385
|
+
voiceLanguage: "it-IT",
|
|
386
|
+
callSid: callSid,
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const tdChannel = new TiledeskChannel({
|
|
390
|
+
API_URL: API_URL,
|
|
391
|
+
redis_client: redis_client
|
|
392
|
+
})
|
|
393
|
+
tdChannel.setProjectId(project_id);
|
|
394
|
+
|
|
395
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
396
|
+
BASE_URL: BASE_URL
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
//send message to tiledesk
|
|
400
|
+
let tiledeskMessage= {
|
|
401
|
+
text:message_text,
|
|
402
|
+
senderFullname: from,
|
|
403
|
+
type: 'text',
|
|
404
|
+
channel: { name: CHANNEL_NAME },
|
|
405
|
+
attributes: attributes
|
|
406
|
+
};
|
|
407
|
+
console.log('messssss', tiledeskMessage)
|
|
408
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
409
|
+
|
|
410
|
+
//generate Tiledesk wait message
|
|
411
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
412
|
+
let message = await tdChannel.generateWaitTdMessage(from, delayTime)
|
|
413
|
+
//update delayIndex for wait command message time
|
|
414
|
+
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
415
|
+
|
|
416
|
+
// convert response to vxml
|
|
417
|
+
let messageToVXML = await tdTranslator.toVXML(message, callSid, vxmlAttributes)
|
|
418
|
+
winston.debug("(voice) VXML to SEND: "+ messageToVXML);
|
|
419
|
+
|
|
420
|
+
res.set('Content-Type', 'text/xml');
|
|
421
|
+
res.status(200).send(messageToVXML);
|
|
422
|
+
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
router.post('/handle/:callSid/:event', async (req, res) => {
|
|
426
|
+
winston.info("(voice) called POST /handle", req.body);
|
|
427
|
+
winston.info("(voice) called POST /handle query -->", req.query);
|
|
428
|
+
winston.info("(voice) called POST /handle params-->", req.params);
|
|
429
|
+
|
|
430
|
+
let event = req.params.event;
|
|
431
|
+
let callSid = req.params.callSid;
|
|
432
|
+
let button_action = '#' + req.query.button_action;
|
|
433
|
+
let previousIntentName = req.query.intentName;
|
|
434
|
+
|
|
435
|
+
let sessionInfo;
|
|
436
|
+
let project_id, conversation_id, user;
|
|
437
|
+
let from, to;
|
|
438
|
+
|
|
439
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
440
|
+
if (!redis_data) {
|
|
441
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
442
|
+
}
|
|
443
|
+
sessionInfo = JSON.parse(redis_data)
|
|
444
|
+
project_id = sessionInfo.project_id;
|
|
445
|
+
from = sessionInfo.from;
|
|
446
|
+
to = sessionInfo.to;
|
|
447
|
+
conversation_id = sessionInfo.conversation_id;
|
|
448
|
+
user = sessionInfo.user;
|
|
449
|
+
|
|
450
|
+
let vxmlAttributes = {
|
|
451
|
+
voiceName: "Polly.Bianca",
|
|
452
|
+
voiceLanguage: "it-IT",
|
|
453
|
+
callSid: callSid,
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const tdChannel = new TiledeskChannel({
|
|
457
|
+
API_URL: API_URL,
|
|
458
|
+
redis_client: redis_client
|
|
459
|
+
})
|
|
460
|
+
tdChannel.setProjectId(project_id);
|
|
461
|
+
|
|
462
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
463
|
+
BASE_URL: BASE_URL
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
//send message to tiledesk
|
|
468
|
+
let tiledeskMessage= {
|
|
469
|
+
text: "/" + event,
|
|
470
|
+
senderFullname: from,
|
|
471
|
+
type: 'text',
|
|
472
|
+
channel: { name: CHANNEL_NAME },
|
|
473
|
+
attributes: {
|
|
474
|
+
type: 'info',
|
|
475
|
+
action: button_action
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
479
|
+
|
|
480
|
+
//generate Tiledesk wait message
|
|
481
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
482
|
+
let message = await tdChannel.generateWaitTdMessage(callSid, delayTime)
|
|
483
|
+
///update delayIndex for wait command message time
|
|
484
|
+
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
485
|
+
|
|
486
|
+
// convert response to vxml
|
|
487
|
+
let messageToVXML = await tdTranslator.toVXML(message, callSid, vxmlAttributes)
|
|
488
|
+
winston.debug("(vxml) VXML to SEND: "+ messageToVXML);
|
|
489
|
+
|
|
490
|
+
res.set('Content-Type', 'text/xml');
|
|
491
|
+
res.status(200).send(messageToVXML);
|
|
492
|
+
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
/* ----> catch Event block <----- */
|
|
497
|
+
router.post('/event/:callSid/:event', async(req, res)=> {
|
|
498
|
+
winston.info("(voice) called POST /event" , req.params);
|
|
499
|
+
winston.debug("(voice) called POST /event query" , req.query);
|
|
500
|
+
winston.debug("(voice) called POST /event body" , req.body);
|
|
501
|
+
|
|
502
|
+
let event = req.params.event;
|
|
503
|
+
let callSid = req.params.callSid;
|
|
504
|
+
let currentIntentName = req.query.intentName;
|
|
505
|
+
let currentIntentTimestamp = req.query.previousIntentTimestamp;
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
let sessionInfo;
|
|
509
|
+
let project_id, conversation_id, user;
|
|
510
|
+
let from, to;
|
|
511
|
+
|
|
512
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
513
|
+
if (!redis_data) {
|
|
514
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
515
|
+
}
|
|
516
|
+
sessionInfo = JSON.parse(redis_data)
|
|
517
|
+
project_id = sessionInfo.project_id;
|
|
518
|
+
from = sessionInfo.from;
|
|
519
|
+
to = sessionInfo.to;
|
|
520
|
+
conversation_id = sessionInfo.conversation_id;
|
|
521
|
+
user = sessionInfo.user;
|
|
522
|
+
|
|
523
|
+
let vxmlAttributes = {
|
|
524
|
+
voiceName: "Polly.Bianca",
|
|
525
|
+
voiceLanguage: "it-IT",
|
|
526
|
+
callSid: callSid,
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const tdChannel = new TiledeskChannel({
|
|
530
|
+
API_URL: API_URL,
|
|
531
|
+
redis_client: redis_client
|
|
532
|
+
})
|
|
533
|
+
tdChannel.setProjectId(project_id);
|
|
534
|
+
|
|
535
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
536
|
+
BASE_URL: BASE_URL
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
let button_action = ''
|
|
540
|
+
if(event === 'transfer'){
|
|
541
|
+
let callStatus = req.body.CallStatus;
|
|
542
|
+
switch(callStatus){
|
|
543
|
+
case CALL_STATUS.COMPLETED:
|
|
544
|
+
button_action = '#' + req.query.button_success;
|
|
545
|
+
break;
|
|
546
|
+
case CALL_STATUS.FAILED:
|
|
547
|
+
button_action = '#' + req.query.button_failure;
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
switch(callStatus){
|
|
552
|
+
case CALL_STATUS.COMPLETED:
|
|
553
|
+
case CALL_STATUS.FAILED: {
|
|
554
|
+
//send message to tiledesk
|
|
555
|
+
let tiledeskMessage= {
|
|
556
|
+
//text:'\\close',
|
|
557
|
+
text:'/'+event,
|
|
558
|
+
senderFullname: from,
|
|
559
|
+
type: 'text',
|
|
560
|
+
channel: { name: CHANNEL_NAME },
|
|
561
|
+
attributes: {
|
|
562
|
+
subtype: "info",
|
|
563
|
+
action: button_action,
|
|
564
|
+
payload: {
|
|
565
|
+
event: event,
|
|
566
|
+
lastBlock: currentIntentName,
|
|
567
|
+
lastTimestamp: currentIntentTimestamp
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
//generate Tiledesk wait message
|
|
579
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
580
|
+
let message = await tdChannel.generateWaitTdMessage(callSid, delayTime)
|
|
581
|
+
///update delayIndex for wait command message time
|
|
582
|
+
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
583
|
+
|
|
584
|
+
// convert response to vxml
|
|
585
|
+
let messageToVXML = await tdTranslator.toVXML(message, callSid, vxmlAttributes)
|
|
586
|
+
winston.debug("(vxml) VXML to SEND: "+ messageToVXML);
|
|
587
|
+
|
|
588
|
+
res.set('Content-Type', 'text/xml');
|
|
589
|
+
res.status(200).send(messageToVXML);
|
|
590
|
+
})
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
/* ----> catch Twilio Events <----- */
|
|
594
|
+
router.post('/twilio/status',async (req, res) => {
|
|
595
|
+
winston.debug('+++++++++++(voice) called POST twilio/status ', req.body);
|
|
596
|
+
|
|
597
|
+
let event = req.body.CallStatus;
|
|
598
|
+
let callSid = req.body.CallSid;
|
|
599
|
+
|
|
600
|
+
let sessionInfo;
|
|
601
|
+
let project_id, conversation_id, user;
|
|
602
|
+
let from, to;
|
|
603
|
+
|
|
604
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
605
|
+
if (!redis_data) {
|
|
606
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
607
|
+
}
|
|
608
|
+
sessionInfo = JSON.parse(redis_data)
|
|
609
|
+
project_id = sessionInfo.project_id;
|
|
610
|
+
from = sessionInfo.from;
|
|
611
|
+
to = sessionInfo.to;
|
|
612
|
+
conversation_id = sessionInfo.conversation_id;
|
|
613
|
+
user = sessionInfo.user;
|
|
614
|
+
|
|
615
|
+
let vxmlAttributes = {
|
|
616
|
+
voiceName: "Polly.Bianca",
|
|
617
|
+
voiceLanguage: "it-IT",
|
|
618
|
+
callSid: callSid,
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
const tdChannel = new TiledeskChannel({
|
|
622
|
+
API_URL: API_URL,
|
|
623
|
+
redis_client: redis_client
|
|
624
|
+
})
|
|
625
|
+
tdChannel.setProjectId(project_id)
|
|
626
|
+
|
|
627
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
628
|
+
BASE_URL: BASE_URL
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
switch(event){
|
|
633
|
+
case CALL_STATUS.COMPLETED:{
|
|
634
|
+
//send message to tiledesk
|
|
635
|
+
let tiledeskMessage= {
|
|
636
|
+
//text:'\\close',
|
|
637
|
+
text:'/close',
|
|
638
|
+
senderFullname: from,
|
|
639
|
+
type: 'text',
|
|
640
|
+
channel: { name: CHANNEL_NAME },
|
|
641
|
+
attributes: {
|
|
642
|
+
subtype: "info",
|
|
643
|
+
action: 'close'+JSON.stringify({event: event}),
|
|
644
|
+
payload: {
|
|
645
|
+
catchEvent: event
|
|
646
|
+
},
|
|
647
|
+
timestamp: 'xxxxxx'
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
652
|
+
|
|
653
|
+
//remove session data for current callId and relative queue data
|
|
654
|
+
await redis_client.del('tiledesk:vxml:'+callSid+':session');
|
|
655
|
+
await redis_client.del('tiledesk:vxml:'+callSid+':delayIndex');
|
|
656
|
+
await tdChannel.clearQueue(conversation_id);
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
res.status(200).send();
|
|
662
|
+
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
router.post('/twilio/fail',async (req, res) => {
|
|
666
|
+
winston.debug('+++++++++++(voice) called POST twilio/fail ', req.params)
|
|
667
|
+
winston.debug('+++++++++++(voice) called POST twilio/fail ', req.body)
|
|
668
|
+
|
|
669
|
+
res.set('Content-Type', 'text/xml');
|
|
670
|
+
res.status(200).send('<Response></Response>');
|
|
671
|
+
})
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
/* ----> catch Twilio Events <----- */
|
|
675
|
+
router.post('/record/:callSid/',async (req, res) => {
|
|
676
|
+
winston.debug('+++++++++++(voice) called POST record/:callSid ', req.body);
|
|
677
|
+
|
|
678
|
+
let callSid = req.body.CallSid;
|
|
679
|
+
|
|
680
|
+
let sessionInfo;
|
|
681
|
+
let project_id, conversation_id, user;
|
|
682
|
+
let from, to;
|
|
683
|
+
|
|
684
|
+
let redis_data = await redis_client.get('tiledesk:vxml:'+callSid+':session');
|
|
685
|
+
if (!redis_data) {
|
|
686
|
+
return res.status(500).send({ success: "false", message: "Can't retrive data for callSid ->" + callSid });
|
|
687
|
+
}
|
|
688
|
+
sessionInfo = JSON.parse(redis_data)
|
|
689
|
+
project_id = sessionInfo.project_id;
|
|
690
|
+
from = sessionInfo.from;
|
|
691
|
+
to = sessionInfo.to;
|
|
692
|
+
conversation_id = sessionInfo.conversation_id;
|
|
693
|
+
user = sessionInfo.user;
|
|
694
|
+
|
|
695
|
+
let vxmlAttributes = {
|
|
696
|
+
voiceName: "Polly.Bianca",
|
|
697
|
+
voiceLanguage: "it-IT",
|
|
698
|
+
callSid: callSid,
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
const tdChannel = new TiledeskChannel({
|
|
702
|
+
API_URL: API_URL,
|
|
703
|
+
redis_client: redis_client
|
|
704
|
+
})
|
|
705
|
+
tdChannel.setProjectId(project_id)
|
|
706
|
+
|
|
707
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
708
|
+
BASE_URL: BASE_URL
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
let audioFileUrl = req.body.RecordingUrl
|
|
713
|
+
let textMessage = await tdChannel.speechToText(audioFileUrl, 'whisper-1')
|
|
714
|
+
winston.debug('(voice) Message captured after STT -->', textMessage)
|
|
715
|
+
|
|
716
|
+
if(!textMessage){
|
|
717
|
+
//case NO_INPUT
|
|
718
|
+
const queryString = utils.buildQueryString(req.query);
|
|
719
|
+
console.log('case no input.. redirect '+ queryString)
|
|
720
|
+
|
|
721
|
+
return await axios({
|
|
722
|
+
url: "http://localhost:3000/handle/" + callSid + '/no_input'+ queryString,
|
|
723
|
+
headers: req.headers,
|
|
724
|
+
data: req.body,
|
|
725
|
+
method: 'POST'
|
|
726
|
+
}).then((response) => {
|
|
727
|
+
winston.debug("[TiledeskChannel] speechToText response : ", response.data);
|
|
728
|
+
return res.status(response.status).send(response.data);
|
|
729
|
+
}).catch((err) => {
|
|
730
|
+
winston.error("[TiledeskChannel] speechToText error: ", err);
|
|
731
|
+
return res.status(500).send({ success: false, message: "Errore while redirect to /handle for callSid " + callSid});;
|
|
732
|
+
})
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
let tiledeskMessage= {
|
|
737
|
+
text:textMessage,
|
|
738
|
+
senderFullname: from,
|
|
739
|
+
type: 'text',
|
|
740
|
+
channel: { name: CHANNEL_NAME }
|
|
741
|
+
};
|
|
742
|
+
let tdMessage = await tdChannel.send(tiledeskMessage, user.token, conversation_id);
|
|
743
|
+
winston.debug("message sent : ", tdMessage);
|
|
744
|
+
//generate Tiledesk wait message
|
|
745
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid)
|
|
746
|
+
let message = await tdChannel.generateWaitTdMessage(from, delayTime)
|
|
747
|
+
//update delayIndex for wait command message time
|
|
748
|
+
await voiceChannel.saveDelayIndexForCallId(callSid)
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
res.set('Content-Type', 'application/xml');
|
|
753
|
+
res.status(200).send(message);
|
|
754
|
+
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
/** --> only for test purpose <-- **/
|
|
759
|
+
router.get('/test', async (req, res) => {
|
|
760
|
+
winston.info("(vxml) called GET /test" , req.query);
|
|
761
|
+
|
|
762
|
+
let project_id = req.query.id_project;
|
|
763
|
+
let callSid = req.body.CallSid;
|
|
764
|
+
let from = req.body.From;
|
|
765
|
+
let to = req.body.To;
|
|
766
|
+
|
|
767
|
+
if(!from || !to){
|
|
768
|
+
return res.status(404).send({error: "Error: Missing from/to parameters"})
|
|
769
|
+
}
|
|
770
|
+
from = utils.getNumber(from); //remove '+' from number
|
|
771
|
+
to = utils.getNumber(to); //remove '+' from number
|
|
772
|
+
|
|
773
|
+
const tdChannel = new TiledeskChannel({
|
|
774
|
+
API_URL: API_URL,
|
|
775
|
+
redis_client: redis_client,
|
|
776
|
+
});
|
|
777
|
+
tdChannel.setProjectId(project_id)
|
|
778
|
+
|
|
779
|
+
const tdTranslator = new TiledeskTwilioTranslator({
|
|
780
|
+
BASE_URL: BASE_URL
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
//let result = await tdChannel.signIn(ani)
|
|
784
|
+
|
|
785
|
+
//let conversation_id = await tdChannel.getConversation(ani, callId, result.token);
|
|
786
|
+
//let message = await tdChannel.sendMessageAndWait(ani, result.chat21.user_data, conversation_id, '/start');
|
|
787
|
+
let delayTime = await voiceChannel.getNextDelayTimeForCallId(callSid);
|
|
788
|
+
let waitTiledeskMessage = await tdChannel.generateWaitTdMessage(from, delayTime);
|
|
789
|
+
|
|
790
|
+
//console.log("response message: ", message);
|
|
791
|
+
let message2= {
|
|
792
|
+
attributes: {
|
|
793
|
+
commands: [
|
|
794
|
+
{
|
|
795
|
+
type: 'wait',
|
|
796
|
+
time: 500
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
type: 'message',
|
|
800
|
+
message: {
|
|
801
|
+
text: 'ciao',
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
]
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
let message_buttons = {
|
|
809
|
+
attributes: {
|
|
810
|
+
disableInputMessage: true,
|
|
811
|
+
commands: [
|
|
812
|
+
{
|
|
813
|
+
type: 'wait',
|
|
814
|
+
time: 500
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
type: 'message',
|
|
818
|
+
message: {
|
|
819
|
+
text: 'ciao',
|
|
820
|
+
type: 'text',
|
|
821
|
+
attributes: {
|
|
822
|
+
attachment: {
|
|
823
|
+
buttons: [
|
|
824
|
+
{value: 'button1', type: 'action', target: 'blank', action: '#action1'},
|
|
825
|
+
{value: 'button2', type: 'action', target: 'blank', action: '#action2'}
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
type: 'wait',
|
|
833
|
+
time: 500
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
type: 'message',
|
|
837
|
+
message: {
|
|
838
|
+
text: 'ciao 2',
|
|
839
|
+
type: 'frame',
|
|
840
|
+
metadata: {
|
|
841
|
+
src:"https://your-audio-url.com"
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
type: 'wait',
|
|
847
|
+
time: 0
|
|
848
|
+
},
|
|
849
|
+
/*{
|
|
850
|
+
type: 'settings',
|
|
851
|
+
subType: 'blind_transfer',
|
|
852
|
+
settings: {
|
|
853
|
+
transferTo: "6040",
|
|
854
|
+
transferType: "consultation",
|
|
855
|
+
falseIntent: "#falseIntenttt",
|
|
856
|
+
trueIntent: "#trueIntennt"
|
|
857
|
+
}
|
|
858
|
+
}*/
|
|
859
|
+
/*{
|
|
860
|
+
type: 'settings',
|
|
861
|
+
subType: 'dtmf_form',
|
|
862
|
+
settings: {
|
|
863
|
+
minDigits: 5,
|
|
864
|
+
maxDigits: 5,
|
|
865
|
+
terminators: "#"
|
|
866
|
+
}
|
|
867
|
+
}*/
|
|
868
|
+
{
|
|
869
|
+
type: 'settings',
|
|
870
|
+
subType: 'speech_form',
|
|
871
|
+
settings: {
|
|
872
|
+
noInputIntent: "#a",
|
|
873
|
+
noInputTimeout: 2000,
|
|
874
|
+
incompleteSpeechTimeout: 2000
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
]
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
let vxmlAttributes = {
|
|
883
|
+
voiceName: "Polly.Bianca",
|
|
884
|
+
voiceLanguage: "it-IT",
|
|
885
|
+
callSid: callSid
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
// convert response to vxml
|
|
891
|
+
let messageToVXML = await tdTranslator.toVXML(message_buttons, callSid, vxmlAttributes)
|
|
892
|
+
//let disconnect = await tdChannel.disconnect();
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
res.set('Content-Type', 'text/xml');
|
|
896
|
+
res.status(200).send(messageToVXML);
|
|
897
|
+
|
|
898
|
+
//res.status(200).send(message);
|
|
899
|
+
|
|
900
|
+
})
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
async function connectRedis() {
|
|
904
|
+
/*redis_client = await redis.createClient({
|
|
905
|
+
host: REDIS_HOST,
|
|
906
|
+
port: REDIS_PORT,
|
|
907
|
+
password: REDIS_PASSWORD
|
|
908
|
+
});*/
|
|
909
|
+
|
|
910
|
+
if(REDIS_PASSWORD){
|
|
911
|
+
redis_client = await redis.createClient({
|
|
912
|
+
socket: {
|
|
913
|
+
host: REDIS_HOST,
|
|
914
|
+
port: REDIS_PORT
|
|
915
|
+
},
|
|
916
|
+
password: REDIS_PASSWORD,
|
|
917
|
+
})
|
|
918
|
+
}else {
|
|
919
|
+
redis_client = await redis.createClient({
|
|
920
|
+
url: 'redis://'+REDIS_HOST+':'+REDIS_PORT
|
|
921
|
+
})
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
redis_client.on('error', err => {
|
|
926
|
+
winston.info('(voice) Connect Redis Error ' + err);
|
|
927
|
+
})
|
|
928
|
+
/*
|
|
929
|
+
redis_client.on('connect', () => {
|
|
930
|
+
winston.info('Redis Connected!'); // Connected!
|
|
931
|
+
});
|
|
932
|
+
*/
|
|
933
|
+
redis_client.on('ready', () => {
|
|
934
|
+
winston.info("(voice) Redis ready!")
|
|
935
|
+
})
|
|
936
|
+
await redis_client.connect(); // only for v4
|
|
937
|
+
require('bluebird').promisifyAll(redis_client)
|
|
938
|
+
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
async function startApp(settings, callback) {
|
|
942
|
+
winston.info("(voice) Starting VOICE TWILIO App");
|
|
943
|
+
|
|
944
|
+
if (!settings.MONGODB_URI) {
|
|
945
|
+
winston.error("(voice) MONGODB_URI is mandatory. Exit...");
|
|
946
|
+
return callback('Missing parameter: MONGODB_URI');
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (!settings.API_URL) {
|
|
950
|
+
winston.error("(voice) API_URL is mandatory. Exit...");
|
|
951
|
+
return callback('Missing parameter: API_URL');
|
|
952
|
+
} else {
|
|
953
|
+
API_URL = settings.API_URL;
|
|
954
|
+
winston.info("(voice) API_URL: " + API_URL);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if (!settings.BASE_URL) {
|
|
958
|
+
winston.error("(voice) BASE_URL is mandatory. Exit...");
|
|
959
|
+
return callback('Missing parameter: BASE_URL');
|
|
960
|
+
} else {
|
|
961
|
+
BASE_URL = settings.BASE_URL;
|
|
962
|
+
winston.info("(voice) BASE_URL: " + BASE_URL);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
if (settings.BRAND_NAME) {
|
|
966
|
+
BRAND_NAME = settings.BRAND_NAME
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
if (settings.REDIS_HOST && settings.REDIS_PORT) {
|
|
970
|
+
REDIS_HOST = settings.REDIS_HOST;
|
|
971
|
+
REDIS_PORT = settings.REDIS_PORT;
|
|
972
|
+
REDIS_PASSWORD = settings.REDIS_PASSWORD;
|
|
973
|
+
await connectRedis();
|
|
974
|
+
} else {
|
|
975
|
+
winston.error("(voice) Missing redis parameters --> REDIS_HOST and REDIS_PORT");
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
//init VOICE CHANNEL
|
|
979
|
+
voiceChannel = new VoiceChannel({
|
|
980
|
+
BASE_POOLING_DELAY: settings.BASE_POOLING_DELAY || 250,
|
|
981
|
+
redis_client: redis_client,
|
|
982
|
+
})
|
|
983
|
+
|
|
984
|
+
if (settings.dbconnection) {
|
|
985
|
+
db.reuseConnection(settings.dbconnection, () => {
|
|
986
|
+
winston.info("(voice) KVBaseMongo reused exsisting db connection");
|
|
987
|
+
if (callback) {
|
|
988
|
+
callback(null);
|
|
989
|
+
}
|
|
990
|
+
})
|
|
991
|
+
} else {
|
|
992
|
+
db.connect(settings.MONGODB_URI, () => {
|
|
993
|
+
winston.info("(voice) KVBaseMongo successfully connected.");
|
|
994
|
+
|
|
995
|
+
if (callback) {
|
|
996
|
+
callback(null);
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
manageApp.startApp({
|
|
1002
|
+
API_URL: API_URL,
|
|
1003
|
+
BASE_URL: BASE_URL,
|
|
1004
|
+
BRAND_NAME: BRAND_NAME,
|
|
1005
|
+
DB: db,
|
|
1006
|
+
redis_client: redis_client
|
|
1007
|
+
}, (err) => {
|
|
1008
|
+
if (!err) {
|
|
1009
|
+
winston.info("Manage route succesfully started.");
|
|
1010
|
+
} else {
|
|
1011
|
+
winston.info("(voice) Unable to start API route.")
|
|
1012
|
+
}
|
|
1013
|
+
})
|
|
1014
|
+
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
function readHTMLFile(templateName, callback) {
|
|
1018
|
+
fs.readFile(__dirname + '/template' + templateName, { encoding: 'utf-8' },
|
|
1019
|
+
function(err, html) {
|
|
1020
|
+
if (err) {
|
|
1021
|
+
throw err;
|
|
1022
|
+
//callback(err);
|
|
1023
|
+
} else {
|
|
1024
|
+
callback(null, html)
|
|
1025
|
+
}
|
|
1026
|
+
})
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
module.exports = { router: router, startApp: startApp };
|