From d88fec7d6f8d0d454ba61d8bfa7e15dfbf756512 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Tue, 19 Sep 2023 17:02:17 -0300 Subject: [PATCH 01/16] Update instance.controller.ts --- .../controllers/instance.controller.ts | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index 8d0e21ca..2a904761 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -67,7 +67,6 @@ export class InstanceController { typebot_keyword_finish, typebot_delay_message, typebot_unknown_message, - typebot_listening_from_me, }: InstanceDto) { try { this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); @@ -127,9 +126,6 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', ]; } else { newEvents = events; @@ -176,12 +172,9 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', ]; } else { - newEvents = websocket_events; + newEvents = events; } this.websocketService.create(instance, { enabled: true, @@ -223,12 +216,9 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', ]; } else { - newEvents = rabbitmq_events; + newEvents = events; } this.rabbitmqService.create(instance, { enabled: true, @@ -257,7 +247,6 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, }); } catch (error) { this.logger.log(error); @@ -315,7 +304,6 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, }, settings, qrcode: getQrcode, @@ -408,7 +396,6 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, }, settings, chatwoot: { @@ -495,13 +482,12 @@ export class InstanceController { } public async fetchInstances({ instanceName }: InstanceDto) { + this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); if (instanceName) { - this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); this.logger.verbose('instanceName: ' + instanceName); return this.waMonitor.instanceInfo(instanceName); } - this.logger.verbose('requested fetchInstances (all instances)'); return this.waMonitor.instanceInfo(); } From f3927e1d19636bfa411f9701c9cc4d946fcba10c Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Tue, 19 Sep 2023 17:16:36 -0300 Subject: [PATCH 02/16] Update instance.controller.ts From f9fda6af75afc37295f71447bea634cfdb7a2d9d Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Tue, 19 Sep 2023 17:22:15 -0300 Subject: [PATCH 03/16] Update env.config.ts --- src/config/env.config.ts | 63 ++++++++++++---------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 873c54ce..9c63b893 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -70,10 +70,6 @@ export type Websocket = { ENABLED: boolean; }; -export type Chatwoot = { - USE_REPLY_ID: boolean; -}; - export type EventsWebhook = { APPLICATION_STARTUP: boolean; QRCODE_UPDATED: boolean; @@ -96,11 +92,6 @@ export type EventsWebhook = { GROUP_PARTICIPANTS_UPDATE: boolean; CALL: boolean; NEW_JWT_TOKEN: boolean; - TYPEBOT_START: boolean; - TYPEBOT_CHANGE_STATUS: boolean; - CHAMA_AI_ACTION: boolean; - ERRORS: boolean; - ERRORS_WEBHOOK: string; }; export type ApiKey = { KEY: string }; @@ -143,7 +134,6 @@ export interface Env { QRCODE: QrCode; AUTHENTICATION: Auth; PRODUCTION?: Production; - CHATWOOT?: Chatwoot; } export type Key = keyof Env; @@ -176,17 +166,17 @@ export class ConfigService { return { SERVER: { TYPE: process.env.SERVER_TYPE as 'http' | 'https', - PORT: Number.parseInt(process.env.SERVER_PORT) || 8080, + PORT: Number.parseInt(process.env.SERVER_PORT), URL: process.env.SERVER_URL, }, CORS: { - ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'], - METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'], + ORIGIN: process.env.CORS_ORIGIN.split(','), + METHODS: process.env.CORS_METHODS.split(',') as HttpMethods[], CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true', }, SSL_CONF: { - PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '', - FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '', + PRIVKEY: process.env?.SSL_CONF_PRIVKEY, + FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN, }, STORE: { MESSAGES: process.env?.STORE_MESSAGES === 'true', @@ -205,8 +195,8 @@ export class ConfigService { }, DATABASE: { CONNECTION: { - URI: process.env.DATABASE_CONNECTION_URI || '', - DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', + URI: process.env.DATABASE_CONNECTION_URI, + DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME, }, ENABLED: process.env?.DATABASE_ENABLED === 'true', SAVE_DATA: { @@ -219,36 +209,27 @@ export class ConfigService { }, REDIS: { ENABLED: process.env?.REDIS_ENABLED === 'true', - URI: process.env.REDIS_URI || '', - PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution', + URI: process.env.REDIS_URI, + PREFIX_KEY: process.env.REDIS_PREFIX_KEY, }, RABBITMQ: { ENABLED: process.env?.RABBITMQ_ENABLED === 'true', - URI: process.env.RABBITMQ_URI || '', + URI: process.env.RABBITMQ_URI, }, WEBSOCKET: { ENABLED: process.env?.WEBSOCKET_ENABLED === 'true', }, LOG: { - LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [ - 'ERROR', - 'WARN', - 'DEBUG', - 'INFO', - 'LOG', - 'VERBOSE', - 'DARK', - 'WEBHOOKS', - ], + LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[], COLOR: process.env?.LOG_COLOR === 'true', BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error', }, - DEL_INSTANCE: isBooleanString(process.env?.DEL_INSTANCE) - ? process.env.DEL_INSTANCE === 'true' + DEL_INSTANCE: process.env?.DEL_INSTANCE === 'true' + ? 5 : Number.parseInt(process.env.DEL_INSTANCE) || false, WEBHOOK: { GLOBAL: { - URL: process.env?.WEBHOOK_GLOBAL_URL || '', + URL: process.env?.WEBHOOK_GLOBAL_URL, ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true', WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true', }, @@ -274,37 +255,29 @@ export class ConfigService { GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true', NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true', - TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true', - TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', - CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true', - ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true', - ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '', }, }, CONFIG_SESSION_PHONE: { CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API', - NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome', + NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'chrome', }, QRCODE: { LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30, COLOR: process.env.QRCODE_COLOR || '#198754', }, AUTHENTICATION: { - TYPE: process.env.AUTHENTICATION_TYPE as 'apikey', + TYPE: process.env.AUTHENTICATION_TYPE as 'jwt', API_KEY: { - KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ', + KEY: process.env.AUTHENTICATION_API_KEY, }, EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true', JWT: { EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN) ? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN) : 3600, - SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`', + SECRET: process.env.AUTHENTICATION_JWT_SECRET, }, }, - CHATWOOT: { - USE_REPLY_ID: process.env?.USE_REPLY_ID === 'true', - }, }; } } From ed20671f5ebeb0dbf4bb2d1f03d86ee407125da9 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:03:54 -0300 Subject: [PATCH 04/16] Update main.ts --- src/main.ts | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/src/main.ts b/src/main.ts index e239f83a..75dd95b3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,11 @@ import 'express-async-errors'; -import axios from 'axios'; import compression from 'compression'; import cors from 'cors'; import express, { json, NextFunction, Request, Response, urlencoded } from 'express'; import { join } from 'path'; -import { Auth, configService, Cors, HttpServer, Rabbitmq, Webhook } from './config/env.config'; +import { configService, Cors, HttpServer, Rabbitmq } from './config/env.config'; import { onUnexpectedError } from './config/error.config'; import { Logger } from './config/logger.config'; import { ROOT_DIR } from './config/path.config'; @@ -48,45 +47,11 @@ function bootstrap() { app.set('views', join(ROOT_DIR, 'views')); app.use(express.static(join(ROOT_DIR, 'public'))); - app.use('/store', express.static(join(ROOT_DIR, 'store'))); - app.use('/', router); app.use( (err: Error, req: Request, res: Response, next: NextFunction) => { if (err) { - const webhook = configService.get('WEBHOOK'); - - if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) { - const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds - const localISOTime = new Date(Date.now() - tzoffset).toISOString(); - const now = localISOTime; - const globalApiKey = configService.get('AUTHENTICATION').API_KEY.KEY; - const serverUrl = configService.get('SERVER').URL; - - const errorData = { - event: 'error', - data: { - error: err['error'] || 'Internal Server Error', - message: err['message'] || 'Internal Server Error', - status: err['status'] || 500, - response: { - message: err['message'] || 'Internal Server Error', - }, - }, - date_time: now, - api_key: globalApiKey, - server_url: serverUrl, - }; - - logger.error(errorData); - - const baseURL = webhook.EVENTS.ERRORS_WEBHOOK; - const httpService = axios.create({ baseURL }); - - httpService.post('', errorData); - } - return res.status(err['status'] || 500).json({ status: err['status'] || 500, error: err['error'] || 'Internal Server Error', @@ -124,7 +89,7 @@ function bootstrap() { initIO(server); - if (configService.get('RABBITMQ')?.ENABLED) initAMQP(); + if (configService.get('RABBITMQ').ENABLED) initAMQP(); onUnexpectedError(); } From 269c9e4b5535c011b96666c7a9219e63d5c08b98 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:16:42 -0300 Subject: [PATCH 05/16] Update instance.controller.ts From ce358e91f0470c25d209021572428ab2f062584a Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:31:04 -0300 Subject: [PATCH 06/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 226 +++++++++++------------ 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index 66b07bae..039a5f29 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -7,6 +7,7 @@ import { join } from 'path'; import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; +import { NotFoundException } from '../../exceptions'; import { dbserver } from '../../libs/db.connect'; import { RedisCache } from '../../libs/redis.client'; import { @@ -75,57 +76,77 @@ export class WAMonitoringService { public async instanceInfo(instanceName?: string) { this.logger.verbose('get instance info'); + if (instanceName && !this.waInstances[instanceName]) { + throw new NotFoundException(`Instance "${instanceName}" not found`); + } - const urlServer = this.configService.get('SERVER').URL; + const instances: any[] = []; - const instances: any[] = await Promise.all( - Object.entries(this.waInstances).map(async ([key, value]) => { - const status = value?.connectionStatus?.state || 'unknown'; + for await (const [key, value] of Object.entries(this.waInstances)) { + if (value) { + this.logger.verbose('get instance info: ' + key); + let chatwoot: any; - if (status === 'unknown') { - return null; + const urlServer = this.configService.get('SERVER').URL; + + const findChatwoot = await this.waInstances[key].findChatwoot(); + + if (findChatwoot && findChatwoot.enabled) { + chatwoot = { + ...findChatwoot, + webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, + }; } - if (status === 'open') { + if (value.connectionStatus.state === 'open') { this.logger.verbose('instance: ' + key + ' - connectionStatus: open'); - } - const instanceData: any = { - instance: { - instanceName: key, - owner: value.wuid, - profileName: (await value.getProfileName()) || 'not loaded', - profilePictureUrl: value.profilePictureUrl, - profileStatus: (await value.getProfileStatus()) || '', - status: status, - }, - }; + const instanceData = { + instance: { + instanceName: key, + owner: value.wuid, + profileName: (await value.getProfileName()) || 'not loaded', + profilePictureUrl: value.profilePictureUrl, + profileStatus: (await value.getProfileStatus()) || '', + status: value.connectionStatus.state, + }, + }; - if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance.serverUrl = urlServer; - instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; + if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { + instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - const findChatwoot = await this.waInstances[key].findChatwoot(); - if (findChatwoot && findChatwoot.enabled) { - instanceData.instance.chatwoot = { - ...findChatwoot, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, - }; + instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + + instanceData.instance['chatwoot'] = chatwoot; } - } - return instanceData; - }), - ).then((results) => results.filter((instance) => instance !== null)); + instances.push(instanceData); + } else { + this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state); + + const instanceData = { + instance: { + instanceName: key, + status: value.connectionStatus.state, + }, + }; + + if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { + instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; + + instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + + instanceData.instance['chatwoot'] = chatwoot; + } + + instances.push(instanceData); + } + } + } this.logger.verbose('return instance info: ' + instances.length); - if (instanceName) { - const instance = instances.find((i) => i.instance.instanceName === instanceName); - return instance || []; - } - - return instances; + return instances.find((i) => i.instance.instanceName === instanceName) ?? instances; } private delInstanceFiles() { @@ -140,7 +161,8 @@ export class WAMonitoringService { }); this.logger.verbose('instance files deleted: ' + name); }); - } else if (!this.redis.ENABLED) { + // } else if (this.redis.ENABLED) { + } else { const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); for await (const dirent of dir) { if (dirent.isDirectory()) { @@ -198,11 +220,6 @@ export class WAMonitoringService { execSync(`rm -rf ${join(STORE_DIR, 'auth', 'apikey', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'webhook', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'chatwoot', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'chamaai', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'proxy', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'rabbitmq', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`); execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`); return; @@ -223,85 +240,68 @@ export class WAMonitoringService { } public async loadInstance() { - this.logger.verbose('Loading instances'); + this.logger.verbose('load instances'); + const set = async (name: string) => { + const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache); + instance.instanceName = name; + this.logger.verbose('instance loaded: ' + name); + + await instance.connectToWhatsapp(); + this.logger.verbose('connectToWhatsapp: ' + name); + + this.waInstances[name] = instance; + }; try { if (this.redis.ENABLED) { - await this.loadInstancesFromRedis(); - } else if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - await this.loadInstancesFromDatabase(); - } else { - await this.loadInstancesFromFiles(); + this.logger.verbose('redis enabled'); + await this.cache.connect(this.redis as Redis); + const keys = await this.cache.instanceKeys(); + if (keys?.length > 0) { + this.logger.verbose('reading instance keys and setting instances'); + keys.forEach(async (k) => await set(k.split(':')[1])); + } else { + this.logger.verbose('no instance keys found'); + } + return; + } + + if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { + this.logger.verbose('database enabled'); + await this.repository.dbServer.connect(); + const collections: any[] = await this.dbInstance.collections(); + if (collections.length > 0) { + this.logger.verbose('reading collections and setting instances'); + collections.forEach(async (coll) => await set(coll.namespace.replace(/^[\w-]+\./, ''))); + } else { + this.logger.verbose('no collections found'); + } + return; + } + + this.logger.verbose('store in files enabled'); + const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); + for await (const dirent of dir) { + if (dirent.isDirectory()) { + this.logger.verbose('reading instance files and setting instances'); + const files = readdirSync(join(INSTANCE_DIR, dirent.name), { + encoding: 'utf-8', + }); + if (files.length === 0) { + rmSync(join(INSTANCE_DIR, dirent.name), { recursive: true, force: true }); + break; + } + + await set(dirent.name); + } else { + this.logger.verbose('no instance files found'); + } } } catch (error) { this.logger.error(error); } } - private async setInstance(name: string) { - const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache); - instance.instanceName = name; - this.logger.verbose('Instance loaded: ' + name); - - await instance.connectToWhatsapp(); - this.logger.verbose('connectToWhatsapp: ' + name); - - this.waInstances[name] = instance; - } - - private async loadInstancesFromRedis() { - this.logger.verbose('Redis enabled'); - await this.cache.connect(this.redis as Redis); - const keys = await this.cache.instanceKeys(); - - if (keys?.length > 0) { - this.logger.verbose('Reading instance keys and setting instances'); - await Promise.all(keys.map((k) => this.setInstance(k.split(':')[1]))); - } else { - this.logger.verbose('No instance keys found'); - } - } - - private async loadInstancesFromDatabase() { - this.logger.verbose('Database enabled'); - await this.repository.dbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - - if (collections.length > 0) { - this.logger.verbose('Reading collections and setting instances'); - await Promise.all(collections.map((coll) => this.setInstance(coll.namespace.replace(/^[\w-]+\./, '')))); - } else { - this.logger.verbose('No collections found'); - } - } - - private async loadInstancesFromFiles() { - this.logger.verbose('Store in files enabled'); - const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); - const instanceDirs = []; - - for await (const dirent of dir) { - if (dirent.isDirectory()) { - instanceDirs.push(dirent.name); - } else { - this.logger.verbose('No instance files found'); - } - } - - await Promise.all( - instanceDirs.map(async (instanceName) => { - this.logger.verbose('Reading instance files and setting instances: ' + instanceName); - const files = readdirSync(join(INSTANCE_DIR, instanceName), { encoding: 'utf-8' }); - - if (files.length === 0) { - rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); - } else { - await this.setInstance(instanceName); - } - }), - ); - } - private removeInstance() { this.eventEmitter.on('remove.instance', async (instanceName: string) => { this.logger.verbose('remove instance: ' + instanceName); From 6c2b7dc6dcc346671c4b677ebd9f0e2e5b6051d1 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:38:37 -0300 Subject: [PATCH 07/16] Update env.config.ts --- src/config/env.config.ts | 63 ++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 9c63b893..873c54ce 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -70,6 +70,10 @@ export type Websocket = { ENABLED: boolean; }; +export type Chatwoot = { + USE_REPLY_ID: boolean; +}; + export type EventsWebhook = { APPLICATION_STARTUP: boolean; QRCODE_UPDATED: boolean; @@ -92,6 +96,11 @@ export type EventsWebhook = { GROUP_PARTICIPANTS_UPDATE: boolean; CALL: boolean; NEW_JWT_TOKEN: boolean; + TYPEBOT_START: boolean; + TYPEBOT_CHANGE_STATUS: boolean; + CHAMA_AI_ACTION: boolean; + ERRORS: boolean; + ERRORS_WEBHOOK: string; }; export type ApiKey = { KEY: string }; @@ -134,6 +143,7 @@ export interface Env { QRCODE: QrCode; AUTHENTICATION: Auth; PRODUCTION?: Production; + CHATWOOT?: Chatwoot; } export type Key = keyof Env; @@ -166,17 +176,17 @@ export class ConfigService { return { SERVER: { TYPE: process.env.SERVER_TYPE as 'http' | 'https', - PORT: Number.parseInt(process.env.SERVER_PORT), + PORT: Number.parseInt(process.env.SERVER_PORT) || 8080, URL: process.env.SERVER_URL, }, CORS: { - ORIGIN: process.env.CORS_ORIGIN.split(','), - METHODS: process.env.CORS_METHODS.split(',') as HttpMethods[], + ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'], + METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'], CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true', }, SSL_CONF: { - PRIVKEY: process.env?.SSL_CONF_PRIVKEY, - FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN, + PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '', + FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '', }, STORE: { MESSAGES: process.env?.STORE_MESSAGES === 'true', @@ -195,8 +205,8 @@ export class ConfigService { }, DATABASE: { CONNECTION: { - URI: process.env.DATABASE_CONNECTION_URI, - DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME, + URI: process.env.DATABASE_CONNECTION_URI || '', + DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', }, ENABLED: process.env?.DATABASE_ENABLED === 'true', SAVE_DATA: { @@ -209,27 +219,36 @@ export class ConfigService { }, REDIS: { ENABLED: process.env?.REDIS_ENABLED === 'true', - URI: process.env.REDIS_URI, - PREFIX_KEY: process.env.REDIS_PREFIX_KEY, + URI: process.env.REDIS_URI || '', + PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution', }, RABBITMQ: { ENABLED: process.env?.RABBITMQ_ENABLED === 'true', - URI: process.env.RABBITMQ_URI, + URI: process.env.RABBITMQ_URI || '', }, WEBSOCKET: { ENABLED: process.env?.WEBSOCKET_ENABLED === 'true', }, LOG: { - LEVEL: process.env?.LOG_LEVEL.split(',') as LogLevel[], + LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [ + 'ERROR', + 'WARN', + 'DEBUG', + 'INFO', + 'LOG', + 'VERBOSE', + 'DARK', + 'WEBHOOKS', + ], COLOR: process.env?.LOG_COLOR === 'true', BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error', }, - DEL_INSTANCE: process.env?.DEL_INSTANCE === 'true' - ? 5 + DEL_INSTANCE: isBooleanString(process.env?.DEL_INSTANCE) + ? process.env.DEL_INSTANCE === 'true' : Number.parseInt(process.env.DEL_INSTANCE) || false, WEBHOOK: { GLOBAL: { - URL: process.env?.WEBHOOK_GLOBAL_URL, + URL: process.env?.WEBHOOK_GLOBAL_URL || '', ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true', WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true', }, @@ -255,29 +274,37 @@ export class ConfigService { GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true', NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true', + TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true', + TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', + CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true', + ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true', + ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '', }, }, CONFIG_SESSION_PHONE: { CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API', - NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'chrome', + NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome', }, QRCODE: { LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30, COLOR: process.env.QRCODE_COLOR || '#198754', }, AUTHENTICATION: { - TYPE: process.env.AUTHENTICATION_TYPE as 'jwt', + TYPE: process.env.AUTHENTICATION_TYPE as 'apikey', API_KEY: { - KEY: process.env.AUTHENTICATION_API_KEY, + KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ', }, EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true', JWT: { EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN) ? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN) : 3600, - SECRET: process.env.AUTHENTICATION_JWT_SECRET, + SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`', }, }, + CHATWOOT: { + USE_REPLY_ID: process.env?.USE_REPLY_ID === 'true', + }, }; } } From ce4113142452d7d5429ea20d4f0bdb12da2a1e05 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:40:59 -0300 Subject: [PATCH 08/16] Update main.ts --- src/main.ts | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index 75dd95b3..e239f83a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,12 @@ import 'express-async-errors'; +import axios from 'axios'; import compression from 'compression'; import cors from 'cors'; import express, { json, NextFunction, Request, Response, urlencoded } from 'express'; import { join } from 'path'; -import { configService, Cors, HttpServer, Rabbitmq } from './config/env.config'; +import { Auth, configService, Cors, HttpServer, Rabbitmq, Webhook } from './config/env.config'; import { onUnexpectedError } from './config/error.config'; import { Logger } from './config/logger.config'; import { ROOT_DIR } from './config/path.config'; @@ -47,11 +48,45 @@ function bootstrap() { app.set('views', join(ROOT_DIR, 'views')); app.use(express.static(join(ROOT_DIR, 'public'))); + app.use('/store', express.static(join(ROOT_DIR, 'store'))); + app.use('/', router); app.use( (err: Error, req: Request, res: Response, next: NextFunction) => { if (err) { + const webhook = configService.get('WEBHOOK'); + + if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) { + const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds + const localISOTime = new Date(Date.now() - tzoffset).toISOString(); + const now = localISOTime; + const globalApiKey = configService.get('AUTHENTICATION').API_KEY.KEY; + const serverUrl = configService.get('SERVER').URL; + + const errorData = { + event: 'error', + data: { + error: err['error'] || 'Internal Server Error', + message: err['message'] || 'Internal Server Error', + status: err['status'] || 500, + response: { + message: err['message'] || 'Internal Server Error', + }, + }, + date_time: now, + api_key: globalApiKey, + server_url: serverUrl, + }; + + logger.error(errorData); + + const baseURL = webhook.EVENTS.ERRORS_WEBHOOK; + const httpService = axios.create({ baseURL }); + + httpService.post('', errorData); + } + return res.status(err['status'] || 500).json({ status: err['status'] || 500, error: err['error'] || 'Internal Server Error', @@ -89,7 +124,7 @@ function bootstrap() { initIO(server); - if (configService.get('RABBITMQ').ENABLED) initAMQP(); + if (configService.get('RABBITMQ')?.ENABLED) initAMQP(); onUnexpectedError(); } From 86fec6fb24c3518a25a153ecca5a0abbe722cc1b Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 01:43:09 -0300 Subject: [PATCH 09/16] Update instance.controller.ts --- .../controllers/instance.controller.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index 2a904761..8d0e21ca 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -67,6 +67,7 @@ export class InstanceController { typebot_keyword_finish, typebot_delay_message, typebot_unknown_message, + typebot_listening_from_me, }: InstanceDto) { try { this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); @@ -126,6 +127,9 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { newEvents = events; @@ -172,9 +176,12 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { - newEvents = events; + newEvents = websocket_events; } this.websocketService.create(instance, { enabled: true, @@ -216,9 +223,12 @@ export class InstanceController { 'CONNECTION_UPDATE', 'CALL', 'NEW_JWT_TOKEN', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'CHAMA_AI_ACTION', ]; } else { - newEvents = events; + newEvents = rabbitmq_events; } this.rabbitmqService.create(instance, { enabled: true, @@ -247,6 +257,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }); } catch (error) { this.logger.log(error); @@ -304,6 +315,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }, settings, qrcode: getQrcode, @@ -396,6 +408,7 @@ export class InstanceController { keyword_finish: typebot_keyword_finish, delay_message: typebot_delay_message, unknown_message: typebot_unknown_message, + listening_from_me: typebot_listening_from_me, }, settings, chatwoot: { @@ -482,12 +495,13 @@ export class InstanceController { } public async fetchInstances({ instanceName }: InstanceDto) { - this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); if (instanceName) { + this.logger.verbose('requested fetchInstances from ' + instanceName + ' instance'); this.logger.verbose('instanceName: ' + instanceName); return this.waMonitor.instanceInfo(instanceName); } + this.logger.verbose('requested fetchInstances (all instances)'); return this.waMonitor.instanceInfo(); } From f298c43cd74cd3d55f9321dd490cc8b9a511bfa2 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 07:50:21 -0300 Subject: [PATCH 10/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 236 ++++++++++++----------- 1 file changed, 119 insertions(+), 117 deletions(-) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index 039a5f29..bd7fed48 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -7,7 +7,6 @@ import { join } from 'path'; import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; -import { NotFoundException } from '../../exceptions'; import { dbserver } from '../../libs/db.connect'; import { RedisCache } from '../../libs/redis.client'; import { @@ -76,77 +75,59 @@ export class WAMonitoringService { public async instanceInfo(instanceName?: string) { this.logger.verbose('get instance info'); - if (instanceName && !this.waInstances[instanceName]) { - throw new NotFoundException(`Instance "${instanceName}" not found`); - } - const instances: any[] = []; + const urlServer = this.configService.get('SERVER').URL; - for await (const [key, value] of Object.entries(this.waInstances)) { - if (value) { - this.logger.verbose('get instance info: ' + key); - let chatwoot: any; + const instances: any[] = await Promise.all( + Object.entries(this.waInstances).map(async ([key, value]) => { + const status = value?.connectionStatus?.state || 'unknown'; - const urlServer = this.configService.get('SERVER').URL; - - const findChatwoot = await this.waInstances[key].findChatwoot(); - - if (findChatwoot && findChatwoot.enabled) { - chatwoot = { - ...findChatwoot, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, - }; + if (status === 'unknown') { + return null; } - if (value.connectionStatus.state === 'open') { + if (status === 'open') { this.logger.verbose('instance: ' + key + ' - connectionStatus: open'); - - const instanceData = { - instance: { - instanceName: key, - owner: value.wuid, - profileName: (await value.getProfileName()) || 'not loaded', - profilePictureUrl: value.profilePictureUrl, - profileStatus: (await value.getProfileStatus()) || '', - status: value.connectionStatus.state, - }, - }; - - if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - - instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; - - instanceData.instance['chatwoot'] = chatwoot; - } - - instances.push(instanceData); - } else { - this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state); - - const instanceData = { - instance: { - instanceName: key, - status: value.connectionStatus.state, - }, - }; - - if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - - instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; - - instanceData.instance['chatwoot'] = chatwoot; - } - - instances.push(instanceData); } - } - } + + const instanceData: any = { + instance: { + instanceName: key, + owner: value.wuid, + profileName: (await value.getProfileName()) || 'not loaded', + profilePictureUrl: value.profilePictureUrl, + profileStatus: (await value.getProfileStatus()) || '', + status: status, + }, + }; + + if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { + // instanceData.instance.serverUrl = urlServer; + instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; + // instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; + instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + + const findChatwoot = await this.waInstances[key].findChatwoot(); + if (findChatwoot && findChatwoot.enabled) { + instanceData.instance.chatwoot = { + ...findChatwoot, + webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, + }; + } + } + + return instanceData; + }), + ).then((results) => results.filter((instance) => instance !== null)); this.logger.verbose('return instance info: ' + instances.length); - return instances.find((i) => i.instance.instanceName === instanceName) ?? instances; + if (instanceName) { + const instance = instances.find((i) => i.instance.instanceName === instanceName); + return instance || []; + } + + return instances; } private delInstanceFiles() { @@ -161,8 +142,7 @@ export class WAMonitoringService { }); this.logger.verbose('instance files deleted: ' + name); }); - // } else if (this.redis.ENABLED) { - } else { + } else if (!this.redis.ENABLED) { const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); for await (const dirent of dir) { if (dirent.isDirectory()) { @@ -220,6 +200,11 @@ export class WAMonitoringService { execSync(`rm -rf ${join(STORE_DIR, 'auth', 'apikey', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'webhook', instanceName + '.json')}`); execSync(`rm -rf ${join(STORE_DIR, 'chatwoot', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'chamaai', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'proxy', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'rabbitmq', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`); + execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`); execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`); return; @@ -240,68 +225,85 @@ export class WAMonitoringService { } public async loadInstance() { - this.logger.verbose('load instances'); - const set = async (name: string) => { - const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache); - instance.instanceName = name; - this.logger.verbose('instance loaded: ' + name); - - await instance.connectToWhatsapp(); - this.logger.verbose('connectToWhatsapp: ' + name); - - this.waInstances[name] = instance; - }; + this.logger.verbose('Loading instances'); try { if (this.redis.ENABLED) { - this.logger.verbose('redis enabled'); - await this.cache.connect(this.redis as Redis); - const keys = await this.cache.instanceKeys(); - if (keys?.length > 0) { - this.logger.verbose('reading instance keys and setting instances'); - keys.forEach(async (k) => await set(k.split(':')[1])); - } else { - this.logger.verbose('no instance keys found'); - } - return; - } - - if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - this.logger.verbose('database enabled'); - await this.repository.dbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - if (collections.length > 0) { - this.logger.verbose('reading collections and setting instances'); - collections.forEach(async (coll) => await set(coll.namespace.replace(/^[\w-]+\./, ''))); - } else { - this.logger.verbose('no collections found'); - } - return; - } - - this.logger.verbose('store in files enabled'); - const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); - for await (const dirent of dir) { - if (dirent.isDirectory()) { - this.logger.verbose('reading instance files and setting instances'); - const files = readdirSync(join(INSTANCE_DIR, dirent.name), { - encoding: 'utf-8', - }); - if (files.length === 0) { - rmSync(join(INSTANCE_DIR, dirent.name), { recursive: true, force: true }); - break; - } - - await set(dirent.name); - } else { - this.logger.verbose('no instance files found'); - } + await this.loadInstancesFromRedis(); + } else if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { + await this.loadInstancesFromDatabase(); + } else { + await this.loadInstancesFromFiles(); } } catch (error) { this.logger.error(error); } } + private async setInstance(name: string) { + const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache); + instance.instanceName = name; + this.logger.verbose('Instance loaded: ' + name); + + await instance.connectToWhatsapp(); + this.logger.verbose('connectToWhatsapp: ' + name); + + this.waInstances[name] = instance; + } + + private async loadInstancesFromRedis() { + this.logger.verbose('Redis enabled'); + await this.cache.connect(this.redis as Redis); + const keys = await this.cache.instanceKeys(); + + if (keys?.length > 0) { + this.logger.verbose('Reading instance keys and setting instances'); + await Promise.all(keys.map((k) => this.setInstance(k.split(':')[1]))); + } else { + this.logger.verbose('No instance keys found'); + } + } + + private async loadInstancesFromDatabase() { + this.logger.verbose('Database enabled'); + await this.repository.dbServer.connect(); + const collections: any[] = await this.dbInstance.collections(); + + if (collections.length > 0) { + this.logger.verbose('Reading collections and setting instances'); + await Promise.all(collections.map((coll) => this.setInstance(coll.namespace.replace(/^[\w-]+\./, '')))); + } else { + this.logger.verbose('No collections found'); + } + } + + private async loadInstancesFromFiles() { + this.logger.verbose('Store in files enabled'); + const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); + const instanceDirs = []; + + for await (const dirent of dir) { + if (dirent.isDirectory()) { + instanceDirs.push(dirent.name); + } else { + this.logger.verbose('No instance files found'); + } + } + + await Promise.all( + instanceDirs.map(async (instanceName) => { + this.logger.verbose('Reading instance files and setting instances: ' + instanceName); + const files = readdirSync(join(INSTANCE_DIR, instanceName), { encoding: 'utf-8' }); + + if (files.length === 0) { + rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); + } else { + await this.setInstance(instanceName); + } + }), + ); + } + private removeInstance() { this.eventEmitter.on('remove.instance', async (instanceName: string) => { this.logger.verbose('remove instance: ' + instanceName); From 939533448b0440763eb16cf5d945a6cbeed4be07 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 07:52:34 -0300 Subject: [PATCH 11/16] Update monitor.service.ts From c2d57f38fbb062714a40b49070d082b3ab5c8a55 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 08:13:24 -0300 Subject: [PATCH 12/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index bd7fed48..16494476 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -7,6 +7,9 @@ import { join } from 'path'; import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; +//inserido por Francis inicio +import { NotFoundException } from '../../exceptions'; +//inserido por Francis final import { dbserver } from '../../libs/db.connect'; import { RedisCache } from '../../libs/redis.client'; import { @@ -76,6 +79,14 @@ export class WAMonitoringService { public async instanceInfo(instanceName?: string) { this.logger.verbose('get instance info'); + //inserido pot Francis - inicio + + if (instanceName && !this.waInstances[instanceName]) { + throw new NotFoundException(`Instance "${instanceName}" not found`); + } + //inserido pot Francis - inicio + + const urlServer = this.configService.get('SERVER').URL; const instances: any[] = await Promise.all( @@ -102,11 +113,10 @@ export class WAMonitoringService { }; if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - // instanceData.instance.serverUrl = urlServer; - instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - // instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; - instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + instanceData.instance.serverUrl = urlServer; + instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; + const findChatwoot = await this.waInstances[key].findChatwoot(); if (findChatwoot && findChatwoot.enabled) { instanceData.instance.chatwoot = { From 8932fd0ada56e30d000ba5745660e306fda722b0 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 08:26:31 -0300 Subject: [PATCH 13/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index 16494476..fe6cec86 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -108,7 +108,8 @@ export class WAMonitoringService { profileName: (await value.getProfileName()) || 'not loaded', profilePictureUrl: value.profilePictureUrl, profileStatus: (await value.getProfileStatus()) || '', - status: status, + //status: status, + status: value.connectionStatus.state, }, }; From 789aadef03d1b4ae953aa35a6551018c20dac79e Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 08:37:55 -0300 Subject: [PATCH 14/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 111 +++++++++++++++++++---- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index fe6cec86..d0975b17 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -7,9 +7,6 @@ import { join } from 'path'; import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; -//inserido por Francis inicio -import { NotFoundException } from '../../exceptions'; -//inserido por Francis final import { dbserver } from '../../libs/db.connect'; import { RedisCache } from '../../libs/redis.client'; import { @@ -75,18 +72,10 @@ export class WAMonitoringService { }, 1000 * 60 * time); } } - +/* ocultado por francis inicio public async instanceInfo(instanceName?: string) { this.logger.verbose('get instance info'); - //inserido pot Francis - inicio - - if (instanceName && !this.waInstances[instanceName]) { - throw new NotFoundException(`Instance "${instanceName}" not found`); - } - //inserido pot Francis - inicio - - const urlServer = this.configService.get('SERVER').URL; const instances: any[] = await Promise.all( @@ -108,15 +97,13 @@ export class WAMonitoringService { profileName: (await value.getProfileName()) || 'not loaded', profilePictureUrl: value.profilePictureUrl, profileStatus: (await value.getProfileStatus()) || '', - //status: status, - status: value.connectionStatus.state, + status: status, }, }; if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance.serverUrl = urlServer; - instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; - + instanceData.instance.serverUrl = urlServer; + instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey; const findChatwoot = await this.waInstances[key].findChatwoot(); if (findChatwoot && findChatwoot.enabled) { @@ -141,6 +128,96 @@ export class WAMonitoringService { return instances; } +ocultado por francis fim */ + +// inserido por francis inicio + +public async instanceInfo(instanceName?: string) { + this.logger.verbose('get instance info'); + if (instanceName && !this.waInstances[instanceName]) { + throw new NotFoundException(`Instance "${instanceName}" not found`); + } + + const instances: any[] = []; + + for await (const [key, value] of Object.entries(this.waInstances)) { + if (value) { + this.logger.verbose('get instance info: ' + key); + let chatwoot: any; + + const urlServer = this.configService.get('SERVER').URL; + + const findChatwoot = await this.waInstances[key].findChatwoot(); + + if (findChatwoot && findChatwoot.enabled) { + chatwoot = { + ...findChatwoot, + webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, + }; + } + + if (value.connectionStatus.state === 'open') { + this.logger.verbose('instance: ' + key + ' - connectionStatus: open'); + + const instanceData = { + instance: { + instanceName: key, + owner: value.wuid, + profileName: (await value.getProfileName()) || 'not loaded', + profilePictureUrl: value.profilePictureUrl, + profileStatus: (await value.getProfileStatus()) || '', + status: value.connectionStatus.state, + }, + }; + + if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { + instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; + + instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + + instanceData.instance['chatwoot'] = chatwoot; + } + + instances.push(instanceData); + } else { + this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state); + + const instanceData = { + instance: { + instanceName: key, + status: value.connectionStatus.state, + }, + }; + + if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { + instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; + + instanceData.instance['apikey'] = (await this.repository.auth.find(key)).apikey; + + instanceData.instance['chatwoot'] = chatwoot; + } + + instances.push(instanceData); + } + } + } + + this.logger.verbose('return instance info: ' + instances.length); + + return instances.find((i) => i.instance.instanceName === instanceName) ?? instances; + } + + + +// inserido por francis fim + + + + + + + + private delInstanceFiles() { this.logger.verbose('cron to delete instance files started'); setInterval(async () => { From d3e409c9b98b27523ac1f03a1a93d32e962b29e3 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 08:43:04 -0300 Subject: [PATCH 15/16] Update monitor.service.ts --- src/whatsapp/services/monitor.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/whatsapp/services/monitor.service.ts b/src/whatsapp/services/monitor.service.ts index d0975b17..c7574968 100644 --- a/src/whatsapp/services/monitor.service.ts +++ b/src/whatsapp/services/monitor.service.ts @@ -7,6 +7,9 @@ import { join } from 'path'; import { Auth, ConfigService, Database, DelInstance, HttpServer, Redis } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; +// inserido por francis inicio +import { NotFoundException } from '../../exceptions'; +// inserido por francis fim import { dbserver } from '../../libs/db.connect'; import { RedisCache } from '../../libs/redis.client'; import { From cab77733b4e19271f9c20b4eef7a2f303313e1d8 Mon Sep 17 00:00:00 2001 From: Francis Breit Date: Wed, 20 Sep 2023 08:45:01 -0300 Subject: [PATCH 16/16] Update monitor.service.ts