Merge pull request #477 from codigoencasa/fix/refactor-cb

Fix/refactor cb
This commit is contained in:
Leifer Mendez
2023-01-12 21:08:33 +01:00
committed by GitHub
17 changed files with 288 additions and 41 deletions

View File

@@ -67,9 +67,13 @@ jobs:
- name: Release Github - name: Release Github
run: yarn node ./scripts/github.js --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.OCTO_TOKEN }}" run: yarn node ./scripts/github.js --version="${{ steps.package-version.outputs.current-version}}" --token="${{ secrets.OCTO_TOKEN }}"
- name: 'Run if changes have been detected'
run: |
git add .
git commit -m "chore(version): pre release"
- name: Commit Versioning & Push changes - name: Commit Versioning & Push changes
if: github.event_name == 'push' if: github.event_name == 'push'
uses: stefanzweifel/git-auto-commit-action@v4 uses: stefanzweifel/git-auto-commit-action@v4
with: with:
commit_message: 'chore(version): launch release 🚀 "${{ steps.package-version.outputs.current-version}}"' commit_message: 'chore(version): launch release 🚀 "${{ steps.package-version.outputs.current-version}}"'
branch: dev

View File

@@ -2,6 +2,12 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.1.16](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.15...v0.1.16) (2023-01-11)
### [0.1.15](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.14...v0.1.15) (2023-01-11)
### [0.1.14](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.13...v0.1.14) (2023-01-11)
### [0.1.13](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.12...v0.1.13) (2023-01-11) ### [0.1.13](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.12...v0.1.13) (2023-01-11)
### [0.1.12](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.10...v0.1.12) (2023-01-11) ### [0.1.12](https://github.com/leifermendez/bot-whatsapp/compare/v0.1.10...v0.1.12) (2023-01-11)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bot-whatsapp/root", "name": "@bot-whatsapp/root",
"version": "0.1.13", "version": "0.1.16",
"description": "Bot de wahtsapp open source para MVP o pequeños negocios", "description": "Bot de wahtsapp open source para MVP o pequeños negocios",
"main": "app.js", "main": "app.js",
"private": true, "private": true,

View File

@@ -8,6 +8,9 @@ const { createWriteStream } = require('fs')
const logger = new Console({ const logger = new Console({
stdout: createWriteStream(`${process.cwd()}/core.class.log`), stdout: createWriteStream(`${process.cwd()}/core.class.log`),
}) })
const QueuePrincipal = new Queue()
/** /**
* [ ] Escuchar eventos del provider asegurarte que los provider emitan eventos * [ ] Escuchar eventos del provider asegurarte que los provider emitan eventos
* [ ] Guardar historial en db * [ ] Guardar historial en db
@@ -84,20 +87,40 @@ class CoreClass {
this.databaseClass.save(ctxByNumber) this.databaseClass.save(ctxByNumber)
} }
// 📄 Esta funcion se encarga de enviar un array de mensajes dentro de este ctx
const sendFlow = async (messageToSend, numberOrId) => {
const queue = []
for (const ctxMessage of messageToSend) {
const delayMs = ctxMessage?.options?.delay || 0
if (delayMs) await delay(delayMs)
QueuePrincipal.enqueue(() =>
Promise.all([
this.sendProviderAndSave(numberOrId, ctxMessage),
resolveCbEveryCtx(ctxMessage),
])
)
}
return Promise.all(queue)
}
// 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje // 📄 [options: fallBack]: esta funcion se encarga de repetir el ultimo mensaje
const fallBack = () => { const fallBack = async () => {
fallBackFlag = true fallBackFlag = true
msgToSend = this.flowClass.find(refToContinue?.keyword, true) || [] await this.sendProviderAndSave(from, refToContinue)
this.sendFlow(msgToSend, from) QueuePrincipal.queue = []
return refToContinue return refToContinue
} }
// 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes // 📄 [options: flowDynamic]: esta funcion se encarga de responder un array de respuesta esta limitado a 5 mensajes
// para evitar bloque de whatsapp // para evitar bloque de whatsapp
const flowDynamic = (listMsg = [], optListMsg = { limit: 3 }) => { const flowDynamic = async (
listMsg = [],
optListMsg = { limit: 5, fallback: false }
) => {
if (!Array.isArray(listMsg)) if (!Array.isArray(listMsg))
throw new Error('Esto debe ser un ARRAY') throw new Error('Esto debe ser un ARRAY')
fallBackFlag = optListMsg.fallback
const parseListMsg = listMsg const parseListMsg = listMsg
.map(({ body }, index) => .map(({ body }, index) =>
toCtx({ toCtx({
@@ -108,26 +131,38 @@ class CoreClass {
}) })
) )
.slice(0, optListMsg.limit) .slice(0, optListMsg.limit)
msgToSend = parseListMsg for (const msg of parseListMsg) {
this.sendFlow(msgToSend, from) await this.sendProviderAndSave(from, msg)
}
return return
} }
// 📄 Se encarga de revisar si el contexto del mensaje tiene callback o fallback
const resolveCbEveryCtx = async (ctxMessage) => {
if (prevMsg?.options?.capture) return cbEveryCtx(prevMsg?.ref)
if (!ctxMessage?.options?.capture)
return await cbEveryCtx(ctxMessage?.ref)
}
// 📄 Se encarga de revisar si el contexto del mensaje tiene callback y ejecutarlo // 📄 Se encarga de revisar si el contexto del mensaje tiene callback y ejecutarlo
const cbEveryCtx = (inRef) => { const cbEveryCtx = async (inRef) => {
this.flowClass.allCallbacks[inRef](messageCtxInComming, { if (!this.flowClass.allCallbacks[inRef]) return Promise.resolve()
return this.flowClass.allCallbacks[inRef](messageCtxInComming, {
fallBack, fallBack,
flowDynamic, flowDynamic,
}) })
} }
if (prevMsg?.ref) resolveCbEveryCtx(prevMsg)
// 📄 [options: callback]: Si se tiene un callback se ejecuta // 📄 [options: callback]: Si se tiene un callback se ejecuta
if (!fallBackFlag) { //TODO AQUI
if (prevMsg?.options?.capture) cbEveryCtx(prevMsg?.ref) // if (!fallBackFlag) {
for (const ite of this.flowClass.find(body)) { // if (prevMsg?.options?.capture) cbEveryCtx(prevMsg?.ref)
if (!ite?.options?.capture) cbEveryCtx(ite?.ref) // for (const ite of this.flowClass.find(body)) {
} // if (!ite?.options?.capture) cbEveryCtx(ite?.ref)
} // }
// }
// 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa // 📄🤘(tiene return) [options: nested(array)]: Si se tiene flujos hijos los implementa
if (!fallBackFlag && prevMsg?.options?.nested?.length) { if (!fallBackFlag && prevMsg?.options?.nested?.length) {
@@ -138,11 +173,12 @@ class CoreClass {
msgToSend = this.flowClass.find(body, false, flowStandalone) || [] msgToSend = this.flowClass.find(body, false, flowStandalone) || []
for (const ite of msgToSend) { // //TODO AQUI
cbEveryCtx(ite?.ref) // for (const ite of msgToSend) {
} // cbEveryCtx(ite?.ref)
// }
this.sendFlow(msgToSend, from) sendFlow(msgToSend, from)
return return
} }
@@ -153,13 +189,13 @@ class CoreClass {
if (['string', 'boolean'].includes(typeCapture) && valueCapture) { if (['string', 'boolean'].includes(typeCapture) && valueCapture) {
msgToSend = this.flowClass.find(refToContinue?.ref, true) || [] msgToSend = this.flowClass.find(refToContinue?.ref, true) || []
this.sendFlow(msgToSend, from) sendFlow(msgToSend, from)
return return
} }
} }
msgToSend = this.flowClass.find(body) || [] msgToSend = this.flowClass.find(body) || []
this.sendFlow(msgToSend, from) sendFlow(msgToSend, from)
} }
/** /**
@@ -176,18 +212,6 @@ class CoreClass {
]) ])
} }
sendFlow = async (messageToSend, numberOrId) => {
const queue = []
for (const ctxMessage of messageToSend) {
const delayMs = ctxMessage?.options?.delay || 0
if (delayMs) await delay(delayMs)
Queue.enqueue(() =>
this.sendProviderAndSave(numberOrId, ctxMessage)
)
}
return Promise.all(queue)
}
/** /**
* @private * @private
* @param {*} message * @param {*} message

View File

@@ -10,6 +10,7 @@ module.exports = [
banner: banner['banner.output'].join(''), banner: banner['banner.output'].join(''),
file: join(__dirname, 'lib', 'bundle.bot.cjs'), file: join(__dirname, 'lib', 'bundle.bot.cjs'),
format: 'cjs', format: 'cjs',
sourcemap: true,
}, },
plugins: [commonjs(), nodeResolve()], plugins: [commonjs(), nodeResolve()],
}, },

View File

@@ -1,8 +1,8 @@
class Queue { class Queue {
static queue = [] queue = []
static pendingPromise = false pendingPromise = false
static enqueue(promise) { enqueue(promise) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.queue.push({ this.queue.push({
promise, promise,
@@ -13,7 +13,7 @@ class Queue {
}) })
} }
static dequeue() { dequeue() {
if (this.workingOnPromise) { if (this.workingOnPromise) {
return false return false
} }

View File

@@ -1,6 +1,6 @@
import Navigation from '../../../components/widgets/Navigation' import Navigation from '../../../components/widgets/Navigation'
# Flow (Flujos) # Flow
Los flujos hace referencia al hecho de construir un flujo de conversion. Esto es un flow podemos observar que estan presente dos metodos importantes **addKeyword** y el **addAnswer**. Los flujos hace referencia al hecho de construir un flujo de conversion. Esto es un flow podemos observar que estan presente dos metodos importantes **addKeyword** y el **addAnswer**.
@@ -23,6 +23,142 @@ const flowPrincipal = addKeyword(['hola', 'alo'])
--- ---
## addKeyword()
Esta funcion se utliza para iniciar un flujo de conversion. <br /> Recibe un `string` o un `array`
de string `['hola','buenas']`.
**Opciones**
- sensitive: Sensible a mayusculas y minusculas por defecto `false`
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola')
const flowArray = addKeyword(['hola', 'alo'])
const flowSensitive = addKeyword(['hola', 'alo'], {
sensitive: true,
})
```
---
## addAnswer()
Esta funcion se utliza para responder un mensaje despues del `addKeyword()`
**Opciones**
- delay: 0 (milisegundos)
- media: url de imagen
- buttons: array `[{body:'Boton1'}, {body:'Boton2'}, {body:'Boton3'}]`
- capture: false (para esperar respuesta)
- child: Objecto tipo flujo o arra de flujos hijos
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Este mensaje se enviara 1 segundo despues',
{
delay: 1000,
}
)
const flowString = addKeyword('hola').addAnswer(
'Este mensaje envia una imagen',
{
media: 'https://i.imgur.com/0HpzsEm.png',
}
)
const flowString = addKeyword('hola').addAnswer(
'Este mensaje envia tres botones',
{
buttons: [
{ body: 'Boton 1' },
{ body: 'Boton 2' },
{ body: 'Boton 3' },
],
}
)
const flowString = addKeyword('hola').addAnswer(
'Este mensaje espera una respueta del usuario',
{
capture: true,
}
)
```
---
## ctx
Este argumento se utiliza para obtener el contexto de la conversación
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Indica cual es tu email',
null,
(ctx) => {
console.log('👉 Informacion del contexto: ', ctx)
}
)
```
---
## fallBack()
Esta funcion se utliza para volver a enviar el ultimo mensaje abajo un ejemplo.
En el ejemplo de abajo esperamos que el usuario ingrese un mensaje que contenga `@` sino contiene
se repetira el mensaje `Indica cual es tu email`
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Indica cual es tu email',
null,
(ctx, { fallBack }) => {
if (!ctx.body.includes('@')) return fallBack()
}
)
```
---
## flowDynamic()
Esta funcion se utliza para devolver mensajes dinamicos que pueden venir de una API o Base de datos.
La funcion recibe un array que debe contener la siguiente estrucutura:
`[{body:'Mensaje}, {body:'Mensaje2}]`
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola')
.addAnswer('Indica cual es tu email', null, async (ctx, {flowDynamic}) => {
const mensajesDB = () => {
const categories = db.find(...)
const mapDatos = categories.map((c) => ({body:c.name}))
return mapDatos
}
await flowDynamic(mensajesDB())
})
```
---
<Navigation <Navigation
pages={[ pages={[
{ name: 'Conceptos', link: '/docs/essential' }, { name: 'Conceptos', link: '/docs/essential' },

View File

@@ -1,7 +1,9 @@
FROM node:lts-bullseye as bot FROM node:18-bullseye as bot
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
RUN npm i RUN npm i
COPY . . COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT ARG PORT
CMD ["npm", "start"] CMD ["npm", "start"]

View File

@@ -1,7 +1,9 @@
FROM node:lts-bullseye as bot FROM node:18-bullseye as bot
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY package*.json ./
RUN npm i RUN npm i
COPY . . COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT ARG PORT
CMD ["npm", "start"] CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]

View File

@@ -0,0 +1,9 @@
FROM node:18-bullseye as bot
WORKDIR /app
COPY package*.json ./
RUN npm i
COPY . .
ARG RAILWAY_STATIC_URL
ARG PUBLIC_URL
ARG PORT
CMD ["npm", "start"]