new(whatsapp.gblib): New WhatsApp provider: Meta.
This commit is contained in:
parent
3e9170d446
commit
37d9028f98
3 changed files with 88 additions and 43 deletions
|
@ -214,6 +214,7 @@
|
||||||
"vm2-process": "2.1.1",
|
"vm2-process": "2.1.1",
|
||||||
"walk-promise": "0.2.0",
|
"walk-promise": "0.2.0",
|
||||||
"washyourmouthoutwithsoap": "1.0.2",
|
"washyourmouthoutwithsoap": "1.0.2",
|
||||||
|
"whatsapp-cloud-api": "^0.3.1",
|
||||||
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
||||||
"winston": "3.8.2",
|
"winston": "3.8.2",
|
||||||
"ws": "8.14.2",
|
"ws": "8.14.2",
|
||||||
|
|
|
@ -442,9 +442,24 @@ export class GBMinService {
|
||||||
|
|
||||||
// Setups official handler for WhatsApp.
|
// Setups official handler for WhatsApp.
|
||||||
|
|
||||||
GBServer.globals.server.post(`/${min.instance.botId}/whatsapp`, async (req, res) => {
|
GBServer.globals.server.all(`/${min.instance.botId}/whatsapp`, async (req, res) => {
|
||||||
const to = req.body.To.replace(/whatsapp\:\+/gi, '');
|
|
||||||
const whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
if (req.query['hub.mode'] === 'subscribe') {
|
||||||
|
const val = req.query['hub.challenge'];
|
||||||
|
res.send(val);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let whatsAppDirectLine = min.whatsAppDirectLine;
|
||||||
|
|
||||||
|
// Not meta, multiples bots on root bot.
|
||||||
|
|
||||||
|
if (!req.body.object) {
|
||||||
|
const to = req.body.To.replace(/whatsapp\:\+/gi, '');
|
||||||
|
whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
||||||
|
}
|
||||||
|
|
||||||
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
||||||
}).bind(min);
|
}).bind(min);
|
||||||
|
|
||||||
|
@ -455,6 +470,11 @@ export class GBMinService {
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return 'GeneralBots';
|
return 'GeneralBots';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.body.entry) {
|
||||||
|
return 'meta';
|
||||||
|
}
|
||||||
|
|
||||||
if (req.body?.AccountSid) {
|
if (req.body?.AccountSid) {
|
||||||
return 'official';
|
return 'official';
|
||||||
}
|
}
|
||||||
|
@ -637,10 +657,10 @@ export class GBMinService {
|
||||||
if (botId === '[default]' || botId === undefined) {
|
if (botId === '[default]' || botId === undefined) {
|
||||||
botId = GBConfigService.get('BOT_ID');
|
botId = GBConfigService.get('BOT_ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Loads by the botId itself or by the activationCode field.
|
// Loads by the botId itself or by the activationCode field.
|
||||||
|
|
||||||
let instance = await this.core.loadInstanceByBotId(botId);
|
let instance = await this.core.loadInstanceByBotId(botId);
|
||||||
if (instance === null) {
|
if (instance === null) {
|
||||||
instance = await this.core.loadInstanceByActivationCode(botId);
|
instance = await this.core.loadInstanceByActivationCode(botId);
|
||||||
|
@ -1076,7 +1096,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Required for F0 handling of persisted conversations.
|
// Required for F0 handling of persisted conversations.
|
||||||
|
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(min,
|
||||||
`Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})`
|
`Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1114,7 +1134,7 @@ export class GBMinService {
|
||||||
) {
|
) {
|
||||||
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
||||||
|
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(min,
|
||||||
`Auto start (web 1) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
`Auto start (web 1) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
||||||
);
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
|
@ -1413,12 +1433,12 @@ export class GBMinService {
|
||||||
startDialog &&
|
startDialog &&
|
||||||
startDialog !== '' &&
|
startDialog !== '' &&
|
||||||
!min['conversationWelcomed'][step.context.activity.conversation.id] &&
|
!min['conversationWelcomed'][step.context.activity.conversation.id] &&
|
||||||
!min['apiConversations'][pid] &&
|
!min['apiConversations'][pid] &&
|
||||||
!step.context.activity['group']
|
!step.context.activity['group']
|
||||||
) {
|
) {
|
||||||
await sec.setParam(userId, 'welcomed', 'true');
|
await sec.setParam(userId, 'welcomed', 'true');
|
||||||
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(min,
|
||||||
`Auto start (4) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
`Auto start (4) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
||||||
);
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
|
@ -1625,26 +1645,25 @@ export class GBMinService {
|
||||||
);
|
);
|
||||||
|
|
||||||
let pid = data?.pid;
|
let pid = data?.pid;
|
||||||
if (script === 'start'){
|
if (script === 'start') {
|
||||||
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
||||||
|
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
|
||||||
|
|
||||||
min['apiConversations'][pid] = {conversation: response.obj, client: client};
|
|
||||||
min['conversationWelcomed'][response.obj.id] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = await GBVMService.callVM(script, min, null, pid, false, data);
|
|
||||||
|
|
||||||
if (script === 'start')
|
const client = await new SwaggerClient({
|
||||||
{
|
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
||||||
|
requestInterceptor: req => {
|
||||||
|
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
|
|
||||||
|
min['apiConversations'][pid] = { conversation: response.obj, client: client };
|
||||||
|
min['conversationWelcomed'][response.obj.id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = await GBVMService.callVM(script, min, null, pid, false, data);
|
||||||
|
|
||||||
|
if (script === 'start') {
|
||||||
ret = pid;
|
ret = pid;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1680,7 +1699,7 @@ export class GBMinService {
|
||||||
};
|
};
|
||||||
|
|
||||||
GBServer.globals.server.apiServer = createKoaHttpServer(
|
GBServer.globals.server.apiServer = createKoaHttpServer(
|
||||||
GBVMService.API_PORT,
|
GBVMService.API_PORT,
|
||||||
getRemoteId, { prefix: `api/v3` });
|
getRemoteId, { prefix: `api/v3` });
|
||||||
|
|
||||||
createRpcServer(
|
createRpcServer(
|
||||||
|
|
|
@ -54,7 +54,7 @@ const { WAState, Client, MessageMedia } = pkg;
|
||||||
import twilio from 'twilio';
|
import twilio from 'twilio';
|
||||||
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { createBot } from 'whatsapp-cloud-api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for Whatsapp.
|
* Support for Whatsapp.
|
||||||
|
@ -103,9 +103,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
this.whatsappServiceKey = whatsappServiceKey;
|
this.whatsappServiceKey = whatsappServiceKey;
|
||||||
this.whatsappServiceNumber = whatsappServiceNumber;
|
this.whatsappServiceNumber = whatsappServiceNumber;
|
||||||
this.whatsappServiceUrl = whatsappServiceUrl;
|
this.whatsappServiceUrl = whatsappServiceUrl;
|
||||||
this.provider =
|
this.provider = whatsappServiceKey === 'internal'
|
||||||
whatsappServiceKey === 'internal'
|
? 'GeneralBots' : 'meta';
|
||||||
? 'GeneralBots' : 'official';
|
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,12 +252,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static providerFromRequest(req: any) {
|
|
||||||
return req.body.ProfileName ? 'official' : 'GeneralBots';
|
|
||||||
}
|
|
||||||
|
|
||||||
public async received(req, res) {
|
public async received(req, res) {
|
||||||
const provider = WhatsappDirectLine.providerFromRequest(req);
|
const provider = GBMinService.getProviderName(req, res);
|
||||||
|
|
||||||
let message, to, from, fromName, text: string;
|
let message, to, from, fromName, text: string;
|
||||||
let group = '';
|
let group = '';
|
||||||
|
@ -266,7 +261,13 @@ export class WhatsappDirectLine extends GBService {
|
||||||
let attachments = null;
|
let attachments = null;
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
|
case 'meta':
|
||||||
|
from = req.body.entry[0].changes[0].value.messages[0].from;
|
||||||
|
text = req.body.entry[0].changes[0].value.messages[0].text.body
|
||||||
|
to = this.min.core.getParam<string>(this.min.instance, 'Bot Number', null);
|
||||||
|
fromName = req.body.entry[0].changes[0].value.contacts[0].profile.name;
|
||||||
|
|
||||||
|
break;
|
||||||
case 'official':
|
case 'official':
|
||||||
message = req.body;
|
message = req.body;
|
||||||
from = req.body.From.replace(/whatsapp\:\+/gi, '');
|
from = req.body.From.replace(/whatsapp\:\+/gi, '');
|
||||||
|
@ -512,7 +513,7 @@ export class WhatsappDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
WhatsappDirectLine.mobiles[generatedConversationId] = from;
|
WhatsappDirectLine.mobiles[generatedConversationId] = from;
|
||||||
WhatsappDirectLine.usernames[from] = fromName;
|
WhatsappDirectLine.usernames[from] = fromName;
|
||||||
WhatsappDirectLine.chatIds[generatedConversationId] = message.chatId;
|
WhatsappDirectLine.chatIds[generatedConversationId] = message?.chatId;
|
||||||
|
|
||||||
this.pollMessages(client, generatedConversationId, from, fromName);
|
this.pollMessages(client, generatedConversationId, from, fromName);
|
||||||
this.inputMessage(client, generatedConversationId, text, from, fromName, group, attachments);
|
this.inputMessage(client, generatedConversationId, text, from, fromName, group, attachments);
|
||||||
|
@ -594,7 +595,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
await this.printMessages(response.obj.activities, conversationId, from, fromName);
|
await this.printMessages(response.obj.activities, conversationId, from, fromName);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
GBLog.error(
|
GBLog.error(
|
||||||
`Error calling printMessages on Whatsapp channel ${err.data === undefined ? err : err.data} ${err.errObj ? err.errObj.message : ''
|
`Error calling printMessages on Whatsapp channel ${err.data === undefined ?
|
||||||
|
err : err.data} ${err.errObj ? err.errObj.message : ''
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -718,17 +720,27 @@ export class WhatsappDirectLine extends GBService {
|
||||||
|
|
||||||
return await this.sendTextAsAudioToDevice(to, msg, chatId);
|
return await this.sendTextAsAudioToDevice(to, msg, chatId);
|
||||||
} else {
|
} else {
|
||||||
let options;
|
let options, messages;
|
||||||
|
const botNumber = this.min.core.getParam(this.min.instance, 'Bot Number', null);
|
||||||
|
|
||||||
switch (this.provider) {
|
switch (this.provider) {
|
||||||
|
case 'meta':
|
||||||
|
const bot = createBot(this.min.instance.whatsappServiceNumber,
|
||||||
|
this.min.instance.whatsappServiceKey);
|
||||||
|
messages = msg.match(/(.|[\r\n]){1,4096}/g)
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(messages, async msg => {
|
||||||
|
await GBUtil.sleep(3000);
|
||||||
|
await bot.sendText(to, msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
case 'official':
|
case 'official':
|
||||||
const botNumber = this.min.core.getParam(this.min.instance, 'Bot Number', null);
|
|
||||||
if (to.charAt(0) !== '+') {
|
if (to.charAt(0) !== '+') {
|
||||||
to = `+${to}`
|
to = `+${to}`
|
||||||
}
|
}
|
||||||
|
|
||||||
let messages = msg.match(/(.|[\r\n]){1,1000}/g)
|
messages = msg.match(/(.|[\r\n]){1,1000}/g)
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(messages, async msg => {
|
await CollectionUtil.asyncForEach(messages, async msg => {
|
||||||
await GBUtil.sleep(3000);
|
await GBUtil.sleep(3000);
|
||||||
|
@ -793,6 +805,19 @@ export class WhatsappDirectLine extends GBService {
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
|
|
||||||
|
case 'meta':
|
||||||
|
if (req.body.entry[0].changes[0].value.statuses){
|
||||||
|
GBLogEx.info(this.min, `WhatsApp: ${req.body.entry[0].changes[0].value.statuses[0].status}.`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id = req.body.entry[0].changes[0].value.messages[0].from;
|
||||||
|
text = req.body.entry[0].changes[0].value.messages[0].text.body
|
||||||
|
senderName = req.body.entry[0].changes[0].value.contacts[0].profile.name;
|
||||||
|
botId = this.botId;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case 'official':
|
case 'official':
|
||||||
|
|
||||||
const { body } = req;
|
const { body } = req;
|
||||||
|
|
Loading…
Add table
Reference in a new issue