From 438607c222b91d6f8814201dabe5f7c3e7ba1abb Mon Sep 17 00:00:00 2001 From: vicente1992 Date: Thu, 15 Dec 2022 00:14:15 -0500 Subject: [PATCH] feat(provider): meta provider is added --- packages/provider/package.json | 3 +- packages/provider/rollup-provider.config.js | 9 ++ packages/provider/src/meta/index.js | 115 ++++++++++++++++++++ packages/provider/src/meta/server.js | 63 +++++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 packages/provider/src/meta/index.js create mode 100644 packages/provider/src/meta/server.js diff --git a/packages/provider/package.json b/packages/provider/package.json index c6ace860b..5c011792a 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -14,6 +14,7 @@ "exports": { "./mock": "./lib/mock/index.cjs", "./twilio": "./lib/twilio/index.cjs", - "./web-whatsapp": "./lib/web-whatsapp/index.cjs" + "./web-whatsapp": "./lib/web-whatsapp/index.cjs", + "./meta": "./lib/meta/index.cjs" } } diff --git a/packages/provider/rollup-provider.config.js b/packages/provider/rollup-provider.config.js index 8a6adcf1d..83f38be4d 100644 --- a/packages/provider/rollup-provider.config.js +++ b/packages/provider/rollup-provider.config.js @@ -30,4 +30,13 @@ module.exports = [ }, plugins: [commonjs()], }, + { + input: join(__dirname, 'src', 'meta', 'index.js'), + output: { + banner: banner['banner.output'].join(''), + file: join(__dirname, 'lib', 'meta', 'index.cjs'), + format: 'cjs', + }, + plugins: [commonjs()], + }, ] diff --git a/packages/provider/src/meta/index.js b/packages/provider/src/meta/index.js new file mode 100644 index 000000000..e32ec5154 --- /dev/null +++ b/packages/provider/src/meta/index.js @@ -0,0 +1,115 @@ +const { ProviderClass } = require('@bot-whatsapp/bot') +const axios = require('axios') +const MetaWebHookServer = require('./server') +const URL = `https://graph.facebook.com/v15.0` + +/** + * ⚙️MetaProvider: Es un provedor que te ofrece enviar + * mensaje a Whatsapp via API + * info: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages + * + * + * Necesitas las siguientes tokens y valores + * { token, numberId, vendorNumber, verify_token } + */ + +class MetaProvider extends ProviderClass { + metHook + token + numberId + constructor({ token, numberId, verifyToken }, _port = 3000) { + super() + this.token = token + this.numberId = numberId + this.metHook = new MetaWebHookServer(verifyToken, _port) + this.metHook.start() + + const listEvents = this.busEvents() + + for (const { event, func } of listEvents) { + this.metHook.on(event, func) + } + } + + /** + * Mapeamos los eventos nativos de whatsapp-web.js a los que la clase Provider espera + * para tener un standar de eventos + * @returns + */ + busEvents = () => [ + { + event: 'auth_failure', + func: (payload) => this.emit('error', payload), + }, + { + event: 'ready', + func: () => this.emit('ready', true), + }, + { + event: 'message', + func: (payload) => { + this.emit('message', payload) + }, + }, + ] + + async sendMessageMeta(body) { + try { + const response = await axios.post( + `${URL}/${this.numberId}/messages`, + body, + { + headers: { + Authorization: `Bearer ${this.token}`, + }, + } + ) + return response.data + } catch (error) { + return Promise.resolve(error) + } + } + + async sendtext(number, message) { + const body = { + messaging_product: 'whatsapp', + to: number, + type: 'text', + text: { + preview_url: false, + body: message, + }, + } + await this.sendMessageMeta(body) + } + + async sendMedia(number, message, mediaInput = null) { + if (!mediaInput) throw new Error(`MEDIA_INPUT_NULL_: ${mediaInput}`) + const body = { + messaging_product: 'whatsapp', + to: number, + type: 'image', + image: { + link: mediaInput, + }, + } + await this.sendMessageMeta(body) + } + + /** + * + * @param {*} userId + * @param {*} message + * @param {*} param2 + * @returns + */ + sendMessage = async (number, message, { options }) => { + if (options?.buttons?.length) return console.log('Envio de botones') + if (options?.media) + return this.sendMedia(number, message, options.media) + + this.sendtext(number, message) + } +} + +module.exports = MetaProvider diff --git a/packages/provider/src/meta/server.js b/packages/provider/src/meta/server.js new file mode 100644 index 000000000..91ae8bc12 --- /dev/null +++ b/packages/provider/src/meta/server.js @@ -0,0 +1,63 @@ +const { EventEmitter } = require('node:events') +const polka = require('polka') +const { urlencoded } = require('body-parser') + +class MetaWebHookServer extends EventEmitter { + metaServer + metaPort + verifyToken + constructor(_verifyToken, _metaPort) { + super() + this.metaServer = this.buildHTTPServer() + this.metaPort = _metaPort + this.verifyToken = _verifyToken + } + + /** + * Mensaje entrante + * emit: 'message' + * @param {*} req + * @param {*} res + */ + incomingMsg = (req, res) => { + const { body } = req + const message = body.entry[0].changes[0].value.messages[0] + const to = body.entry[0].changes[0].value.metadata.display_phone_number + this.emit('message', { + from: message.from, + to, + body: message.text.body, + }) + const json = JSON.stringify({ body }) + res.end(json) + } + + /** + * Contruir HTTP Server + * @returns + */ + buildHTTPServer = () => { + return polka() + .use(urlencoded({ extended: true })) + .post('/meta-hook', this.incomingMsg) + } + + /** + * Puerto del HTTP + * @param {*} port default 3000 + */ + start = () => { + this.metaServer.listen(this.metaPort, () => { + console.log(``) + console.log(`[meta]: Agregar esta url "WHEN A MESSAGE COMES IN"`) + console.log( + `[meta]: POST http://localhost:${this.metaPort}/meta-hook` + ) + console.log(`[meta]: Más información en la documentacion`) + console.log(``) + }) + this.emit('ready') + } +} + +module.exports = MetaWebHookServer