From b122882aac0f438cb8ffc4c507fad807a389251c Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sat, 12 May 2018 16:08:24 -0300 Subject: [PATCH] - NEW: Whatsapp directline client is now working in preview. --- VERSION.md | 4 + deploy/core.gbapp/models/GBModel.ts | 2 + deploy/core.gbapp/services/GBMinService.ts | 3 +- deploy/kb.gbapp/dialogs/AskDialog.ts | 8 +- deploy/whatsapp.gblib/index.ts | 2 +- .../services/WhatsappDirectLine.ts | 91 +++++++++++++------ package.json | 4 +- src/logger.ts | 4 +- 8 files changed, 79 insertions(+), 39 deletions(-) diff --git a/VERSION.md b/VERSION.md index 662e6d6d..ba1de944 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1,3 +1,7 @@ +## Version 0.0.20 + +- NEW: Whatsapp directline client is now working in preview. + ## Version 0.0.19 - NEW: Whatsapp directline client started. diff --git a/deploy/core.gbapp/models/GBModel.ts b/deploy/core.gbapp/models/GBModel.ts index c5706bfa..565b2a3d 100644 --- a/deploy/core.gbapp/models/GBModel.ts +++ b/deploy/core.gbapp/models/GBModel.ts @@ -97,6 +97,8 @@ export class GuaribasInstance extends Model implements IGBInst @Column whatsappServiceNumber: string; + @Column whatsappServiceUrl: string; + @Column spellcheckerKey: string; @Column theme: string; diff --git a/deploy/core.gbapp/services/GBMinService.ts b/deploy/core.gbapp/services/GBMinService.ts index cc1d987c..599322ad 100644 --- a/deploy/core.gbapp/services/GBMinService.ts +++ b/deploy/core.gbapp/services/GBMinService.ts @@ -172,7 +172,8 @@ export class GBMinService { e.sysPackages.push(p); if (sysPackage.name === "GBWhatsappPackage") { - server.post("/instances/:botId/whatsapp", (req, res) => { + let url = "/instances/:botId/whatsapp"; + server.post(url, (req, res) => { p["channel"].received(req, res); }); } diff --git a/deploy/kb.gbapp/dialogs/AskDialog.ts b/deploy/kb.gbapp/dialogs/AskDialog.ts index dad6b4bd..54edc949 100644 --- a/deploy/kb.gbapp/dialogs/AskDialog.ts +++ b/deploy/kb.gbapp/dialogs/AskDialog.ts @@ -109,14 +109,16 @@ export class AskDialog extends IGBDialog { session.userData.isAsking = false; if (session.userData.subjects.length > 0) { - let subjectText = `${KBService.getSubjectItemsSeparatedBySpaces( + let subjectText = + `${KBService.getSubjectItemsSeparatedBySpaces( session.userData.subjects )}`; let msgs = [ `Respondendo nao apenas sobre ${subjectText}... `, `Respondendo de modo mais abrangente...`, - `Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}` + `Vou te responder de modo mais abrangente... + Não apenas sobre ${subjectText}` ]; session.send(msgs); } @@ -195,7 +197,7 @@ export class AskDialog extends IGBDialog { } ]) .triggerAction({ - matches: /^(procurar|bing|google|perguntar)/i + matches: /^(bing|google)/i }); bot.beginDialogAction("ask", "/ask"); } diff --git a/deploy/whatsapp.gblib/index.ts b/deploy/whatsapp.gblib/index.ts index 357465a9..4b321b5b 100644 --- a/deploy/whatsapp.gblib/index.ts +++ b/deploy/whatsapp.gblib/index.ts @@ -55,7 +55,7 @@ export class GBWhatsappPackage implements IGBPackage { loadBot(min: GBMinInstance): void { this.channel = new WhatsappDirectLine(min.botId, min.instance.whatsappBotKey, min.instance.whatsappServiceKey, - min.instance.whatsappServiceNumber); + min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl); } unloadBot(min: GBMinInstance): void { diff --git a/deploy/whatsapp.gblib/services/WhatsappDirectLine.ts b/deploy/whatsapp.gblib/services/WhatsappDirectLine.ts index 1c0ae08d..e1ab6fd4 100644 --- a/deploy/whatsapp.gblib/services/WhatsappDirectLine.ts +++ b/deploy/whatsapp.gblib/services/WhatsappDirectLine.ts @@ -49,53 +49,83 @@ export class WhatsappDirectLine extends GBService { pollInterval = 1000; directLineClientName = 'DirectLineClient'; directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'; + directLineClient: any; whatsappServiceKey: string; whatsappServiceNumber: string; + whatsappServiceUrl: string; botId: string; - constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber) { + conversationIds = {}; + + constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber, whatsappServiceUrl) { super(); this.botId = botId; this.whatsappServiceKey = whatsappServiceKey; this.whatsappServiceNumber = whatsappServiceNumber; + this.whatsappServiceUrl = whatsappServiceUrl; // TODO: Migrate to Swagger 3. this.directLineClient = rp(this.directLineSpecUrl) - .then(function (spec) { + .then((spec) => { return new Swagger({ spec: JSON.parse(spec.trim()), usePromise: true }); }) - .then(function (client) { + .then(async (client) => { client.clientAuthorizations.add('AuthorizationBotConnector', new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header')); + + + + var options = { + method: 'POST', + url: UrlJoin(this.whatsappServiceUrl, "webhook"), + qs: + { + token: this.whatsappServiceKey, + webhookUrl: `https://cec02d94.ngrok.io/instances/${this.botId}/whatsapp` + }, + headers: + { + 'cache-control': 'no-cache' + } + }; + + try { + const result = await request.post(options); + } catch (error) { + logger.error('Error initializing DirectLine client', error); + } + return client; }) - .catch(function (err) { + .catch((err) => { logger.error('Error initializing DirectLine client', err); }); } received(req, res) { + let text = req.body.messages[0].body; + let from = req.body.messages[0].author.split('@')[0]; + let fromName = req.body.messages[0].senderName; - logger.info(`GBWhatsapp: Hook called. Event: ${req.body.event}, - muid: ${req.body.muid}, contact: ${req.body.contact.name}, - (${req.body.contact.uid}, ${req.body.contact.type})`); + if (req.body.messages[0].fromMe){ + return; // Exit here. + } + + logger.info(`GBWhatsapp: Hook called. from: ${from}(${fromName}), text: ${text})`); - let conversationId = null; // req.body.cuid; - let text = req.body.message.body.text; - let from = req.body.contact.uid; - let fromName = req.body.contact.name; + let conversationId = this.conversationIds[from]; this.directLineClient.then((client) => { - if (conversationId == null) { + if (this.conversationIds[from] == null) { logger.info(`GBWhatsapp: Starting new conversation on Bot.`); client.Conversations.Conversations_StartConversation() @@ -104,10 +134,12 @@ export class WhatsappDirectLine extends GBService { }) .then((conversationId) => { + this.conversationIds[from] = conversationId; + this.inputMessage(client, conversationId, text, from, fromName); - this.pollMessages(client, conversationId,from, fromName); + this.pollMessages(client, conversationId, from, fromName); }) .catch((err) => { console.error('Error starting conversation', err); @@ -139,14 +171,14 @@ export class WhatsappDirectLine extends GBService { }, replyToId: from } - }).catch(function (err) { + }).catch((err) => { logger.error(`GBWhatsapp: Error receiving message: ${err}.`); }); } - pollMessages(client, conversationId,from, fromName){ + pollMessages(client, conversationId, from, fromName) { logger.info(`GBWhatsapp: Starting polling message for conversationId: ${conversationId}.`); @@ -162,31 +194,32 @@ export class WhatsappDirectLine extends GBService { return response.obj.activities; }) .then((activities) => { - this.printMessages(activities, from, fromName); + this.printMessages(activities, conversationId, from, fromName); }); }, this.pollInterval); } - printMessages(activities,from, fromName) { + printMessages(activities, conversationId, from, fromName) { if (activities && activities.length) { // Ignore own messages. - activities = activities.filter((m) => { return m.from.id === this.botId }); + activities = activities.filter((m) => { return m.from.id === this.botId && m.type === "message"}); if (activities.length) { // Print other messages. - activities.forEach(activity => { - this.printMessage(activity, from, fromName); - }); + this.printMessage(activities[0], conversationId, from, fromName); + // activities.forEach(activity => { + // this.printMessage(activity, conversationId, from, fromName); + // }); } } } - printMessage(activity, from, fromName) { + printMessage(activity, conversationId, from, fromName) { let output: string; @@ -196,7 +229,7 @@ export class WhatsappDirectLine extends GBService { } if (activity.attachments) { - activity.attachments.forEach(function (attachment) { + activity.attachments.forEach((attachment) => { switch (attachment.contentType) { case "application/vnd.microsoft.card.hero": output += this.renderHeroCard(attachment); @@ -210,7 +243,7 @@ export class WhatsappDirectLine extends GBService { }); } - this.sendToDevice(from, fromName, output); + this.sendToDevice(conversationId, from, fromName, output); } renderHeroCard(attachment) { @@ -230,17 +263,15 @@ export class WhatsappDirectLine extends GBService { output += '*'.repeat(width + 1) + '/'; } - async sendToDevice(to, toName, msg) { + async sendToDevice(conversationId, to, toName, msg) { var options = { method: 'POST', - url: 'https://www.waboxapp.com/api/send/chat', + url: UrlJoin(this.whatsappServiceUrl, 'message'), qs: { token: this.whatsappServiceKey, - uid: this.whatsappServiceNumber, - to: to, - custom_uid: 'GBZAP' + (new Date()).toISOString, - text: msg + phone: to, + body: msg }, headers: { diff --git a/package.json b/package.json index 56c84c08..4490fefc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "botserver", - "version": "0.0.19", + "version": "0.0.20", "description": "General Bot Community Edition open-core server.", "contributors": [ "Rodrigo Rodriguez " @@ -32,7 +32,7 @@ "async": "^1.5.2", "body-parser": "^1.18.2", "botbuilder": "^3.14.0", - "botlib": "0.0.18", + "botlib": "0.0.19", "chai": "^4.1.2", "chokidar": "^2.0.2", "csv-parse": "^2.4.0", diff --git a/src/logger.ts b/src/logger.ts index b7983d27..e9a77b4c 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -61,7 +61,7 @@ var logger = new (winston.Logger)({ logger.add(winston.transports.Console, { label: 'General Bot Server', - level: 'info', + level: 'error', prettyPrint: true, colorize: true, silent: false, @@ -71,7 +71,7 @@ logger.add(winston.transports.Console, { logger.add(winston.transports.File, { label: 'General Bot Server', prettyPrint: true, - level: 'info', + level: 'error', silent: false, colorize: false, timestamp: true,