From 9b72b3e332de2b74082078b0f585e93266030c45 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Fri, 25 Aug 2023 09:01:48 -0300 Subject: [PATCH] Added webhook to send errors --- CHANGELOG.md | 1 + Docker/.env.example | 2 ++ Dockerfile | 2 ++ src/config/env.config.ts | 2 ++ src/dev-env.yml | 2 ++ src/main.ts | 31 ++++++++++++++++++- src/whatsapp/guards/instance.guard.ts | 43 ++++++++++++++++----------- 7 files changed, 65 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5701dfb4..427a412b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Added variables options in Start Typebot * Added webhooks for typebot events * Added ChamaAI integration +* Added webhook to send errors ### Fixed diff --git a/Docker/.env.example b/Docker/.env.example index 69ceaf23..ef70e704 100644 --- a/Docker/.env.example +++ b/Docker/.env.example @@ -86,6 +86,8 @@ WEBHOOK_EVENTS_TYPEBOT_START=false WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false # This event is used with Chama AI WEBHOOK_EVENTS_CHAMA_AI_ACTION=false +# This event is used to send errors +WEBHOOK_EVENTS_ERRORS=false # Name that will be displayed on smartphone connection CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI diff --git a/Dockerfile b/Dockerfile index d4defe07..76699acb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -89,6 +89,8 @@ ENV WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false ENV WEBHOOK_EVENTS_CHAMA_AI_ACTION=false +ENV WEBHOOK_EVENTS_ERRORS=false + ENV CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI ENV CONFIG_SESSION_PHONE_NAME=chrome diff --git a/src/config/env.config.ts b/src/config/env.config.ts index a2255b32..fb566eaf 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -95,6 +95,7 @@ export type EventsWebhook = { TYPEBOT_START: boolean; TYPEBOT_CHANGE_STATUS: boolean; CHAMA_AI_ACTION: boolean; + ERRORS: boolean; }; export type ApiKey = { KEY: string }; @@ -270,6 +271,7 @@ export class ConfigService { 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', }, }, CONFIG_SESSION_PHONE: { diff --git a/src/dev-env.yml b/src/dev-env.yml index bd9ad277..624137e7 100644 --- a/src/dev-env.yml +++ b/src/dev-env.yml @@ -125,6 +125,8 @@ WEBHOOK: TYPEBOT_CHANGE_STATUS: false # This event is used with Chama AI CHAMA_AI_ACTION: false + # This event is used to send errors to the webhook + ERRORS: false CONFIG_SESSION_PHONE: # Name that will be displayed on smartphone connection diff --git a/src/main.ts b/src/main.ts index 2095bd4c..5727575c 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 { 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'; @@ -54,6 +55,34 @@ function bootstrap() { app.use( (err: Error, req: Request, res: Response, next: NextFunction) => { if (err) { + const webhook = configService.get('WEBHOOK'); + + if (webhook.GLOBAL.ENABLED && webhook.EVENTS.ERRORS) { + const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds + const localISOTime = new Date(Date.now() - tzoffset).toISOString(); + const now = localISOTime; + + 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, + }; + + logger.error(errorData); + + const baseURL = configService.get('WEBHOOK').GLOBAL.URL; + 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', diff --git a/src/whatsapp/guards/instance.guard.ts b/src/whatsapp/guards/instance.guard.ts index 144f4d40..e5b7ebe0 100644 --- a/src/whatsapp/guards/instance.guard.ts +++ b/src/whatsapp/guards/instance.guard.ts @@ -4,31 +4,40 @@ import { join } from 'path'; import { configService, Database, Redis } from '../../config/env.config'; import { INSTANCE_DIR } from '../../config/path.config'; -import { BadRequestException, ForbiddenException, NotFoundException } from '../../exceptions'; +import { + BadRequestException, + ForbiddenException, + InternalServerErrorException, + NotFoundException, +} from '../../exceptions'; import { dbserver } from '../../libs/db.connect'; import { InstanceDto } from '../dto/instance.dto'; import { cache, waMonitor } from '../whatsapp.module'; async function getInstance(instanceName: string) { - const db = configService.get('DATABASE'); - const redisConf = configService.get('REDIS'); + try { + const db = configService.get('DATABASE'); + const redisConf = configService.get('REDIS'); - const exists = !!waMonitor.waInstances[instanceName]; + const exists = !!waMonitor.waInstances[instanceName]; - if (redisConf.ENABLED) { - const keyExists = await cache.keyExists(); - return exists || keyExists; + if (redisConf.ENABLED) { + const keyExists = await cache.keyExists(); + return exists || keyExists; + } + + if (db.ENABLED) { + const collection = dbserver + .getClient() + .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') + .collection(instanceName); + return exists || (await collection.find({}).toArray()).length > 0; + } + + return exists || existsSync(join(INSTANCE_DIR, instanceName)); + } catch (error) { + throw new InternalServerErrorException(error?.toString()); } - - if (db.ENABLED) { - const collection = dbserver - .getClient() - .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(instanceName); - return exists || (await collection.find({}).toArray()).length > 0; - } - - return exists || existsSync(join(INSTANCE_DIR, instanceName)); } export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) {