fix(conflict): conflict resolution

This commit is contained in:
vicente1992
2022-12-15 00:25:13 -05:00
111 changed files with 3726 additions and 1404 deletions

View File

@@ -0,0 +1,216 @@
const { ProviderClass } = require('@bot-whatsapp/bot')
const pino = require('pino')
const mime = require('mime-types')
const fs = require('fs')
const {
default: makeWASocket,
useMultiFileAuthState,
} = require('@adiwajshing/baileys')
const {
baileyGenerateImage,
baileyCleanNumber,
baileyIsValidNumber,
} = require('./utils')
/**
* ⚙️ BaileysProvider: Es una clase tipo adaptor
* que extiende clases de ProviderClass (la cual es como interfaz para sber que funciones rqueridas)
* https://github.com/adiwajshing/Baileys
*/
class BaileysProvider extends ProviderClass {
vendor
constructor() {
super()
this.initBailey().then(() => this.initBusEvents())
}
/**
* Iniciar todo Bailey
*/
async initBailey() {
const { state, saveCreds } = await useMultiFileAuthState('sessions')
try {
this.vendor = makeWASocket({
printQRInTerminal: false,
auth: state,
logger: pino({ level: 'error' }),
})
this.vendor.ev.on(
'connection.update',
async ({ qr, connection, lastDisconnect }) => {
if (qr) baileyGenerateImage(qr)
if (connection === 'open') this.emit('ready', true)
if (lastDisconnect?.error) {
saveCreds()
this.initBailey()
}
}
)
} catch (e) {
this.emit('error', e)
}
}
/**
* Mapeamos los eventos nativos a los que la clase Provider espera
* para tener un standar de eventos
* @returns
*/
busEvents = () => [
{
event: 'connection.update',
func: async ({ qr, connection, lastDisconnect }) => {
if (qr) {
this.emit('require_action', {
instructions: [
`Debes escanear el QR Code para iniciar session reivsa qr.png`,
`Recuerda que el QR se actualiza cada minuto `,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
],
})
baileyGenerateImage(qr)
}
if (lastDisconnect?.error) {
this.emit('require_action', {
instructions: [
`Algo sucedio reinicia el bot o revisa tu whatsapp`,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
],
})
}
if (connection === 'open') this.emit('ready', true)
},
},
{
event: 'messages.upsert',
func: ({ messages }) => {
const [messageCtx] = messages
let payload = {
...messageCtx,
body: messageCtx?.message?.conversation,
from: messageCtx?.key?.remoteJid,
}
if (payload.from === 'status@broadcast') {
return
}
if (!baileyIsValidNumber(payload.from)) {
return
}
payload.from = baileyCleanNumber(payload.from, true)
this.emit('message', payload)
},
},
]
initBusEvents = () => {
const listEvents = this.busEvents()
for (const { event, func } of listEvents) {
this.vendor.ev.on(event, func)
}
}
/**
* @alpha
* @param {string} number
* @param {string} message
* @example await sendMessage('+XXXXXXXXXXX', 'https://dominio.com/imagen.jpg' | 'img/imagen.jpg')
*/
sendMedia = async (number, imageUrl) => {
await this.vendor.sendMessage(number, {
image: { url: imageUrl },
})
}
/**
* @alpha
* @param {string} number
* @param {string} message
* @param {boolean} voiceNote optional
* @example await sendMessage('+XXXXXXXXXXX', 'audio.mp3')
*/
sendAudio = async (number, audioUrl, voiceNote = false) => {
const numberClean = number.replace('+', '')
await this.vendor.sendMessage(`${numberClean}@c.us`, {
audio: { url: audioUrl },
ptt: voiceNote,
})
}
/**
*
* @param {string} number
* @param {string} message
* @returns
*/
sendText = async (number, message) => {
return this.vendor.sendMessage(number, { text: message })
}
/**
* TODO: Necesita terminar de implementar el sendMedia y sendButton guiarse:
* https://github.com/leifermendez/bot-whatsapp/blob/4e0fcbd8347f8a430adb43351b5415098a5d10df/packages/provider/src/web-whatsapp/index.js#L165
* @param {string} number
* @param {string} message
* @example await sendMessage('+XXXXXXXXXXX', 'Hello World')
*/
sendMessage = async (numberIn, message, { options }) => {
const number = baileyCleanNumber(numberIn)
// if (options?.buttons?.length)
// return this.sendButtons(number, message, options.buttons)
if (options?.media) return this.sendMedia(number, options.media)
return this.sendText(number, message)
}
/**
*
* @param {string} number
* @param {string} filePath
* @example await sendMessage('+XXXXXXXXXXX', './document/file.pdf')
*/
sendFile = async (number, filePath) => {
if (fs.existsSync(filePath)) {
const mimeType = mime.lookup(filePath)
const numberClean = number.replace('+', '')
const fileName = filePath.split('/').pop()
await this.vendor.sendMessage(`${numberClean}@c.us`, {
document: { url: filePath },
mimetype: mimeType,
fileName: fileName,
})
}
}
/**
*
* @param {string} number
* @param {string} text
* @param {string} footer
* @param {Array} buttons
* @example await sendMessage("+XXXXXXXXXXX", "Your Text", "Your Footer", [{"buttonId": "id", "buttonText": {"displayText": "Button"}, "type": 1}])
*/
sendButtons = async (number, text, footer, buttons) => {
const numberClean = number.replace('+', '')
const buttonMessage = {
text: text,
footer: footer,
buttons: buttons,
headerType: 1,
}
await this.vendor.sendMessage(`${numberClean}@c.us`, buttonMessage)
}
}
module.exports = BaileysProvider

View File

@@ -0,0 +1,21 @@
const { createWriteStream } = require('fs')
const qr = require('qr-image')
const baileyCleanNumber = (number, full = false) => {
number = number.replace('@s.whatsapp.net', '')
number = !full ? `${number}@s.whatsapp.net` : `${number}`
return number
}
const baileyGenerateImage = (base64) => {
let qr_svg = qr.image(base64, { type: 'png', margin: 4 })
qr_svg.pipe(createWriteStream(`${process.cwd()}/qr.png`))
}
const baileyIsValidNumber = (rawNumber) => {
const regexGroup = /\@g.us\b/gm
const exist = rawNumber.match(regexGroup)
return !exist
}
module.exports = { baileyCleanNumber, baileyGenerateImage, baileyIsValidNumber }

View File

@@ -81,7 +81,7 @@ class TwilioProvider extends ProviderClass {
* @param {*} buttons []
* @returns
*/
sendButtons = async (number, message, buttons = []) => {
sendButtons = async () => {
console.log(``)
console.log(
`[NOTA]: Actualmente enviar botons con Twilio esta en desarrollo`

View File

@@ -0,0 +1,116 @@
const { ProviderClass } = require('@bot-whatsapp/bot')
const venom = require('venom-bot')
const {
venomCleanNumber,
venomGenerateImage,
venomisValidNumber,
} = require('./utils')
/**
* ⚙️ VenomProvider: Es una clase tipo adaptor
* que extiende clases de ProviderClass (la cual es como interfaz para sber que funciones rqueridas)
* https://github.com/orkestral/venom
*/
class VenomProvider extends ProviderClass {
vendor
constructor() {
super()
this.init().then(() => this.initBusEvents())
}
/**
* Iniciamos el Proveedor Venom
*/
init = async () => {
try {
const client = await venom.create(
{
session: 'session-base',
multidevice: true,
},
(base) => this.generateQr(base),
undefined,
{ logQR: false }
)
this.vendor = client
} catch (e) {
this.emit('auth_failure', {
instructions: [
`Ocurrio un error con la inicializacion de venom`,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
`(Puedes abrir un ISSUE) https://github.com/leifermendez/bot-whatsapp/issues/new/choose`,
``,
`${e?.message}`,
],
})
}
}
/**
* Generamos QR Code pra escanear con el Whatsapp
*/
generateQr = (qr) => {
console.clear()
this.emit('require_action', {
instructions: [
`Debes escanear el QR Code para iniciar session reivsa qr.png`,
`Recuerda que el QR se actualiza cada minuto `,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
],
})
venomGenerateImage(qr)
}
/**
* Mapeamos los eventos nativos de https://docs.orkestral.io/venom/#/?id=events
* para tener un standar de eventos
* @returns
*/
busEvents = () => [
{
event: 'onMessage',
func: (payload) => {
if (payload.from === 'status@broadcast') {
return
}
if (!venomisValidNumber(payload.from)) {
return
}
payload.from = venomCleanNumber(payload.from, true)
this.emit('message', payload)
},
},
]
/**
* Iniciamos y mapeamos el BusEvent
* Ejemplo:
* this.vendor.onMessage() 👉 this.vendor["onMessage"]()
*/
initBusEvents = () => {
const listEvents = this.busEvents()
for (const { event, func } of listEvents) {
if (this.vendor[event])
this.vendor[event]((payload) => func(payload))
}
}
/**
* Enviar mensaje al usuario
* @param {*} userId
* @param {*} message
* @param {*} param2
* @returns
*/
sendMessage = async (userId, message, { options }) => {
const number = venomCleanNumber(userId)
if (options?.buttons?.length)
return this.sendButtons(number, message, options.buttons)
if (options?.media) return this.sendMedia(number, options.media)
return this.vendor.sendText(number, message)
}
}
module.exports = VenomProvider

View File

@@ -0,0 +1,36 @@
const { writeFile } = require('fs')
const venomCleanNumber = (number, full = false) => {
number = number.replace('@c.us', '')
number = !full ? `${number}@c.us` : `${number}`
return number
}
const venomGenerateImage = (base) => {
const matches = base.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/)
if (matches.length !== 3) {
return new Error('Invalid input string')
}
let response = {}
response.type = matches[1]
response.data = new Buffer.from(matches[2], 'base64')
var imageBuffer = response
writeFile(
`${process.cwd()}/qr.png`,
imageBuffer['data'],
'binary',
(err) => {
if (err != null) throw new Error('ERROR_QR_GENERATE')
return
}
)
}
const venomisValidNumber = (rawNumber) => {
const regexGroup = /\@g.us\b/gm
const exist = rawNumber.match(regexGroup)
return !exist
}
module.exports = { venomCleanNumber, venomGenerateImage, venomisValidNumber }

View File

@@ -1,18 +1,12 @@
const {
Client,
LocalAuth,
MessageMedia,
Buttons,
List,
} = require('whatsapp-web.js')
const { Client, LocalAuth, MessageMedia, Buttons } = require('whatsapp-web.js')
const { ProviderClass } = require('@bot-whatsapp/bot')
const { Console } = require('console')
const { createWriteStream, existsSync } = require('fs')
const { createWriteStream } = require('fs')
const {
cleanNumber,
generateImage,
isValidNumber,
downloadMedia,
wwebCleanNumber,
wwebDownloadMedia,
wwebGenerateImage,
wwebIsValidNumber,
} = require('./utils')
const logger = new Console({
@@ -37,6 +31,7 @@ class WebWhatsappProvider extends ProviderClass {
for (const { event, func } of listEvents) {
this.vendor.on(event, func)
}
this.vendor.emit('preinit')
this.vendor.initialize().catch((e) => {
logger.log(e)
@@ -65,12 +60,12 @@ class WebWhatsappProvider extends ProviderClass {
func: (qr) => {
this.emit('require_action', {
instructions: [
`Debes escanear el QR Code para iniciar session reivsa qr.svg`,
`Debes escanear el QR Code para iniciar session reivsa qr.png`,
`Recuerda que el QR se actualiza cada minuto `,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
],
})
generateImage(qr)
wwebGenerateImage(qr)
},
},
{
@@ -84,10 +79,10 @@ class WebWhatsappProvider extends ProviderClass {
return
}
if (!isValidNumber(payload.from)) {
if (!wwebIsValidNumber(payload.from)) {
return
}
payload.from = cleanNumber(payload.from, true)
payload.from = wwebCleanNumber(payload.from, true)
this.emit('message', payload)
},
},
@@ -103,7 +98,7 @@ class WebWhatsappProvider extends ProviderClass {
*/
sendMedia = async (number, mediaInput = null) => {
if (!mediaInput) throw new Error(`NO_SE_ENCONTRO: ${mediaInput}`)
const fileDownloaded = await downloadMedia(mediaInput)
const fileDownloaded = await wwebDownloadMedia(mediaInput)
const media = MessageMedia.fromFilePath(fileDownloaded)
return this.vendor.sendMessage(number, media, {
sendAudioAsVoice: true,
@@ -134,19 +129,19 @@ class WebWhatsappProvider extends ProviderClass {
* @param {*} buttons []
* @returns
*/
sendList = async (number, message, listInput = []) => {
let sections = [
{
title: 'sectionTitle',
rows: [
{ title: 'ListItem1', description: 'desc' },
{ title: 'ListItem2' },
],
},
]
let list = new List('List body', 'btnText', sections, 'Title', 'footer')
return this.vendor.sendMessage(number, list)
}
// sendList = async (number, message, listInput = []) => {
// let sections = [
// {
// title: 'sectionTitle',
// rows: [
// { title: 'ListItem1', description: 'desc' },
// { title: 'ListItem2' },
// ],
// },
// ]
// let list = new List('List body', 'btnText', sections, 'Title', 'footer')
// return this.vendor.sendMessage(number, list)
// }
/**
* Enviar un mensaje solo texto
@@ -168,7 +163,7 @@ class WebWhatsappProvider extends ProviderClass {
* @returns
*/
sendMessage = async (userId, message, { options }) => {
const number = cleanNumber(userId)
const number = wwebCleanNumber(userId)
if (options?.buttons?.length)
return this.sendButtons(number, message, options.buttons)
if (options?.media) return this.sendMedia(number, options.media)

View File

@@ -4,18 +4,18 @@ const { tmpdir } = require('os')
const http = require('http')
const https = require('https')
const cleanNumber = (number, full = false) => {
const wwebCleanNumber = (number, full = false) => {
number = number.replace('@c.us', '')
number = !full ? `${number}@c.us` : `${number}`
return number
}
const generateImage = (base64) => {
let qr_svg = qr.image(base64, { type: 'svg', margin: 4 })
qr_svg.pipe(createWriteStream(`${process.cwd()}/qr.svg`))
const wwebGenerateImage = (base64) => {
let qr_svg = qr.image(base64, { type: 'png', margin: 4 })
qr_svg.pipe(createWriteStream(`${process.cwd()}/qr.png`))
}
const isValidNumber = (rawNumber) => {
const wwebIsValidNumber = (rawNumber) => {
const regexGroup = /\@g.us\b/gm
const exist = rawNumber.match(regexGroup)
return !exist
@@ -27,7 +27,7 @@ const isValidNumber = (rawNumber) => {
* @param {*} url
* @returns
*/
const downloadMedia = (url) => {
const wwebDownloadMedia = (url) => {
return new Promise((resolve, reject) => {
const ext = url.split('.').pop()
const checkProtocol = url.includes('https:')
@@ -50,4 +50,9 @@ const downloadMedia = (url) => {
})
}
module.exports = { cleanNumber, generateImage, isValidNumber, downloadMedia }
module.exports = {
wwebCleanNumber,
wwebGenerateImage,
wwebIsValidNumber,
wwebDownloadMedia,
}