web-whatsapp work

This commit is contained in:
Leifer Mendez
2022-11-10 20:17:07 +01:00
parent 8410309e38
commit 6afb019f9d
14 changed files with 2374 additions and 554 deletions

View File

@@ -1,10 +1,10 @@
- [ ] Evitar dependencias
**Comunidad**
> Forma parte de este proyecto.
- [Discord](https://link.codigoencasa.com/DISCORD)
- [Twitter](https://twitter.com/leifermendez)
- [Youtube](https://www.youtube.com/watch?v=5lEMCeWEJ8o&list=PL_WGMLcL4jzWPhdhcUyhbFU6bC0oJd2BR)
- [Telegram](https://t.me/leifermendez)
- [ ] Evitar dependencias
**Comunidad**
> Forma parte de este proyecto.
- [Discord](https://link.codigoencasa.com/DISCORD)
- [Twitter](https://twitter.com/leifermendez)
- [Youtube](https://www.youtube.com/watch?v=5lEMCeWEJ8o&list=PL_WGMLcL4jzWPhdhcUyhbFU6bC0oJd2BR)
- [Telegram](https://t.me/leifermendez)

2686
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,11 +22,7 @@
"cli": "node ./packages/cli/bin/cli.js"
},
"workspaces": [
"packages/cli",
"packages/core",
"packages/database",
"packages/io",
"packages/provider",
"packages/*",
"docs"
],
"keywords": [

View File

@@ -1,5 +1,5 @@
/**
* [ ] Escuchar eventos del provider
* [ ] Escuchar eventos del provider asegurarte que los provider emitan eventos
* [ ] Guardar historial en db
* [ ] Buscar mensaje en flow
*
@@ -13,8 +13,16 @@ class BotClass {
this.databaseClass = _database
this.providerClass = _provider
this.providerClass.on('message', ({ message }) =>
this.handleOnMessage(message)
this.providerClass.on('require_action', (a) => console.log('here??', a))
this.providerClass.on('ready', (a) => console.log('ready??', a))
this.providerClass.on('auth_failure', (a) =>
console.log('auth_failure??', a)
)
this.providerClass.on('authenticated', (a) =>
console.log('authenticated??', a)
)
this.providerClass.on('message', (message) =>
console.log('message?', message)
)
}

View File

@@ -0,0 +1,25 @@
const { EventEmitter } = require('node:events')
/**
* Esta clase debe siempre proporcionar los siguietes metodos
* sendMessage = Para enviar un mensaje
*
* @important
* Esta clase extiende de la clase del provider OJO
* Eventos
* - message
* - ready
* - error
* - require_action
*/
class ProviderClass extends EventEmitter {
/**
* events: message | auth | auth_error | ...
*
*/
sendMessage = async (userId, message) => {
return message
}
}
module.exports = ProviderClass

View File

@@ -1,4 +1,5 @@
const BotClass = require('./classes/bot.class')
const ProviderClass = require('./classes/provider.class')
/**
* Crear instancia de clase
@@ -6,10 +7,7 @@ const BotClass = require('./classes/bot.class')
* @returns
*/
const create = async ({ flow, database, provider }) => {
return Object.setPrototypeOf(
new BotClass(flow, database, provider),
provider
)
new BotClass(flow, database, provider)
}
module.exports = { create }
module.exports = { create, ProviderClass }

View File

@@ -1,5 +1,24 @@
const { EventEmitter } = require('node:events')
const ProviderClass = require('../../core/classes/provider.class')
class MockProvider extends EventEmitter {}
class MockSetting {
enviar = async (number, msg) => {
return Promise.resolve('1')
}
}
const mock = new MockSetting()
class MockProvider extends ProviderClass {
vendor
constructor() {
super()
this.vendor = mock
}
sendMessage = async (userId, message) => {
const status = await this.vendor.enviar(userId, message)
return { userId, message, status }
}
}
module.exports = MockProvider

View File

@@ -1 +1,19 @@
class TwilioProvider {}
const twilio = require('twilio')
const ProviderClass = require('../classes/provider.class')
const TwilioVendor = new twilio(accountSid, authToken)
class TwilioProvider extends ProviderClass {
constructor() {
super(TwilioVendor)
}
sendMessage = (message) =>
this.vendor.messages.create({
body: message,
to: '+12345678901', // Text this number
from: '+12345678901', // From a valid Twilio number
})
}
module.exports = TwilioProvider

View File

@@ -0,0 +1,71 @@
const { createWriteStream } = require('fs')
const qr = require('qr-image')
const { Client, LocalAuth } = require('whatsapp-web.js')
//TODO: Acoplamiento OJO
const { ProviderClass } = require('../../index').botcore
const WebWhatsappVendor = new Client({
authStrategy: new LocalAuth(),
})
/**
* TODO esto se debe mover a un utils.js
* @param {*} number
* @returns
*/
const cleanNumber = (number) => {
number = number.replace('@c.us', '')
number = `${number}@c.us`
return number
}
const generateImage = (base64) => {
let qr_svg = qr.image(base64, { type: 'svg', margin: 4 })
qr_svg.pipe(createWriteStream(`${process.cwd()}/qr.svg`))
console.log(`⚡ Recuerda que el QR se actualiza cada minuto ⚡'`)
console.log(`⚡ Actualiza F5 el navegador para mantener el mejor QR⚡`)
}
//////////////////////////////////////////////////////
class WebWhatsappProvider extends ProviderClass {
vendor
constructor(_vendor) {
super()
this.vendor = _vendor
this.vendor.on('qr', (qr) => {
this.emit('require_action', {
eventName: 'require_action',
instructions: `Debes escanear el QR Code para iniciar session reivsa qr.svg`,
})
generateImage(qr)
})
this.vendor.on('ready', (ready) =>
this.emit('ready', { eventName: 'ready', ...ready })
)
this.vendor.on('auth_failure', (error) =>
this.emit('error', { eventName: 'error', ...error })
)
this.vendor.on('authenticated', (authenticated) =>
this.emit('ready', { eventName: 'authenticated', ...authenticated })
)
this.vendor.on('message', (message) =>
this.emit('message', { eventName: 'message', ...message })
)
this.vendor.initialize()
}
sendMessage = async (userId, message) => {
const number = cleanNumber(userId)
return this.vendor.sendMessage(number, message)
}
}
/**
* Injectamos!
*/
module.exports = new WebWhatsappProvider(WebWhatsappVendor)

View File

@@ -1,13 +0,0 @@
class ProviderClass {
/**
* events: message | auth | auth_error | ...
*
*/
constructor() {}
sendMessage = (message) => {
return message
}
}
module.exports = ProviderClass

View File

@@ -1,22 +0,0 @@
const ProviderClass = require('./classes/provider.class')
const TwilioProvider = require('./adapters/twilio')
const MockProvider = require('./adapters/mock')
const prepareVendor = ({ vendor, credentials }) => {
if (vendor === 'twilio') return new TwilioProvider(credentials)
// if (vendor === 'meta') return new TwilioProvider(credentials)
// if (vendor === 'wev') return new TwilioProvider(credentials)
return new MockProvider()
}
/**
* Crear instancia de clase
* @param {*} args
* @returns
*/
const create = async (args) => {
const vendor = prepareVendor(args)
return Object.setPrototypeOf(new ProviderClass(), vendor)
}
module.exports = { create }

View File

@@ -7,5 +7,9 @@
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {}
"devDependencies": {},
"dependencies": {
"qr-image": "^3.2.0",
"whatsapp-web.js": "^1.18.2"
}
}

View File

@@ -0,0 +1,13 @@
const { test } = require('uvu')
const assert = require('uvu/assert')
const MockProvider = require('../adapters/mock')
test(`ProviderClass`, async () => {
const provider = new MockProvider()
const msg = await provider.sendMessage('123456789', 'hola')
console.log(msg)
assert.is(msg.userId, '123456789')
assert.is(msg.message, 'hola')
})
test.run()

1
qr.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.6 KiB