mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-12-18 19:32:21 -06:00
Merge branch 'develop' into fetch-profile
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { isBooleanString } from 'class-validator';
|
||||
import { readFileSync } from 'fs';
|
||||
import { load } from 'js-yaml';
|
||||
import { join } from 'path';
|
||||
import { isBooleanString } from 'class-validator';
|
||||
|
||||
export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string };
|
||||
|
||||
@@ -14,15 +14,7 @@ export type Cors = {
|
||||
|
||||
export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
||||
|
||||
export type LogLevel =
|
||||
| 'ERROR'
|
||||
| 'WARN'
|
||||
| 'DEBUG'
|
||||
| 'INFO'
|
||||
| 'LOG'
|
||||
| 'VERBOSE'
|
||||
| 'DARK'
|
||||
| 'WEBHOOKS';
|
||||
export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS';
|
||||
|
||||
export type Log = {
|
||||
LEVEL: LogLevel[];
|
||||
@@ -69,6 +61,15 @@ export type Redis = {
|
||||
PREFIX_KEY: string;
|
||||
};
|
||||
|
||||
export type Rabbitmq = {
|
||||
ENABLED: boolean;
|
||||
URI: string;
|
||||
};
|
||||
|
||||
export type Websocket = {
|
||||
ENABLED: boolean;
|
||||
};
|
||||
|
||||
export type EventsWebhook = {
|
||||
APPLICATION_STARTUP: boolean;
|
||||
QRCODE_UPDATED: boolean;
|
||||
@@ -89,25 +90,23 @@ export type EventsWebhook = {
|
||||
GROUPS_UPSERT: boolean;
|
||||
GROUP_UPDATE: boolean;
|
||||
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 };
|
||||
export type Jwt = { EXPIRIN_IN: number; SECRET: string };
|
||||
export type Instance = {
|
||||
NAME: string;
|
||||
WEBHOOK_URL: string;
|
||||
MODE: string;
|
||||
CHATWOOT_ACCOUNT_ID: string;
|
||||
CHATWOOT_TOKEN: string;
|
||||
CHATWOOT_URL: string;
|
||||
};
|
||||
|
||||
export type Auth = {
|
||||
API_KEY: ApiKey;
|
||||
EXPOSE_IN_FETCH_INSTANCES: boolean;
|
||||
JWT: Jwt;
|
||||
TYPE: 'jwt' | 'apikey';
|
||||
INSTANCE: Instance;
|
||||
};
|
||||
|
||||
export type DelInstance = number | boolean;
|
||||
@@ -120,7 +119,7 @@ export type GlobalWebhook = {
|
||||
export type SslConf = { PRIVKEY: string; FULLCHAIN: string };
|
||||
export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
|
||||
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
|
||||
export type QrCode = { LIMIT: number };
|
||||
export type QrCode = { LIMIT: number; COLOR: string };
|
||||
export type Production = boolean;
|
||||
|
||||
export interface Env {
|
||||
@@ -131,6 +130,8 @@ export interface Env {
|
||||
CLEAN_STORE: CleanStoreConf;
|
||||
DATABASE: Database;
|
||||
REDIS: Redis;
|
||||
RABBITMQ: Rabbitmq;
|
||||
WEBSOCKET: Websocket;
|
||||
LOG: Log;
|
||||
DEL_INSTANCE: DelInstance;
|
||||
WEBHOOK: Webhook;
|
||||
@@ -163,26 +164,24 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
private envYaml(): Env {
|
||||
return load(
|
||||
readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' }),
|
||||
) as Env;
|
||||
return load(readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' })) as Env;
|
||||
}
|
||||
|
||||
private envProcess(): Env {
|
||||
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',
|
||||
@@ -201,8 +200,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: {
|
||||
@@ -215,11 +214,27 @@ 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 || '',
|
||||
},
|
||||
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',
|
||||
},
|
||||
@@ -228,7 +243,7 @@ export class ConfigService {
|
||||
: 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',
|
||||
},
|
||||
@@ -251,39 +266,35 @@ export class ConfigService {
|
||||
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
|
||||
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
|
||||
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
|
||||
GROUP_PARTICIPANTS_UPDATE:
|
||||
process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
|
||||
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',
|
||||
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,
|
||||
},
|
||||
INSTANCE: {
|
||||
NAME: process.env.AUTHENTICATION_INSTANCE_NAME,
|
||||
WEBHOOK_URL: process.env.AUTHENTICATION_INSTANCE_WEBHOOK_URL,
|
||||
MODE: process.env.AUTHENTICATION_INSTANCE_MODE,
|
||||
CHATWOOT_ACCOUNT_ID:
|
||||
process.env.AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID || '',
|
||||
CHATWOOT_TOKEN: process.env.AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN || '',
|
||||
CHATWOOT_URL: process.env.AUTHENTICATION_INSTANCE_CHATWOOT_URL || '',
|
||||
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ export function onUnexpectedError() {
|
||||
stderr: process.stderr.fd,
|
||||
error,
|
||||
});
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (error, origin) => {
|
||||
@@ -17,5 +18,6 @@ export function onUnexpectedError() {
|
||||
stderr: process.stderr.fd,
|
||||
error,
|
||||
});
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { configService, Log } from './env.config';
|
||||
import dayjs from 'dayjs';
|
||||
import fs from 'fs';
|
||||
|
||||
import { configService, Log } from './env.config';
|
||||
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
|
||||
const formatDateLog = (timestamp: number) =>
|
||||
dayjs(timestamp)
|
||||
@@ -73,6 +76,8 @@ export class Logger {
|
||||
/*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type],
|
||||
'[Evolution API]',
|
||||
Command.BRIGHT + Color[type],
|
||||
`v${packageJson.version}`,
|
||||
Command.BRIGHT + Color[type],
|
||||
process.pid.toString(),
|
||||
Command.RESET,
|
||||
Command.BRIGHT + Color[type],
|
||||
|
||||
@@ -79,6 +79,13 @@ REDIS:
|
||||
URI: "redis://localhost:6379"
|
||||
PREFIX_KEY: "evolution"
|
||||
|
||||
RABBITMQ:
|
||||
ENABLED: false
|
||||
URI: "amqp://guest:guest@localhost:5672"
|
||||
|
||||
WEBSOCKET:
|
||||
ENABLED: false
|
||||
|
||||
# Global Webhook Settings
|
||||
# Each instance's Webhook URL and events will be requested at the time it is created
|
||||
WEBHOOK:
|
||||
@@ -110,17 +117,27 @@ WEBHOOK:
|
||||
GROUP_UPDATE: true
|
||||
GROUP_PARTICIPANTS_UPDATE: true
|
||||
CONNECTION_UPDATE: true
|
||||
CALL: true
|
||||
# This event fires every time a new token is requested via the refresh route
|
||||
NEW_JWT_TOKEN: false
|
||||
# This events is used with Typebot
|
||||
TYPEBOT_START: false
|
||||
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
|
||||
ERRORS_WEBHOOK: <url>
|
||||
|
||||
CONFIG_SESSION_PHONE:
|
||||
# Name that will be displayed on smartphone connection
|
||||
CLIENT: "Evolution API"
|
||||
NAME: chrome # chrome | firefox | edge | opera | safari
|
||||
NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari
|
||||
|
||||
# Set qrcode display limit
|
||||
QRCODE:
|
||||
LIMIT: 30
|
||||
COLOR: "#198754"
|
||||
|
||||
# Defines an authentication type for the api
|
||||
# We recommend using the apikey because it will allow you to use a custom token,
|
||||
@@ -137,13 +154,3 @@ AUTHENTICATION:
|
||||
JWT:
|
||||
EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires
|
||||
SECRET: L=0YWt]b2w[WF>#>:&E`
|
||||
# Set the instance name and webhook url to create an instance in init the application
|
||||
INSTANCE:
|
||||
# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event
|
||||
MODE: server # container or server
|
||||
# if you are using container mode, set the container name and the webhook url to default instance
|
||||
NAME: evolution
|
||||
WEBHOOK_URL: <url>
|
||||
CHATWOOT_ACCOUNT_ID: 1
|
||||
CHATWOOT_TOKEN: 123456
|
||||
CHATWOOT_URL: <url>
|
||||
|
||||
@@ -5,7 +5,7 @@ export class UnauthorizedException {
|
||||
throw {
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
error: 'Unauthorized',
|
||||
message: objectError.length > 0 ? objectError : undefined,
|
||||
message: objectError.length > 0 ? objectError : 'Unauthorized',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
73
src/libs/amqp.server.ts
Normal file
73
src/libs/amqp.server.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import * as amqp from 'amqplib/callback_api';
|
||||
|
||||
import { configService, Rabbitmq } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
const logger = new Logger('AMQP');
|
||||
|
||||
let amqpChannel: amqp.Channel | null = null;
|
||||
|
||||
export const initAMQP = () => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
|
||||
amqp.connect(uri, (error, connection) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
connection.createChannel((channelError, channel) => {
|
||||
if (channelError) {
|
||||
reject(channelError);
|
||||
return;
|
||||
}
|
||||
|
||||
const exchangeName = 'evolution_exchange';
|
||||
|
||||
channel.assertExchange(exchangeName, 'topic', {
|
||||
durable: true,
|
||||
autoDelete: false,
|
||||
});
|
||||
|
||||
amqpChannel = channel;
|
||||
|
||||
logger.info('AMQP initialized');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getAMQP = (): amqp.Channel | null => {
|
||||
return amqpChannel;
|
||||
};
|
||||
|
||||
export const initQueues = (instanceName: string, events: string[]) => {
|
||||
if (!events || !events.length) return;
|
||||
|
||||
const queues = events.map((event) => {
|
||||
return `${event.replace(/_/g, '.').toLowerCase()}`;
|
||||
});
|
||||
|
||||
queues.forEach((event) => {
|
||||
const amqp = getAMQP();
|
||||
const exchangeName = instanceName ?? 'evolution_exchange';
|
||||
|
||||
amqp.assertExchange(exchangeName, 'topic', {
|
||||
durable: true,
|
||||
autoDelete: false,
|
||||
});
|
||||
|
||||
const queueName = `${instanceName}.${event}`;
|
||||
|
||||
amqp.assertQueue(queueName, {
|
||||
durable: true,
|
||||
autoDelete: false,
|
||||
arguments: {
|
||||
'x-queue-type': 'quorum',
|
||||
},
|
||||
});
|
||||
|
||||
amqp.bindQueue(queueName, exchangeName, event);
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { configService, Database } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { createClient, RedisClientType } from '@redis/client';
|
||||
import { Logger } from '../config/logger.config';
|
||||
import { BufferJSON } from '@whiskeysockets/baileys';
|
||||
|
||||
import { Redis } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
export class RedisCache {
|
||||
async disconnect() {
|
||||
await this.client.disconnect();
|
||||
this.statusConnection = false;
|
||||
}
|
||||
constructor() {
|
||||
this.logger.verbose('instance created');
|
||||
process.on('beforeExit', async () => {
|
||||
@@ -59,11 +64,7 @@ export class RedisCache {
|
||||
this.logger.verbose('writeData: ' + field);
|
||||
const json = JSON.stringify(data, BufferJSON.replacer);
|
||||
|
||||
return await this.client.hSet(
|
||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
||||
field,
|
||||
json,
|
||||
);
|
||||
return await this.client.hSet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field, json);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
@@ -72,10 +73,7 @@ export class RedisCache {
|
||||
public async readData(field: string) {
|
||||
try {
|
||||
this.logger.verbose('readData: ' + field);
|
||||
const data = await this.client.hGet(
|
||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
||||
field,
|
||||
);
|
||||
const data = await this.client.hGet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
|
||||
|
||||
if (data) {
|
||||
this.logger.verbose('readData: ' + field + ' success');
|
||||
@@ -92,10 +90,7 @@ export class RedisCache {
|
||||
public async removeData(field: string) {
|
||||
try {
|
||||
this.logger.verbose('removeData: ' + field);
|
||||
return await this.client.hDel(
|
||||
this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
||||
field,
|
||||
);
|
||||
return await this.client.hDel(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
@@ -104,9 +99,7 @@ export class RedisCache {
|
||||
public async delAll(hash?: string) {
|
||||
try {
|
||||
this.logger.verbose('instance delAll: ' + hash);
|
||||
const result = await this.client.del(
|
||||
hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName,
|
||||
);
|
||||
const result = await this.client.del(hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
44
src/libs/socket.server.ts
Normal file
44
src/libs/socket.server.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Server } from 'http';
|
||||
import { Server as SocketIO } from 'socket.io';
|
||||
|
||||
import { configService, Cors, Websocket } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
|
||||
const logger = new Logger('Socket');
|
||||
|
||||
let io: SocketIO;
|
||||
|
||||
const cors = configService.get<Cors>('CORS').ORIGIN;
|
||||
|
||||
export const initIO = (httpServer: Server) => {
|
||||
if (configService.get<Websocket>('WEBSOCKET').ENABLED) {
|
||||
io = new SocketIO(httpServer, {
|
||||
cors: {
|
||||
origin: cors,
|
||||
},
|
||||
});
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
logger.info('User connected');
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
logger.info('User disconnected');
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('Socket.io initialized');
|
||||
return io;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getIO = (): SocketIO => {
|
||||
logger.verbose('Getting Socket.io');
|
||||
|
||||
if (!io) {
|
||||
logger.error('Socket.io not initialized');
|
||||
throw new Error('Socket.io not initialized');
|
||||
}
|
||||
|
||||
return io;
|
||||
};
|
||||
103
src/main.ts
103
src/main.ts
@@ -1,16 +1,20 @@
|
||||
import 'express-async-errors';
|
||||
|
||||
import axios from 'axios';
|
||||
import compression from 'compression';
|
||||
import { configService, Cors, HttpServer } from './config/env.config';
|
||||
import cors from 'cors';
|
||||
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
||||
import { join } from 'path';
|
||||
|
||||
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';
|
||||
import { waMonitor } from './whatsapp/whatsapp.module';
|
||||
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
||||
import 'express-async-errors';
|
||||
import { initAMQP } from './libs/amqp.server';
|
||||
import { initIO } from './libs/socket.server';
|
||||
import { ServerUP } from './utils/server-up';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
||||
import { waMonitor } from './whatsapp/whatsapp.module';
|
||||
|
||||
function initWA() {
|
||||
waMonitor.loadInstance();
|
||||
@@ -20,32 +24,13 @@ function bootstrap() {
|
||||
const logger = new Logger('SERVER');
|
||||
const app = express();
|
||||
|
||||
// Sentry.init({
|
||||
// dsn: '',
|
||||
// integrations: [
|
||||
// // enable HTTP calls tracing
|
||||
// new Sentry.Integrations.Http({ tracing: true }),
|
||||
// // enable Express.js middleware tracing
|
||||
// new Sentry.Integrations.Express({ app }),
|
||||
// // Automatically instrument Node.js libraries and frameworks
|
||||
// ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(),
|
||||
// ],
|
||||
|
||||
// // Set tracesSampleRate to 1.0 to capture 100%
|
||||
// // of transactions for performance monitoring.
|
||||
// // We recommend adjusting this value in production
|
||||
// tracesSampleRate: 1.0,
|
||||
// });
|
||||
|
||||
// app.use(Sentry.Handlers.requestHandler());
|
||||
|
||||
// app.use(Sentry.Handlers.tracingHandler());
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin(requestOrigin, callback) {
|
||||
const { ORIGIN } = configService.get<Cors>('CORS');
|
||||
!requestOrigin ? (requestOrigin = '*') : undefined;
|
||||
if (ORIGIN.includes('*')) {
|
||||
return callback(null, true);
|
||||
}
|
||||
if (ORIGIN.indexOf(requestOrigin) !== -1) {
|
||||
return callback(null, true);
|
||||
}
|
||||
@@ -63,28 +48,66 @@ 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(Sentry.Handlers.errorHandler());
|
||||
|
||||
// app.use(function onError(err, req, res, next) {
|
||||
// res.statusCode = 500;
|
||||
// res.end(res.sentry + '\n');
|
||||
// });
|
||||
|
||||
app.use(
|
||||
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
if (err) {
|
||||
return res.status(err['status'] || 500).json(err);
|
||||
const webhook = configService.get<Webhook>('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 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 = webhook.EVENTS.ERRORS_WEBHOOK;
|
||||
const httpService = axios.create({ baseURL });
|
||||
|
||||
httpService.post('', errorData);
|
||||
}
|
||||
|
||||
if (err['message'].includes('No sessions')) {
|
||||
console.log(err['message']);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return res.status(err['status'] || 500).json({
|
||||
status: err['status'] || 500,
|
||||
error: err['error'] || 'Internal Server Error',
|
||||
response: {
|
||||
message: err['message'] || 'Internal Server Error',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const { method, url } = req;
|
||||
|
||||
res.status(HttpStatus.NOT_FOUND).json({
|
||||
status: HttpStatus.NOT_FOUND,
|
||||
message: `Cannot ${method.toUpperCase()} ${url}`,
|
||||
error: 'Not Found',
|
||||
response: {
|
||||
message: [`Cannot ${method.toUpperCase()} ${url}`],
|
||||
},
|
||||
});
|
||||
|
||||
next();
|
||||
@@ -96,12 +119,14 @@ function bootstrap() {
|
||||
ServerUP.app = app;
|
||||
const server = ServerUP[httpServer.TYPE];
|
||||
|
||||
server.listen(httpServer.PORT, () =>
|
||||
logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT),
|
||||
);
|
||||
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
|
||||
|
||||
initWA();
|
||||
|
||||
initIO(server);
|
||||
|
||||
if (configService.get<Rabbitmq>('RABBITMQ').ENABLED) initAMQP();
|
||||
|
||||
onUnexpectedError();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Express } from 'express';
|
||||
import { readFileSync } from 'fs';
|
||||
import { configService, SslConf } from '../config/env.config';
|
||||
import * as https from 'https';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
|
||||
import { configService, SslConf } from '../config/env.config';
|
||||
|
||||
export class ServerUP {
|
||||
static #app: Express;
|
||||
|
||||
@@ -6,9 +6,10 @@ import {
|
||||
proto,
|
||||
SignalDataTypeMap,
|
||||
} from '@whiskeysockets/baileys';
|
||||
|
||||
import { configService, Database } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
import { dbserver } from '../db/db.connect';
|
||||
import { dbserver } from '../libs/db.connect';
|
||||
|
||||
export async function useMultiFileAuthStateDb(
|
||||
coll: string,
|
||||
@@ -24,12 +25,12 @@ export async function useMultiFileAuthStateDb(
|
||||
const writeData = async (data: any, key: string): Promise<any> => {
|
||||
try {
|
||||
await client.connect();
|
||||
return await collection.replaceOne(
|
||||
{ _id: key },
|
||||
JSON.parse(JSON.stringify(data, BufferJSON.replacer)),
|
||||
{ upsert: true },
|
||||
);
|
||||
} catch {}
|
||||
return await collection.replaceOne({ _id: key }, JSON.parse(JSON.stringify(data, BufferJSON.replacer)), {
|
||||
upsert: true,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const readData = async (key: string): Promise<any> => {
|
||||
@@ -38,14 +39,18 @@ export async function useMultiFileAuthStateDb(
|
||||
const data = await collection.findOne({ _id: key });
|
||||
const creds = JSON.stringify(data);
|
||||
return JSON.parse(creds, BufferJSON.reviver);
|
||||
} catch {}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const removeData = async (key: string) => {
|
||||
try {
|
||||
await client.connect();
|
||||
return await collection.deleteOne({ _id: key });
|
||||
} catch {}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
proto,
|
||||
SignalDataTypeMap,
|
||||
} from '@whiskeysockets/baileys';
|
||||
import { RedisCache } from '../db/redis.client';
|
||||
|
||||
import { Logger } from '../config/logger.config';
|
||||
import { Redis } from '../config/env.config';
|
||||
import { RedisCache } from '../libs/redis.client';
|
||||
|
||||
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
||||
state: AuthenticationState;
|
||||
|
||||
@@ -53,11 +53,16 @@ export const instanceNameSchema: JSONSchema7 = {
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
],
|
||||
},
|
||||
},
|
||||
qrcode: { type: 'boolean', enum: [true, false] },
|
||||
number: { type: 'string', pattern: '^\\d+[\\.@\\w-]+' },
|
||||
token: { type: 'string' },
|
||||
},
|
||||
...isNotEmpty('instanceName'),
|
||||
@@ -123,7 +128,6 @@ const optionsSchema: JSONSchema7 = {
|
||||
|
||||
const numberDefinition: JSONSchema7Definition = {
|
||||
type: 'string',
|
||||
pattern: '^\\d+[\\.@\\w-]+',
|
||||
description: 'Invalid format',
|
||||
};
|
||||
|
||||
@@ -398,7 +402,7 @@ export const contactMessageSchema: JSONSchema7 = {
|
||||
email: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
},
|
||||
required: ['fullName', 'wuid', 'phoneNumber'],
|
||||
required: ['fullName', 'phoneNumber'],
|
||||
...isNotEmpty('fullName'),
|
||||
},
|
||||
minItems: 1,
|
||||
@@ -445,7 +449,6 @@ export const whatsappNumberSchema: JSONSchema7 = {
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
pattern: '^\\d+',
|
||||
description: '"numbers" must be an array of numeric strings',
|
||||
},
|
||||
},
|
||||
@@ -456,7 +459,7 @@ export const readMessageSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
readMessages: {
|
||||
read_messages: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
uniqueItems: true,
|
||||
@@ -471,7 +474,7 @@ export const readMessageSchema: JSONSchema7 = {
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['readMessages'],
|
||||
required: ['read_messages'],
|
||||
};
|
||||
|
||||
export const privacySettingsSchema: JSONSchema7 = {
|
||||
@@ -508,6 +511,7 @@ export const archiveChatSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
chat: { type: 'string' },
|
||||
lastMessage: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -528,7 +532,7 @@ export const archiveChatSchema: JSONSchema7 = {
|
||||
},
|
||||
archive: { type: 'boolean', enum: [true, false] },
|
||||
},
|
||||
required: ['lastMessage', 'archive'],
|
||||
required: ['archive'],
|
||||
};
|
||||
|
||||
export const deleteMessageSchema: JSONSchema7 = {
|
||||
@@ -668,6 +672,7 @@ export const createGroupSchema: JSONSchema7 = {
|
||||
subject: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
profilePicture: { type: 'string' },
|
||||
promoteParticipants: { type: 'boolean', enum: [true, false] },
|
||||
participants: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
@@ -822,12 +827,84 @@ export const updateGroupDescriptionSchema: JSONSchema7 = {
|
||||
...isNotEmpty('groupJid', 'description'),
|
||||
};
|
||||
|
||||
// Webhook Schema
|
||||
export const webhookSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string' },
|
||||
events: {
|
||||
type: 'array',
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['url'],
|
||||
...isNotEmpty('url'),
|
||||
};
|
||||
|
||||
export const chatwootSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
account_id: { type: 'string' },
|
||||
token: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
sign_msg: { type: 'boolean', enum: [true, false] },
|
||||
reopen_conversation: { type: 'boolean', enum: [true, false] },
|
||||
conversation_pending: { type: 'boolean', enum: [true, false] },
|
||||
},
|
||||
required: ['enabled', 'account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'],
|
||||
...isNotEmpty('account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'),
|
||||
};
|
||||
|
||||
export const settingsSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
reject_call: { type: 'boolean', enum: [true, false] },
|
||||
msg_call: { type: 'string' },
|
||||
groups_ignore: { type: 'boolean', enum: [true, false] },
|
||||
always_online: { type: 'boolean', enum: [true, false] },
|
||||
read_messages: { type: 'boolean', enum: [true, false] },
|
||||
read_status: { type: 'boolean', enum: [true, false] },
|
||||
},
|
||||
required: ['reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'],
|
||||
...isNotEmpty('reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status'),
|
||||
};
|
||||
|
||||
export const websocketSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
events: {
|
||||
type: 'array',
|
||||
@@ -854,25 +931,122 @@ export const webhookSchema: JSONSchema7 = {
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['url', 'enabled'],
|
||||
...isNotEmpty('url'),
|
||||
required: ['enabled'],
|
||||
...isNotEmpty('enabled'),
|
||||
};
|
||||
|
||||
export const chatwootSchema: JSONSchema7 = {
|
||||
export const rabbitmqSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
account_id: { type: 'string' },
|
||||
token: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
sign_msg: { type: 'boolean', enum: [true, false] },
|
||||
events: {
|
||||
type: 'array',
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['enabled', 'account_id', 'token', 'url', 'sign_msg'],
|
||||
...isNotEmpty('account_id', 'token', 'url', 'sign_msg'),
|
||||
required: ['enabled'],
|
||||
...isNotEmpty('enabled'),
|
||||
};
|
||||
|
||||
export const typebotSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
url: { type: 'string' },
|
||||
typebot: { type: 'string' },
|
||||
expire: { type: 'integer' },
|
||||
delay_message: { type: 'integer' },
|
||||
unknown_message: { type: 'string' },
|
||||
listening_from_me: { type: 'boolean', enum: [true, false] },
|
||||
},
|
||||
required: ['enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'],
|
||||
...isNotEmpty('enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'),
|
||||
};
|
||||
|
||||
export const typebotStatusSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
remoteJid: { type: 'string' },
|
||||
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
|
||||
},
|
||||
required: ['remoteJid', 'status'],
|
||||
...isNotEmpty('remoteJid', 'status'),
|
||||
};
|
||||
|
||||
export const typebotStartSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
remoteJid: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
typebot: { type: 'string' },
|
||||
},
|
||||
required: ['remoteJid', 'url', 'typebot'],
|
||||
...isNotEmpty('remoteJid', 'url', 'typebot'),
|
||||
};
|
||||
|
||||
export const proxySchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
proxy: { type: 'string' },
|
||||
},
|
||||
required: ['enabled', 'proxy'],
|
||||
...isNotEmpty('enabled', 'proxy'),
|
||||
};
|
||||
|
||||
export const chamaaiSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean', enum: [true, false] },
|
||||
url: { type: 'string' },
|
||||
token: { type: 'string' },
|
||||
waNumber: { type: 'string' },
|
||||
answerByAudio: { type: 'boolean', enum: [true, false] },
|
||||
},
|
||||
required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'],
|
||||
...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService, Database } from '../../config/env.config';
|
||||
import { ROOT_DIR } from '../../config/path.config';
|
||||
|
||||
@@ -34,11 +35,9 @@ export abstract class Repository implements IRepository {
|
||||
mkdirSync(create.path, { recursive: true });
|
||||
}
|
||||
try {
|
||||
writeFileSync(
|
||||
join(create.path, create.fileName + '.json'),
|
||||
JSON.stringify({ ...create.data }),
|
||||
{ encoding: 'utf-8' },
|
||||
);
|
||||
writeFileSync(join(create.path, create.fileName + '.json'), JSON.stringify({ ...create.data }), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
return { message: 'create - success' };
|
||||
} finally {
|
||||
@@ -46,19 +45,23 @@ export abstract class Repository implements IRepository {
|
||||
}
|
||||
};
|
||||
|
||||
public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
// eslint-disable-next-line
|
||||
public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
// eslint-disable-next-line
|
||||
public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public find(query: any): Promise<any> {
|
||||
// eslint-disable-next-line
|
||||
public find(query: any): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
delete(query: any, force?: boolean): Promise<any> {
|
||||
// eslint-disable-next-line
|
||||
delete(query: any, force?: boolean): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { Request } from 'express';
|
||||
import { validate } from 'jsonschema';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import 'express-async-errors';
|
||||
|
||||
import { Request } from 'express';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { validate } from 'jsonschema';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { GetParticipant, GroupInvite, GroupJid } from '../dto/group.dto';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { GetParticipant, GroupInvite } from '../dto/group.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
|
||||
type DataValidate<T> = {
|
||||
request: Request;
|
||||
@@ -46,20 +48,21 @@ export abstract class RouterBroker {
|
||||
const v = schema ? validate(ref, schema) : { valid: true, errors: [] };
|
||||
|
||||
if (!v.valid) {
|
||||
const message: any[] = v.errors.map(({ property, stack, schema }) => {
|
||||
const message: any[] = v.errors.map(({ stack, schema }) => {
|
||||
let message: string;
|
||||
if (schema['description']) {
|
||||
message = schema['description'];
|
||||
} else {
|
||||
message = stack.replace('instance.', '');
|
||||
}
|
||||
return {
|
||||
property: property.replace('instance.', ''),
|
||||
message,
|
||||
};
|
||||
return message;
|
||||
// return {
|
||||
// property: property.replace('instance.', ''),
|
||||
// message,
|
||||
// };
|
||||
});
|
||||
logger.error([...message]);
|
||||
throw new BadRequestException(...message);
|
||||
logger.error(message);
|
||||
throw new BadRequestException(message);
|
||||
}
|
||||
|
||||
return await execute(instance, ref);
|
||||
@@ -99,21 +102,29 @@ export abstract class RouterBroker {
|
||||
public async groupValidate<T>(args: DataValidate<T>) {
|
||||
const { request, ClassRef, schema, execute } = args;
|
||||
|
||||
const groupJid = request.query as unknown as GroupJid;
|
||||
|
||||
if (!groupJid?.groupJid) {
|
||||
throw new BadRequestException(
|
||||
'The group id needs to be informed in the query',
|
||||
'ex: "groupJid=120362@g.us"',
|
||||
);
|
||||
}
|
||||
|
||||
const instance = request.params as unknown as InstanceDto;
|
||||
const body = request.body;
|
||||
|
||||
let groupJid = body?.groupJid;
|
||||
|
||||
if (!groupJid) {
|
||||
if (request.query?.groupJid) {
|
||||
groupJid = request.query.groupJid;
|
||||
} else {
|
||||
throw new BadRequestException('The group id needs to be informed in the query', 'ex: "groupJid=120362@g.us"');
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupJid.endsWith('@g.us')) {
|
||||
groupJid = groupJid + '@g.us';
|
||||
}
|
||||
|
||||
Object.assign(body, {
|
||||
groupJid: groupJid,
|
||||
});
|
||||
|
||||
const ref = new ClassRef();
|
||||
|
||||
Object.assign(body, groupJid);
|
||||
Object.assign(ref, body);
|
||||
|
||||
const v = validate(ref, schema);
|
||||
@@ -186,9 +197,7 @@ export abstract class RouterBroker {
|
||||
const getParticipants = request.query as unknown as GetParticipant;
|
||||
|
||||
if (!getParticipants?.getParticipants) {
|
||||
throw new BadRequestException(
|
||||
'The getParticipants needs to be informed in the query',
|
||||
);
|
||||
throw new BadRequestException('The getParticipants needs to be informed in the query');
|
||||
}
|
||||
|
||||
const instance = request.params as unknown as InstanceDto;
|
||||
|
||||
29
src/whatsapp/controllers/chamaai.controller.ts
Normal file
29
src/whatsapp/controllers/chamaai.controller.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { ChamaaiDto } from '../dto/chamaai.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ChamaaiService } from '../services/chamaai.service';
|
||||
|
||||
const logger = new Logger('ChamaaiController');
|
||||
|
||||
export class ChamaaiController {
|
||||
constructor(private readonly chamaaiService: ChamaaiService) {}
|
||||
|
||||
public async createChamaai(instance: InstanceDto, data: ChamaaiDto) {
|
||||
logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('chamaai disabled');
|
||||
data.url = '';
|
||||
data.token = '';
|
||||
data.waNumber = '';
|
||||
data.answerByAudio = false;
|
||||
}
|
||||
|
||||
return this.chamaaiService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findChamaai(instance: InstanceDto) {
|
||||
logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance');
|
||||
return this.chamaaiService.find(instance);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { proto } from '@whiskeysockets/baileys';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
ArchiveChatDto,
|
||||
DeleteMessage,
|
||||
getBase64FromMediaMessageDto,
|
||||
NumberDto,
|
||||
PrivacySettingDto,
|
||||
ProfileNameDto,
|
||||
@@ -9,14 +10,12 @@ import {
|
||||
ProfileStatusDto,
|
||||
ReadMessageDto,
|
||||
WhatsAppNumberDto,
|
||||
getBase64FromMediaMessageDto,
|
||||
} from '../dto/chat.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ContactQuery } from '../repository/contact.repository';
|
||||
import { MessageQuery } from '../repository/message.repository';
|
||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('ChatController');
|
||||
|
||||
@@ -47,7 +46,7 @@ export class ChatController {
|
||||
logger.verbose('requested fetchProfilePicture from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].profilePicture(data.number);
|
||||
}
|
||||
|
||||
|
||||
public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) {
|
||||
logger.verbose('requested fetchProfile from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number);
|
||||
@@ -58,13 +57,8 @@ export class ChatController {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchContacts(query);
|
||||
}
|
||||
|
||||
public async getBase64FromMediaMessage(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: getBase64FromMediaMessageDto,
|
||||
) {
|
||||
logger.verbose(
|
||||
'requested getBase64FromMediaMessage from ' + instanceName + ' instance',
|
||||
);
|
||||
public async getBase64FromMediaMessage({ instanceName }: InstanceDto, data: getBase64FromMediaMessageDto) {
|
||||
logger.verbose('requested getBase64FromMediaMessage from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data);
|
||||
}
|
||||
|
||||
@@ -88,22 +82,14 @@ export class ChatController {
|
||||
return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings();
|
||||
}
|
||||
|
||||
public async updatePrivacySettings(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: PrivacySettingDto,
|
||||
) {
|
||||
public async updatePrivacySettings({ instanceName }: InstanceDto, data: PrivacySettingDto) {
|
||||
logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data);
|
||||
}
|
||||
|
||||
public async fetchBusinessProfile(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
public async fetchBusinessProfile({ instanceName }: InstanceDto, data: ProfilePictureDto) {
|
||||
logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(
|
||||
data.number,
|
||||
);
|
||||
return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(data.number);
|
||||
}
|
||||
|
||||
public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) {
|
||||
@@ -111,30 +97,17 @@ export class ChatController {
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name);
|
||||
}
|
||||
|
||||
public async updateProfileStatus(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfileStatusDto,
|
||||
) {
|
||||
public async updateProfileStatus({ instanceName }: InstanceDto, data: ProfileStatusDto) {
|
||||
logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(
|
||||
data.status,
|
||||
);
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(data.status);
|
||||
}
|
||||
|
||||
public async updateProfilePicture(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
public async updateProfilePicture({ instanceName }: InstanceDto, data: ProfilePictureDto) {
|
||||
logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(
|
||||
data.picture,
|
||||
);
|
||||
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(data.picture);
|
||||
}
|
||||
|
||||
public async removeProfilePicture(
|
||||
{ instanceName }: InstanceDto,
|
||||
data: ProfilePictureDto,
|
||||
) {
|
||||
public async removeProfilePicture({ instanceName }: InstanceDto) {
|
||||
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
import { isURL } from 'class-validator';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { waMonitor } from '../whatsapp.module';
|
||||
|
||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { waMonitor } from '../whatsapp.module';
|
||||
|
||||
const logger = new Logger('ChatwootController');
|
||||
|
||||
export class ChatwootController {
|
||||
constructor(
|
||||
private readonly chatwootService: ChatwootService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
constructor(private readonly chatwootService: ChatwootService, private readonly configService: ConfigService) {}
|
||||
|
||||
public async createChatwoot(instance: InstanceDto, data: ChatwootDto) {
|
||||
logger.verbose(
|
||||
'requested createChatwoot from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
logger.verbose('requested createChatwoot from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (data.enabled) {
|
||||
if (!isURL(data.url, { require_tld: false })) {
|
||||
@@ -33,7 +29,7 @@ export class ChatwootController {
|
||||
throw new BadRequestException('token is required');
|
||||
}
|
||||
|
||||
if (!data.sign_msg) {
|
||||
if (data.sign_msg !== true && data.sign_msg !== false) {
|
||||
throw new BadRequestException('sign_msg is required');
|
||||
}
|
||||
}
|
||||
@@ -44,6 +40,8 @@ export class ChatwootController {
|
||||
data.token = '';
|
||||
data.url = '';
|
||||
data.sign_msg = false;
|
||||
data.reopen_conversation = false;
|
||||
data.conversation_pending = false;
|
||||
}
|
||||
|
||||
data.name_inbox = instance.instanceName;
|
||||
@@ -54,7 +52,7 @@ export class ChatwootController {
|
||||
|
||||
const response = {
|
||||
...result,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||
};
|
||||
|
||||
return response;
|
||||
@@ -80,16 +78,14 @@ export class ChatwootController {
|
||||
|
||||
const response = {
|
||||
...result,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public async receiveWebhook(instance: InstanceDto, data: any) {
|
||||
logger.verbose(
|
||||
'requested receiveWebhook from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
|
||||
const chatwootService = new ChatwootService(waMonitor, this.configService);
|
||||
|
||||
return chatwootService.receiveWebhook(instance, data);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
CreateGroupDto,
|
||||
GetParticipant,
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
} from '../dto/group.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('ChatController');
|
||||
|
||||
@@ -26,33 +26,18 @@ export class GroupController {
|
||||
}
|
||||
|
||||
public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) {
|
||||
logger.verbose(
|
||||
'requested updateGroupPicture from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(
|
||||
update,
|
||||
);
|
||||
logger.verbose('requested updateGroupPicture from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(update);
|
||||
}
|
||||
|
||||
public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) {
|
||||
logger.verbose(
|
||||
'requested updateGroupSubject from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(
|
||||
update,
|
||||
);
|
||||
logger.verbose('requested updateGroupSubject from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(update);
|
||||
}
|
||||
|
||||
public async updateGroupDescription(
|
||||
instance: InstanceDto,
|
||||
update: GroupDescriptionDto,
|
||||
) {
|
||||
logger.verbose(
|
||||
'requested updateGroupDescription from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(
|
||||
update,
|
||||
);
|
||||
public async updateGroupDescription(instance: InstanceDto, update: GroupDescriptionDto) {
|
||||
logger.verbose('requested updateGroupDescription from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(update);
|
||||
}
|
||||
|
||||
public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) {
|
||||
@@ -61,12 +46,8 @@ export class GroupController {
|
||||
}
|
||||
|
||||
public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) {
|
||||
logger.verbose(
|
||||
'requested fetchAllGroups from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(
|
||||
getPaticipants,
|
||||
);
|
||||
logger.verbose('requested fetchAllGroups from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(getPaticipants);
|
||||
}
|
||||
|
||||
public async inviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||
@@ -85,49 +66,28 @@ export class GroupController {
|
||||
}
|
||||
|
||||
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||
logger.verbose(
|
||||
'requested revokeInviteCode from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(
|
||||
groupJid,
|
||||
);
|
||||
logger.verbose('requested revokeInviteCode from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(groupJid);
|
||||
}
|
||||
|
||||
public async findParticipants(instance: InstanceDto, groupJid: GroupJid) {
|
||||
logger.verbose(
|
||||
'requested findParticipants from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(
|
||||
groupJid,
|
||||
);
|
||||
logger.verbose('requested findParticipants from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(groupJid);
|
||||
}
|
||||
|
||||
public async updateGParticipate(
|
||||
instance: InstanceDto,
|
||||
update: GroupUpdateParticipantDto,
|
||||
) {
|
||||
logger.verbose(
|
||||
'requested updateGParticipate from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(
|
||||
update,
|
||||
);
|
||||
public async updateGParticipate(instance: InstanceDto, update: GroupUpdateParticipantDto) {
|
||||
logger.verbose('requested updateGParticipate from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(update);
|
||||
}
|
||||
|
||||
public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) {
|
||||
logger.verbose(
|
||||
'requested updateGSetting from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
logger.verbose('requested updateGSetting from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update);
|
||||
}
|
||||
|
||||
public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) {
|
||||
logger.verbose(
|
||||
'requested toggleEphemeral from ' + instance.instanceName + ' instance',
|
||||
);
|
||||
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(
|
||||
update,
|
||||
);
|
||||
logger.verbose('requested toggleEphemeral from ' + instance.instanceName + ' instance');
|
||||
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(update);
|
||||
}
|
||||
|
||||
public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) {
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { delay } from '@whiskeysockets/baileys';
|
||||
import { isURL } from 'class-validator';
|
||||
import EventEmitter2 from 'eventemitter2';
|
||||
import { Auth, ConfigService, HttpServer } from '../../config/env.config';
|
||||
|
||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
||||
import { RedisCache } from '../../libs/redis.client';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { AuthService, OldToken } from '../services/auth.service';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
import { WAStartupService } from '../services/whatsapp.service';
|
||||
import { WebhookService } from '../services/webhook.service';
|
||||
import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
import { RabbitmqService } from '../services/rabbitmq.service';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
import { TypebotService } from '../services/typebot.service';
|
||||
import { WebhookService } from '../services/webhook.service';
|
||||
import { WebsocketService } from '../services/websocket.service';
|
||||
import { WAStartupService } from '../services/whatsapp.service';
|
||||
import { wa } from '../types/wa.types';
|
||||
import { RedisCache } from '../../db/redis.client';
|
||||
import { isURL } from 'class-validator';
|
||||
|
||||
export class InstanceController {
|
||||
constructor(
|
||||
@@ -23,6 +28,10 @@ export class InstanceController {
|
||||
private readonly authService: AuthService,
|
||||
private readonly webhookService: WebhookService,
|
||||
private readonly chatwootService: ChatwootService,
|
||||
private readonly settingsService: SettingsService,
|
||||
private readonly websocketService: WebsocketService,
|
||||
private readonly rabbitmqService: RabbitmqService,
|
||||
private readonly typebotService: TypebotService,
|
||||
private readonly cache: RedisCache,
|
||||
) {}
|
||||
|
||||
@@ -34,40 +43,42 @@ export class InstanceController {
|
||||
webhook_by_events,
|
||||
events,
|
||||
qrcode,
|
||||
number,
|
||||
token,
|
||||
chatwoot_account_id,
|
||||
chatwoot_token,
|
||||
chatwoot_url,
|
||||
chatwoot_sign_msg,
|
||||
chatwoot_reopen_conversation,
|
||||
chatwoot_conversation_pending,
|
||||
reject_call,
|
||||
msg_call,
|
||||
groups_ignore,
|
||||
always_online,
|
||||
read_messages,
|
||||
read_status,
|
||||
websocket_enabled,
|
||||
websocket_events,
|
||||
rabbitmq_enabled,
|
||||
rabbitmq_events,
|
||||
typebot_url,
|
||||
typebot,
|
||||
typebot_expire,
|
||||
typebot_keyword_finish,
|
||||
typebot_delay_message,
|
||||
typebot_unknown_message,
|
||||
typebot_listening_from_me,
|
||||
}: InstanceDto) {
|
||||
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
|
||||
|
||||
const mode = this.configService.get<Auth>('AUTHENTICATION').INSTANCE.MODE;
|
||||
|
||||
if (mode === 'container') {
|
||||
this.logger.verbose('container mode');
|
||||
|
||||
if (Object.keys(this.waMonitor.waInstances).length > 0) {
|
||||
throw new BadRequestException([
|
||||
'Instance already created',
|
||||
'Only one instance can be created',
|
||||
]);
|
||||
}
|
||||
try {
|
||||
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
|
||||
|
||||
this.logger.verbose('checking duplicate token');
|
||||
await this.authService.checkDuplicateToken(token);
|
||||
|
||||
this.logger.verbose('creating instance');
|
||||
const instance = new WAStartupService(
|
||||
this.configService,
|
||||
this.eventEmitter,
|
||||
this.repository,
|
||||
this.cache,
|
||||
);
|
||||
instance.instanceName = instanceName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]/g, '')
|
||||
.replace(' ', '');
|
||||
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||
instance.instanceName = instanceName;
|
||||
|
||||
this.logger.verbose('instance: ' + instance.instanceName + ' created');
|
||||
|
||||
this.waMonitor.waInstances[instance.instanceName] = instance;
|
||||
@@ -83,193 +94,237 @@ export class InstanceController {
|
||||
|
||||
this.logger.verbose('hash: ' + hash + ' generated');
|
||||
|
||||
let getEvents: string[];
|
||||
let webhookEvents: string[];
|
||||
|
||||
if (webhook) {
|
||||
if (!isURL(webhook, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property in webhook');
|
||||
}
|
||||
|
||||
this.logger.verbose('creating webhook');
|
||||
try {
|
||||
let newEvents: string[] = [];
|
||||
if (events.length === 0) {
|
||||
newEvents = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
} else {
|
||||
newEvents = events;
|
||||
}
|
||||
this.webhookService.create(instance, {
|
||||
enabled: true,
|
||||
url: webhook,
|
||||
events,
|
||||
events: newEvents,
|
||||
webhook_by_events,
|
||||
});
|
||||
|
||||
getEvents = (await this.webhookService.find(instance)).events;
|
||||
webhookEvents = (await this.webhookService.find(instance)).events;
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) {
|
||||
this.logger.verbose('instance created');
|
||||
this.logger.verbose({
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
events: getEvents,
|
||||
});
|
||||
let websocketEvents: string[];
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
events: getEvents,
|
||||
};
|
||||
if (websocket_enabled) {
|
||||
this.logger.verbose('creating websocket');
|
||||
try {
|
||||
let newEvents: string[] = [];
|
||||
if (websocket_events.length === 0) {
|
||||
newEvents = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
} else {
|
||||
newEvents = websocket_events;
|
||||
}
|
||||
this.websocketService.create(instance, {
|
||||
enabled: true,
|
||||
events: newEvents,
|
||||
});
|
||||
|
||||
websocketEvents = (await this.websocketService.find(instance)).events;
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatwoot_account_id) {
|
||||
throw new BadRequestException('account_id is required');
|
||||
let rabbitmqEvents: string[];
|
||||
|
||||
if (rabbitmq_enabled) {
|
||||
this.logger.verbose('creating rabbitmq');
|
||||
try {
|
||||
let newEvents: string[] = [];
|
||||
if (rabbitmq_events.length === 0) {
|
||||
newEvents = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
} else {
|
||||
newEvents = rabbitmq_events;
|
||||
}
|
||||
this.rabbitmqService.create(instance, {
|
||||
enabled: true,
|
||||
events: newEvents,
|
||||
});
|
||||
|
||||
rabbitmqEvents = (await this.rabbitmqService.find(instance)).events;
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatwoot_token) {
|
||||
throw new BadRequestException('token is required');
|
||||
if (typebot_url) {
|
||||
try {
|
||||
if (!isURL(typebot_url, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property in typebot_url');
|
||||
}
|
||||
|
||||
this.logger.verbose('creating typebot');
|
||||
|
||||
this.typebotService.create(instance, {
|
||||
enabled: true,
|
||||
url: typebot_url,
|
||||
typebot: typebot,
|
||||
expire: typebot_expire,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatwoot_url) {
|
||||
throw new BadRequestException('url is required');
|
||||
}
|
||||
|
||||
if (!isURL(chatwoot_url, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property in chatwoot');
|
||||
}
|
||||
|
||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||
|
||||
try {
|
||||
this.chatwootService.create(instance, {
|
||||
enabled: true,
|
||||
account_id: chatwoot_account_id,
|
||||
token: chatwoot_token,
|
||||
url: chatwoot_url,
|
||||
sign_msg: chatwoot_sign_msg || false,
|
||||
name_inbox: instance.instanceName,
|
||||
});
|
||||
|
||||
this.chatwootService.initInstanceChatwoot(
|
||||
instance,
|
||||
instance.instanceName,
|
||||
`${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
qrcode,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
chatwoot: {
|
||||
enabled: true,
|
||||
account_id: chatwoot_account_id,
|
||||
token: chatwoot_token,
|
||||
url: chatwoot_url,
|
||||
sign_msg: chatwoot_sign_msg || false,
|
||||
name_inbox: instance.instanceName,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
},
|
||||
this.logger.verbose('creating settings');
|
||||
const settings: wa.LocalSettings = {
|
||||
reject_call: reject_call || false,
|
||||
msg_call: msg_call || '',
|
||||
groups_ignore: groups_ignore || false,
|
||||
always_online: always_online || false,
|
||||
read_messages: read_messages || false,
|
||||
read_status: read_status || false,
|
||||
};
|
||||
} else {
|
||||
this.logger.verbose('server mode');
|
||||
|
||||
this.logger.verbose('checking duplicate token');
|
||||
await this.authService.checkDuplicateToken(token);
|
||||
this.logger.verbose('settings: ' + JSON.stringify(settings));
|
||||
|
||||
this.logger.verbose('creating instance');
|
||||
const instance = new WAStartupService(
|
||||
this.configService,
|
||||
this.eventEmitter,
|
||||
this.repository,
|
||||
this.cache,
|
||||
);
|
||||
instance.instanceName = instanceName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]/g, '')
|
||||
.replace(' ', '');
|
||||
|
||||
this.logger.verbose('instance: ' + instance.instanceName + ' created');
|
||||
|
||||
this.waMonitor.waInstances[instance.instanceName] = instance;
|
||||
this.waMonitor.delInstanceTime(instance.instanceName);
|
||||
|
||||
this.logger.verbose('generating hash');
|
||||
const hash = await this.authService.generateHash(
|
||||
{
|
||||
instanceName: instance.instanceName,
|
||||
},
|
||||
token,
|
||||
);
|
||||
|
||||
this.logger.verbose('hash: ' + hash + ' generated');
|
||||
|
||||
let getEvents: string[];
|
||||
|
||||
if (webhook) {
|
||||
if (!isURL(webhook, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property in webhook');
|
||||
}
|
||||
|
||||
this.logger.verbose('creating webhook');
|
||||
try {
|
||||
this.webhookService.create(instance, {
|
||||
enabled: true,
|
||||
url: webhook,
|
||||
events,
|
||||
webhook_by_events,
|
||||
});
|
||||
|
||||
getEvents = (await this.webhookService.find(instance)).events;
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
}
|
||||
}
|
||||
this.settingsService.create(instance, settings);
|
||||
|
||||
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) {
|
||||
let getQrcode: wa.QrCode;
|
||||
|
||||
if (qrcode) {
|
||||
this.logger.verbose('creating qrcode');
|
||||
await instance.connectToWhatsapp();
|
||||
await delay(2000);
|
||||
await instance.connectToWhatsapp(number);
|
||||
await delay(5000);
|
||||
getQrcode = instance.qrCode;
|
||||
}
|
||||
|
||||
this.logger.verbose('instance created');
|
||||
this.logger.verbose({
|
||||
const result = {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: getEvents,
|
||||
qrcode: getQrcode,
|
||||
});
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
webhook: {
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: webhookEvents,
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: getEvents,
|
||||
websocket: {
|
||||
enabled: websocket_enabled,
|
||||
events: websocketEvents,
|
||||
},
|
||||
rabbitmq: {
|
||||
enabled: rabbitmq_enabled,
|
||||
events: rabbitmqEvents,
|
||||
},
|
||||
typebot: {
|
||||
enabled: typebot_url ? true : false,
|
||||
url: typebot_url,
|
||||
typebot,
|
||||
expire: typebot_expire,
|
||||
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,
|
||||
};
|
||||
|
||||
this.logger.verbose('instance created');
|
||||
this.logger.verbose(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!chatwoot_account_id) {
|
||||
@@ -288,6 +343,18 @@ export class InstanceController {
|
||||
throw new BadRequestException('Invalid "url" property in chatwoot');
|
||||
}
|
||||
|
||||
if (chatwoot_sign_msg !== true && chatwoot_sign_msg !== false) {
|
||||
throw new BadRequestException('sign_msg is required');
|
||||
}
|
||||
|
||||
if (chatwoot_reopen_conversation !== true && chatwoot_reopen_conversation !== false) {
|
||||
throw new BadRequestException('reopen_conversation is required');
|
||||
}
|
||||
|
||||
if (chatwoot_conversation_pending !== true && chatwoot_conversation_pending !== false) {
|
||||
throw new BadRequestException('conversation_pending is required');
|
||||
}
|
||||
|
||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||
|
||||
try {
|
||||
@@ -297,14 +364,18 @@ export class InstanceController {
|
||||
token: chatwoot_token,
|
||||
url: chatwoot_url,
|
||||
sign_msg: chatwoot_sign_msg || false,
|
||||
name_inbox: instance.instanceName,
|
||||
name_inbox: instance.instanceName.split('-cwId-')[0],
|
||||
number,
|
||||
reopen_conversation: chatwoot_reopen_conversation || false,
|
||||
conversation_pending: chatwoot_conversation_pending || false,
|
||||
});
|
||||
|
||||
this.chatwootService.initInstanceChatwoot(
|
||||
instance,
|
||||
instance.instanceName,
|
||||
`${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
instance.instanceName.split('-cwId-')[0],
|
||||
`${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||
qrcode,
|
||||
number,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.log(error);
|
||||
@@ -316,44 +387,85 @@ export class InstanceController {
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: getEvents,
|
||||
webhook: {
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: webhookEvents,
|
||||
},
|
||||
websocket: {
|
||||
enabled: websocket_enabled,
|
||||
events: websocketEvents,
|
||||
},
|
||||
rabbitmq: {
|
||||
enabled: rabbitmq_enabled,
|
||||
events: rabbitmqEvents,
|
||||
},
|
||||
typebot: {
|
||||
enabled: typebot_url ? true : false,
|
||||
url: typebot_url,
|
||||
typebot,
|
||||
expire: typebot_expire,
|
||||
keyword_finish: typebot_keyword_finish,
|
||||
delay_message: typebot_delay_message,
|
||||
unknown_message: typebot_unknown_message,
|
||||
listening_from_me: typebot_listening_from_me,
|
||||
},
|
||||
settings,
|
||||
chatwoot: {
|
||||
enabled: true,
|
||||
account_id: chatwoot_account_id,
|
||||
token: chatwoot_token,
|
||||
url: chatwoot_url,
|
||||
sign_msg: chatwoot_sign_msg || false,
|
||||
reopen_conversation: chatwoot_reopen_conversation || false,
|
||||
conversation_pending: chatwoot_conversation_pending || false,
|
||||
number,
|
||||
name_inbox: instance.instanceName,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${instance.instanceName}`,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error.message[0]);
|
||||
throw new BadRequestException(error.message[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public async connectToWhatsapp({ instanceName }: InstanceDto) {
|
||||
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
|
||||
try {
|
||||
this.logger.verbose(
|
||||
'requested connectToWhatsapp from ' + instanceName + ' instance',
|
||||
);
|
||||
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
|
||||
|
||||
const instance = this.waMonitor.waInstances[instanceName];
|
||||
const state = instance?.connectionStatus?.state;
|
||||
|
||||
this.logger.verbose('state: ' + state);
|
||||
|
||||
switch (state) {
|
||||
case 'close':
|
||||
this.logger.verbose('connecting');
|
||||
await instance.connectToWhatsapp();
|
||||
await delay(2000);
|
||||
return instance.qrCode;
|
||||
case 'connecting':
|
||||
return instance.qrCode;
|
||||
default:
|
||||
return await this.connectionState({ instanceName });
|
||||
if (!state) {
|
||||
throw new BadRequestException('The "' + instanceName + '" instance does not exist');
|
||||
}
|
||||
|
||||
if (state == 'open') {
|
||||
return await this.connectionState({ instanceName });
|
||||
}
|
||||
|
||||
if (state == 'connecting') {
|
||||
return instance.qrCode;
|
||||
}
|
||||
|
||||
if (state == 'close') {
|
||||
this.logger.verbose('connecting');
|
||||
await instance.connectToWhatsapp(number);
|
||||
|
||||
await delay(5000);
|
||||
return instance.qrCode;
|
||||
}
|
||||
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instanceName,
|
||||
status: state,
|
||||
},
|
||||
qrcode: instance?.qrCode,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
@@ -366,7 +478,7 @@ export class InstanceController {
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
||||
|
||||
return { error: false, message: 'Instance restarted' };
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance restarted' } };
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
@@ -374,39 +486,41 @@ export class InstanceController {
|
||||
|
||||
public async connectionState({ instanceName }: InstanceDto) {
|
||||
this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
|
||||
return this.waMonitor.waInstances[instanceName]?.connectionStatus;
|
||||
return {
|
||||
instance: {
|
||||
instanceName: instanceName,
|
||||
state: this.waMonitor.waInstances[instanceName]?.connectionStatus?.state,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public async logout({ instanceName }: InstanceDto) {
|
||||
this.logger.verbose('requested logout from ' + instanceName + ' instance');
|
||||
const stateConn = await this.connectionState({ instanceName });
|
||||
const { instance } = await this.connectionState({ instanceName });
|
||||
|
||||
if (stateConn.state === 'close') {
|
||||
throw new BadRequestException(
|
||||
'The "' + instanceName + '" instance is not connected',
|
||||
);
|
||||
if (instance.state === 'close') {
|
||||
throw new BadRequestException('The "' + instanceName + '" instance is not connected');
|
||||
}
|
||||
|
||||
try {
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
await this.waMonitor.waInstances[instanceName]?.client?.logout(
|
||||
'Log out instance: ' + instanceName,
|
||||
);
|
||||
await this.waMonitor.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
||||
|
||||
this.logger.verbose('close connection instance: ' + instanceName);
|
||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
||||
|
||||
return { error: false, message: 'Instance logged out' };
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance logged out' } };
|
||||
} catch (error) {
|
||||
throw new InternalServerErrorException(error.toString());
|
||||
}
|
||||
@@ -414,26 +528,24 @@ export class InstanceController {
|
||||
|
||||
public async deleteInstance({ instanceName }: InstanceDto) {
|
||||
this.logger.verbose('requested deleteInstance from ' + instanceName + ' instance');
|
||||
const stateConn = await this.connectionState({ instanceName });
|
||||
const { instance } = await this.connectionState({ instanceName });
|
||||
|
||||
if (stateConn.state === 'open') {
|
||||
throw new BadRequestException(
|
||||
'The "' + instanceName + '" instance needs to be disconnected',
|
||||
);
|
||||
if (instance.state === 'open') {
|
||||
throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected');
|
||||
}
|
||||
try {
|
||||
if (stateConn.state === 'connecting') {
|
||||
if (instance.state === 'connecting') {
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
|
||||
await this.logout({ instanceName });
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
return { error: false, message: 'Instance deleted' };
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||
} else {
|
||||
this.logger.verbose('deleting instance: ' + instanceName);
|
||||
|
||||
delete this.waMonitor.waInstances[instanceName];
|
||||
this.eventEmitter.emit('remove.instance', instanceName, 'inner');
|
||||
return { error: false, message: 'Instance deleted' };
|
||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } };
|
||||
}
|
||||
} catch (error) {
|
||||
throw new BadRequestException(error.toString());
|
||||
|
||||
26
src/whatsapp/controllers/proxy.controller.ts
Normal file
26
src/whatsapp/controllers/proxy.controller.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ProxyDto } from '../dto/proxy.dto';
|
||||
import { ProxyService } from '../services/proxy.service';
|
||||
|
||||
const logger = new Logger('ProxyController');
|
||||
|
||||
export class ProxyController {
|
||||
constructor(private readonly proxyService: ProxyService) {}
|
||||
|
||||
public async createProxy(instance: InstanceDto, data: ProxyDto) {
|
||||
logger.verbose('requested createProxy from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('proxy disabled');
|
||||
data.proxy = '';
|
||||
}
|
||||
|
||||
return this.proxyService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findProxy(instance: InstanceDto) {
|
||||
logger.verbose('requested findProxy from ' + instance.instanceName + ' instance');
|
||||
return this.proxyService.find(instance);
|
||||
}
|
||||
}
|
||||
56
src/whatsapp/controllers/rabbitmq.controller.ts
Normal file
56
src/whatsapp/controllers/rabbitmq.controller.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RabbitmqDto } from '../dto/rabbitmq.dto';
|
||||
import { RabbitmqService } from '../services/rabbitmq.service';
|
||||
|
||||
const logger = new Logger('RabbitmqController');
|
||||
|
||||
export class RabbitmqController {
|
||||
constructor(private readonly rabbitmqService: RabbitmqService) {}
|
||||
|
||||
public async createRabbitmq(instance: InstanceDto, data: RabbitmqDto) {
|
||||
logger.verbose('requested createRabbitmq from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('rabbitmq disabled');
|
||||
data.events = [];
|
||||
}
|
||||
|
||||
if (data.events.length === 0) {
|
||||
logger.verbose('rabbitmq events empty');
|
||||
data.events = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
}
|
||||
|
||||
return this.rabbitmqService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findRabbitmq(instance: InstanceDto) {
|
||||
logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance');
|
||||
return this.rabbitmqService.find(instance);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { isBase64, isURL } from 'class-validator';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import {
|
||||
@@ -16,8 +18,6 @@ import {
|
||||
} from '../dto/sendMessage.dto';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('MessageRouter');
|
||||
|
||||
export class SendMessageController {
|
||||
@@ -39,12 +39,7 @@ export class SendMessageController {
|
||||
throw new BadRequestException('For base64 the file name must be informed.');
|
||||
}
|
||||
|
||||
logger.verbose(
|
||||
'isURL: ' +
|
||||
isURL(data?.mediaMessage?.media) +
|
||||
', isBase64: ' +
|
||||
isBase64(data?.mediaMessage?.media),
|
||||
);
|
||||
logger.verbose('isURL: ' + isURL(data?.mediaMessage?.media) + ', isBase64: ' + isBase64(data?.mediaMessage?.media));
|
||||
if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) {
|
||||
return await this.waMonitor.waInstances[instanceName].mediaMessage(data);
|
||||
}
|
||||
@@ -55,10 +50,7 @@ export class SendMessageController {
|
||||
logger.verbose('requested sendSticker from ' + instanceName + ' instance');
|
||||
|
||||
logger.verbose(
|
||||
'isURL: ' +
|
||||
isURL(data?.stickerMessage?.image) +
|
||||
', isBase64: ' +
|
||||
isBase64(data?.stickerMessage?.image),
|
||||
'isURL: ' + isURL(data?.stickerMessage?.image) + ', isBase64: ' + isBase64(data?.stickerMessage?.image),
|
||||
);
|
||||
if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) {
|
||||
return await this.waMonitor.waInstances[instanceName].mediaSticker(data);
|
||||
@@ -69,12 +61,7 @@ export class SendMessageController {
|
||||
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
||||
logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance');
|
||||
|
||||
logger.verbose(
|
||||
'isURL: ' +
|
||||
isURL(data?.audioMessage?.audio) +
|
||||
', isBase64: ' +
|
||||
isBase64(data?.audioMessage?.audio),
|
||||
);
|
||||
logger.verbose('isURL: ' + isURL(data?.audioMessage?.audio) + ', isBase64: ' + isBase64(data?.audioMessage?.audio));
|
||||
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
||||
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
||||
}
|
||||
@@ -83,10 +70,7 @@ export class SendMessageController {
|
||||
|
||||
public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) {
|
||||
logger.verbose('requested sendButtons from ' + instanceName + ' instance');
|
||||
if (
|
||||
isBase64(data.buttonMessage.mediaMessage?.media) &&
|
||||
!data.buttonMessage.mediaMessage?.fileName
|
||||
) {
|
||||
if (isBase64(data.buttonMessage.mediaMessage?.media) && !data.buttonMessage.mediaMessage?.fileName) {
|
||||
throw new BadRequestException('For bse64 the file name must be informed.');
|
||||
}
|
||||
return await this.waMonitor.waInstances[instanceName].buttonMessage(data);
|
||||
@@ -109,7 +93,7 @@ export class SendMessageController {
|
||||
|
||||
public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) {
|
||||
logger.verbose('requested sendReaction from ' + instanceName + ' instance');
|
||||
if (!data.reactionMessage.reaction.match(/[^\(\)\w\sà-ú"-\+]+/)) {
|
||||
if (!data.reactionMessage.reaction.match(/[^()\w\sà-ú"-+]+/)) {
|
||||
throw new BadRequestException('"reaction" must be an emoji');
|
||||
}
|
||||
return await this.waMonitor.waInstances[instanceName].reactionMessage(data);
|
||||
|
||||
24
src/whatsapp/controllers/settings.controller.ts
Normal file
24
src/whatsapp/controllers/settings.controller.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// import { isURL } from 'class-validator';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
// import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { SettingsDto } from '../dto/settings.dto';
|
||||
import { SettingsService } from '../services/settings.service';
|
||||
|
||||
const logger = new Logger('SettingsController');
|
||||
|
||||
export class SettingsController {
|
||||
constructor(private readonly settingsService: SettingsService) {}
|
||||
|
||||
public async createSettings(instance: InstanceDto, data: SettingsDto) {
|
||||
logger.verbose('requested createSettings from ' + instance.instanceName + ' instance');
|
||||
|
||||
return this.settingsService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findSettings(instance: InstanceDto) {
|
||||
logger.verbose('requested findSettings from ' + instance.instanceName + ' instance');
|
||||
return this.settingsService.find(instance);
|
||||
}
|
||||
}
|
||||
46
src/whatsapp/controllers/typebot.controller.ts
Normal file
46
src/whatsapp/controllers/typebot.controller.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { TypebotDto } from '../dto/typebot.dto';
|
||||
import { TypebotService } from '../services/typebot.service';
|
||||
|
||||
const logger = new Logger('TypebotController');
|
||||
|
||||
export class TypebotController {
|
||||
constructor(private readonly typebotService: TypebotService) {}
|
||||
|
||||
public async createTypebot(instance: InstanceDto, data: TypebotDto) {
|
||||
logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('typebot disabled');
|
||||
data.url = '';
|
||||
data.typebot = '';
|
||||
data.expire = 0;
|
||||
data.sessions = [];
|
||||
} else {
|
||||
const saveData = await this.typebotService.find(instance);
|
||||
|
||||
if (saveData.enabled) {
|
||||
logger.verbose('typebot enabled');
|
||||
data.sessions = saveData.sessions;
|
||||
}
|
||||
}
|
||||
|
||||
return this.typebotService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findTypebot(instance: InstanceDto) {
|
||||
logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance');
|
||||
return this.typebotService.find(instance);
|
||||
}
|
||||
|
||||
public async changeStatus(instance: InstanceDto, data: any) {
|
||||
logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance');
|
||||
return this.typebotService.changeStatus(instance, data);
|
||||
}
|
||||
|
||||
public async startTypebot(instance: InstanceDto, data: any) {
|
||||
logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance');
|
||||
return this.typebotService.startTypebot(instance, data);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,15 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { Auth, ConfigService } from '../../config/env.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { HttpStatus } from '../routers/index.router';
|
||||
import { WAMonitoringService } from '../services/monitor.service';
|
||||
|
||||
export class ViewsController {
|
||||
constructor(
|
||||
private readonly waMonit: WAMonitoringService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
constructor(private readonly waMonit: WAMonitoringService, private readonly configService: ConfigService) {}
|
||||
|
||||
public async qrcode(request: Request, response: Response) {
|
||||
public async manager(request: Request, response: Response) {
|
||||
try {
|
||||
const param = request.params as unknown as InstanceDto;
|
||||
const instance = this.waMonit.waInstances[param.instanceName];
|
||||
if (instance.connectionStatus.state === 'open') {
|
||||
throw new BadRequestException('The instance is already connected');
|
||||
}
|
||||
const type = this.configService.get<Auth>('AUTHENTICATION').TYPE;
|
||||
|
||||
return response.status(HttpStatus.OK).render('qrcode', { type, ...param });
|
||||
return response.status(HttpStatus.OK).render('manager');
|
||||
} catch (error) {
|
||||
console.log('ERROR: ', error);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { isURL } from 'class-validator';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebhookDto } from '../dto/webhook.dto';
|
||||
import { WebhookService } from '../services/webhook.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('WebhookController');
|
||||
|
||||
@@ -13,14 +14,44 @@ export class WebhookController {
|
||||
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
||||
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (data.enabled && !isURL(data.url, { require_tld: false })) {
|
||||
if (!isURL(data.url, { require_tld: false })) {
|
||||
throw new BadRequestException('Invalid "url" property');
|
||||
}
|
||||
|
||||
data.enabled = data.enabled ?? true;
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('webhook disabled');
|
||||
data.url = '';
|
||||
data.events = [];
|
||||
} else if (data.events.length === 0) {
|
||||
logger.verbose('webhook events empty');
|
||||
data.events = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
}
|
||||
|
||||
return this.webhookService.create(instance, data);
|
||||
|
||||
56
src/whatsapp/controllers/websocket.controller.ts
Normal file
56
src/whatsapp/controllers/websocket.controller.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebsocketDto } from '../dto/websocket.dto';
|
||||
import { WebsocketService } from '../services/websocket.service';
|
||||
|
||||
const logger = new Logger('WebsocketController');
|
||||
|
||||
export class WebsocketController {
|
||||
constructor(private readonly websocketService: WebsocketService) {}
|
||||
|
||||
public async createWebsocket(instance: InstanceDto, data: WebsocketDto) {
|
||||
logger.verbose('requested createWebsocket from ' + instance.instanceName + ' instance');
|
||||
|
||||
if (!data.enabled) {
|
||||
logger.verbose('websocket disabled');
|
||||
data.events = [];
|
||||
}
|
||||
|
||||
if (data.events.length === 0) {
|
||||
logger.verbose('websocket events empty');
|
||||
data.events = [
|
||||
'APPLICATION_STARTUP',
|
||||
'QRCODE_UPDATED',
|
||||
'MESSAGES_SET',
|
||||
'MESSAGES_UPSERT',
|
||||
'MESSAGES_UPDATE',
|
||||
'MESSAGES_DELETE',
|
||||
'SEND_MESSAGE',
|
||||
'CONTACTS_SET',
|
||||
'CONTACTS_UPSERT',
|
||||
'CONTACTS_UPDATE',
|
||||
'PRESENCE_UPDATE',
|
||||
'CHATS_SET',
|
||||
'CHATS_UPSERT',
|
||||
'CHATS_UPDATE',
|
||||
'CHATS_DELETE',
|
||||
'GROUPS_UPSERT',
|
||||
'GROUP_UPDATE',
|
||||
'GROUP_PARTICIPANTS_UPDATE',
|
||||
'CONNECTION_UPDATE',
|
||||
'CALL',
|
||||
'NEW_JWT_TOKEN',
|
||||
'TYPEBOT_START',
|
||||
'TYPEBOT_CHANGE_STATUS',
|
||||
'CHAMA_AI_ACTION',
|
||||
];
|
||||
}
|
||||
|
||||
return this.websocketService.create(instance, data);
|
||||
}
|
||||
|
||||
public async findWebsocket(instance: InstanceDto) {
|
||||
logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance');
|
||||
return this.websocketService.find(instance);
|
||||
}
|
||||
}
|
||||
7
src/whatsapp/dto/chamaai.dto.ts
Normal file
7
src/whatsapp/dto/chamaai.dto.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class ChamaaiDto {
|
||||
enabled: boolean;
|
||||
url: string;
|
||||
token: string;
|
||||
waNumber: string;
|
||||
answerByAudio: boolean;
|
||||
}
|
||||
@@ -1,16 +1,7 @@
|
||||
import {
|
||||
WAPrivacyOnlineValue,
|
||||
WAPrivacyValue,
|
||||
WAReadReceiptsValue,
|
||||
proto,
|
||||
} from '@whiskeysockets/baileys';
|
||||
import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
|
||||
|
||||
export class OnWhatsAppDto {
|
||||
constructor(
|
||||
public readonly jid: string,
|
||||
public readonly exists: boolean,
|
||||
public readonly name?: string,
|
||||
) {}
|
||||
constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {}
|
||||
}
|
||||
|
||||
export class getBase64FromMediaMessageDto {
|
||||
@@ -59,16 +50,17 @@ class Key {
|
||||
remoteJid: string;
|
||||
}
|
||||
export class ReadMessageDto {
|
||||
readMessages: Key[];
|
||||
read_messages: Key[];
|
||||
}
|
||||
|
||||
class LastMessage {
|
||||
export class LastMessage {
|
||||
key: Key;
|
||||
messageTimestamp?: number;
|
||||
}
|
||||
|
||||
export class ArchiveChatDto {
|
||||
lastMessage: LastMessage;
|
||||
lastMessage?: LastMessage;
|
||||
chat?: string;
|
||||
archive: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,4 +5,7 @@ export class ChatwootDto {
|
||||
url?: string;
|
||||
name_inbox?: string;
|
||||
sign_msg?: boolean;
|
||||
number?: string;
|
||||
reopen_conversation?: boolean;
|
||||
conversation_pending?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export class CreateGroupDto {
|
||||
subject: string;
|
||||
description?: string;
|
||||
participants: string[];
|
||||
description?: string;
|
||||
promoteParticipants?: boolean;
|
||||
}
|
||||
|
||||
export class GroupPictureDto {
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
export class InstanceDto {
|
||||
instanceName: string;
|
||||
qrcode?: boolean;
|
||||
number?: string;
|
||||
token?: string;
|
||||
webhook?: string;
|
||||
webhook_by_events?: boolean;
|
||||
events?: string[];
|
||||
qrcode?: boolean;
|
||||
token?: string;
|
||||
reject_call?: boolean;
|
||||
msg_call?: string;
|
||||
groups_ignore?: boolean;
|
||||
always_online?: boolean;
|
||||
read_messages?: boolean;
|
||||
read_status?: boolean;
|
||||
chatwoot_account_id?: string;
|
||||
chatwoot_token?: string;
|
||||
chatwoot_url?: string;
|
||||
chatwoot_sign_msg?: boolean;
|
||||
chatwoot_reopen_conversation?: boolean;
|
||||
chatwoot_conversation_pending?: boolean;
|
||||
websocket_enabled?: boolean;
|
||||
websocket_events?: string[];
|
||||
rabbitmq_enabled?: boolean;
|
||||
rabbitmq_events?: string[];
|
||||
typebot_url?: string;
|
||||
typebot?: string;
|
||||
typebot_expire?: number;
|
||||
typebot_keyword_finish?: string;
|
||||
typebot_delay_message?: number;
|
||||
typebot_unknown_message?: string;
|
||||
typebot_listening_from_me?: boolean;
|
||||
proxy_enabled?: boolean;
|
||||
proxy_proxy?: string;
|
||||
}
|
||||
|
||||
4
src/whatsapp/dto/proxy.dto.ts
Normal file
4
src/whatsapp/dto/proxy.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class ProxyDto {
|
||||
enabled: boolean;
|
||||
proxy: string;
|
||||
}
|
||||
4
src/whatsapp/dto/rabbitmq.dto.ts
Normal file
4
src/whatsapp/dto/rabbitmq.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class RabbitmqDto {
|
||||
enabled: boolean;
|
||||
events?: string[];
|
||||
}
|
||||
@@ -15,6 +15,8 @@ export class Options {
|
||||
presence?: WAPresence;
|
||||
quoted?: Quoted;
|
||||
mentions?: Mentions;
|
||||
linkPreview?: boolean;
|
||||
encoding?: boolean;
|
||||
}
|
||||
class OptionsMessage {
|
||||
options: Options;
|
||||
|
||||
8
src/whatsapp/dto/settings.dto.ts
Normal file
8
src/whatsapp/dto/settings.dto.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export class SettingsDto {
|
||||
reject_call?: boolean;
|
||||
msg_call?: string;
|
||||
groups_ignore?: boolean;
|
||||
always_online?: boolean;
|
||||
read_messages?: boolean;
|
||||
read_status?: boolean;
|
||||
}
|
||||
19
src/whatsapp/dto/typebot.dto.ts
Normal file
19
src/whatsapp/dto/typebot.dto.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export class Session {
|
||||
remoteJid?: string;
|
||||
sessionId?: string;
|
||||
status?: string;
|
||||
createdAt?: number;
|
||||
updateAt?: number;
|
||||
}
|
||||
|
||||
export class TypebotDto {
|
||||
enabled?: boolean;
|
||||
url: string;
|
||||
typebot?: string;
|
||||
expire?: number;
|
||||
keyword_finish?: string;
|
||||
delay_message?: number;
|
||||
unknown_message?: string;
|
||||
listening_from_me?: boolean;
|
||||
sessions?: Session[];
|
||||
}
|
||||
4
src/whatsapp/dto/websocket.dto.ts
Normal file
4
src/whatsapp/dto/websocket.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class WebsocketDto {
|
||||
enabled: boolean;
|
||||
events?: string[];
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import { isJWT } from 'class-validator';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import { name } from '../../../package.json';
|
||||
import { Auth, configService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { name } from '../../../package.json';
|
||||
import { ForbiddenException, UnauthorizedException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { JwtPayload } from '../services/auth.service';
|
||||
import { ForbiddenException, UnauthorizedException } from '../../exceptions';
|
||||
import { repository } from '../whatsapp.module';
|
||||
|
||||
const logger = new Logger('GUARD');
|
||||
@@ -22,15 +23,8 @@ async function jwtGuard(req: Request, res: Response, next: NextFunction) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (
|
||||
(req.originalUrl.includes('/instance/create') ||
|
||||
req.originalUrl.includes('/instance/fetchInstances')) &&
|
||||
!key
|
||||
) {
|
||||
throw new ForbiddenException(
|
||||
'Missing global api key',
|
||||
'The global api key must be set',
|
||||
);
|
||||
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
|
||||
throw new ForbiddenException('Missing global api key', 'The global api key must be set');
|
||||
}
|
||||
|
||||
const jwtOpts = configService.get<Auth>('AUTHENTICATION').JWT;
|
||||
@@ -61,7 +55,7 @@ async function jwtGuard(req: Request, res: Response, next: NextFunction) {
|
||||
}
|
||||
}
|
||||
|
||||
async function apikey(req: Request, res: Response, next: NextFunction) {
|
||||
async function apikey(req: Request, _: Response, next: NextFunction) {
|
||||
const env = configService.get<Auth>('AUTHENTICATION').API_KEY;
|
||||
const key = req.get('apikey');
|
||||
|
||||
@@ -69,15 +63,8 @@ async function apikey(req: Request, res: Response, next: NextFunction) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (
|
||||
(req.originalUrl.includes('/instance/create') ||
|
||||
req.originalUrl.includes('/instance/fetchInstances')) &&
|
||||
!key
|
||||
) {
|
||||
throw new ForbiddenException(
|
||||
'Missing global api key',
|
||||
'The global api key must be set',
|
||||
);
|
||||
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
|
||||
throw new ForbiddenException('Missing global api key', 'The global api key must be set');
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -86,7 +73,9 @@ async function apikey(req: Request, res: Response, next: NextFunction) {
|
||||
if (instanceKey.apikey === key) {
|
||||
return next();
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
||||
@@ -1,44 +1,47 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { configService, Database, Redis } from '../../config/env.config';
|
||||
import { INSTANCE_DIR } from '../../config/path.config';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
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';
|
||||
import { Database, Redis, configService } from '../../config/env.config';
|
||||
|
||||
async function getInstance(instanceName: string) {
|
||||
const db = configService.get<Database>('DATABASE');
|
||||
const redisConf = configService.get<Redis>('REDIS');
|
||||
try {
|
||||
const db = configService.get<Database>('DATABASE');
|
||||
const redisConf = configService.get<Redis>('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) {
|
||||
if (
|
||||
req.originalUrl.includes('/instance/create') ||
|
||||
req.originalUrl.includes('/instance/fetchInstances')
|
||||
) {
|
||||
if (req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -58,9 +61,7 @@ export async function instanceLoggedGuard(req: Request, _: Response, next: NextF
|
||||
if (req.originalUrl.includes('/instance/create')) {
|
||||
const instance = req.body as InstanceDto;
|
||||
if (await getInstance(instance.instanceName)) {
|
||||
throw new ForbiddenException(
|
||||
`This name "${instance.instanceName}" is already in use.`,
|
||||
);
|
||||
throw new ForbiddenException(`This name "${instance.instanceName}" is already in use.`);
|
||||
}
|
||||
|
||||
if (waMonitor.waInstances[instance.instanceName]) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class AuthRaw {
|
||||
_id?: string;
|
||||
|
||||
24
src/whatsapp/models/chamaai.model.ts
Normal file
24
src/whatsapp/models/chamaai.model.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ChamaaiRaw {
|
||||
_id?: string;
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
token?: string;
|
||||
waNumber?: string;
|
||||
answerByAudio?: boolean;
|
||||
}
|
||||
|
||||
const chamaaiSchema = new Schema<ChamaaiRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
enabled: { type: Boolean, required: true },
|
||||
url: { type: String, required: true },
|
||||
token: { type: String, required: true },
|
||||
waNumber: { type: String, required: true },
|
||||
answerByAudio: { type: Boolean, required: true },
|
||||
});
|
||||
|
||||
export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai');
|
||||
export type IChamaaiModel = typeof ChamaaiModel;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ChatRaw {
|
||||
_id?: string;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ChatwootRaw {
|
||||
_id?: string;
|
||||
@@ -9,6 +10,9 @@ export class ChatwootRaw {
|
||||
url?: string;
|
||||
name_inbox?: string;
|
||||
sign_msg?: boolean;
|
||||
number?: string;
|
||||
reopen_conversation?: boolean;
|
||||
conversation_pending?: boolean;
|
||||
}
|
||||
|
||||
const chatwootSchema = new Schema<ChatwootRaw>({
|
||||
@@ -19,11 +23,8 @@ const chatwootSchema = new Schema<ChatwootRaw>({
|
||||
url: { type: String, required: true },
|
||||
name_inbox: { type: String, required: true },
|
||||
sign_msg: { type: Boolean, required: true },
|
||||
number: { type: String, required: true },
|
||||
});
|
||||
|
||||
export const ChatwootModel = dbserver?.model(
|
||||
ChatwootRaw.name,
|
||||
chatwootSchema,
|
||||
'chatwoot',
|
||||
);
|
||||
export const ChatwootModel = dbserver?.model(ChatwootRaw.name, chatwootSchema, 'chatwoot');
|
||||
export type IChatwootModel = typeof ChatwootModel;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ContactRaw {
|
||||
_id?: string;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
export * from './auth.model';
|
||||
export * from './chamaai.model';
|
||||
export * from './chat.model';
|
||||
export * from './chatwoot.model';
|
||||
export * from './contact.model';
|
||||
export * from './message.model';
|
||||
export * from './auth.model';
|
||||
export * from './proxy.model';
|
||||
export * from './rabbitmq.model';
|
||||
export * from './settings.model';
|
||||
export * from './typebot.model';
|
||||
export * from './webhook.model';
|
||||
export * from './chatwoot.model';
|
||||
export * from './websocket.model';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
import { wa } from '../types/wa.types';
|
||||
|
||||
class Key {
|
||||
@@ -64,9 +65,5 @@ const messageUpdateSchema = new Schema<MessageUpdateRaw>({
|
||||
owner: { type: String, required: true, min: 1 },
|
||||
});
|
||||
|
||||
export const MessageUpModel = dbserver?.model(
|
||||
MessageUpdateRaw.name,
|
||||
messageUpdateSchema,
|
||||
'messageUpdate',
|
||||
);
|
||||
export const MessageUpModel = dbserver?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate');
|
||||
export type IMessageUpModel = typeof MessageUpModel;
|
||||
|
||||
18
src/whatsapp/models/proxy.model.ts
Normal file
18
src/whatsapp/models/proxy.model.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class ProxyRaw {
|
||||
_id?: string;
|
||||
enabled?: boolean;
|
||||
proxy?: string;
|
||||
}
|
||||
|
||||
const proxySchema = new Schema<ProxyRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
enabled: { type: Boolean, required: true },
|
||||
proxy: { type: String, required: true },
|
||||
});
|
||||
|
||||
export const ProxyModel = dbserver?.model(ProxyRaw.name, proxySchema, 'proxy');
|
||||
export type IProxyModel = typeof ProxyModel;
|
||||
18
src/whatsapp/models/rabbitmq.model.ts
Normal file
18
src/whatsapp/models/rabbitmq.model.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class RabbitmqRaw {
|
||||
_id?: string;
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
}
|
||||
|
||||
const rabbitmqSchema = new Schema<RabbitmqRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
enabled: { type: Boolean, required: true },
|
||||
events: { type: [String], required: true },
|
||||
});
|
||||
|
||||
export const RabbitmqModel = dbserver?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq');
|
||||
export type IRabbitmqModel = typeof RabbitmqModel;
|
||||
26
src/whatsapp/models/settings.model.ts
Normal file
26
src/whatsapp/models/settings.model.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class SettingsRaw {
|
||||
_id?: string;
|
||||
reject_call?: boolean;
|
||||
msg_call?: string;
|
||||
groups_ignore?: boolean;
|
||||
always_online?: boolean;
|
||||
read_messages?: boolean;
|
||||
read_status?: boolean;
|
||||
}
|
||||
|
||||
const settingsSchema = new Schema<SettingsRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
reject_call: { type: Boolean, required: true },
|
||||
msg_call: { type: String, required: true },
|
||||
groups_ignore: { type: Boolean, required: true },
|
||||
always_online: { type: Boolean, required: true },
|
||||
read_messages: { type: Boolean, required: true },
|
||||
read_status: { type: Boolean, required: true },
|
||||
});
|
||||
|
||||
export const SettingsModel = dbserver?.model(SettingsRaw.name, settingsSchema, 'settings');
|
||||
export type ISettingsModel = typeof SettingsModel;
|
||||
48
src/whatsapp/models/typebot.model.ts
Normal file
48
src/whatsapp/models/typebot.model.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
class Session {
|
||||
remoteJid?: string;
|
||||
sessionId?: string;
|
||||
status?: string;
|
||||
createdAt?: number;
|
||||
updateAt?: number;
|
||||
}
|
||||
|
||||
export class TypebotRaw {
|
||||
_id?: string;
|
||||
enabled?: boolean;
|
||||
url: string;
|
||||
typebot?: string;
|
||||
expire?: number;
|
||||
keyword_finish?: string;
|
||||
delay_message?: number;
|
||||
unknown_message?: string;
|
||||
listening_from_me?: boolean;
|
||||
sessions?: Session[];
|
||||
}
|
||||
|
||||
const typebotSchema = new Schema<TypebotRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
enabled: { type: Boolean, required: true },
|
||||
url: { type: String, required: true },
|
||||
typebot: { type: String, required: true },
|
||||
expire: { type: Number, required: true },
|
||||
keyword_finish: { type: String, required: true },
|
||||
delay_message: { type: Number, required: true },
|
||||
unknown_message: { type: String, required: true },
|
||||
listening_from_me: { type: Boolean, required: true },
|
||||
sessions: [
|
||||
{
|
||||
remoteJid: { type: String, required: true },
|
||||
sessionId: { type: String, required: true },
|
||||
status: { type: String, required: true },
|
||||
createdAt: { type: Number, required: true },
|
||||
updateAt: { type: Number, required: true },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot');
|
||||
export type ITypebotModel = typeof TypebotModel;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Schema } from 'mongoose';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class WebhookRaw {
|
||||
_id?: string;
|
||||
|
||||
18
src/whatsapp/models/websocket.model.ts
Normal file
18
src/whatsapp/models/websocket.model.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Schema } from 'mongoose';
|
||||
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
|
||||
export class WebsocketRaw {
|
||||
_id?: string;
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
}
|
||||
|
||||
const websocketSchema = new Schema<WebsocketRaw>({
|
||||
_id: { type: String, _id: true },
|
||||
enabled: { type: Boolean, required: true },
|
||||
events: { type: [String], required: true },
|
||||
});
|
||||
|
||||
export const WebsocketModel = dbserver?.model(WebsocketRaw.name, websocketSchema, 'websocket');
|
||||
export type IWebsocketModel = typeof WebsocketModel;
|
||||
@@ -1,16 +1,14 @@
|
||||
import { join } from 'path';
|
||||
import { Auth, ConfigService } from '../../config/env.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IAuthModel, AuthRaw } from '../models';
|
||||
import { readFileSync } from 'fs';
|
||||
import { AUTH_DIR } from '../../config/path.config';
|
||||
import { join } from 'path';
|
||||
|
||||
import { Auth, ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { AUTH_DIR } from '../../config/path.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { AuthRaw, IAuthModel } from '../models';
|
||||
|
||||
export class AuthRepository extends Repository {
|
||||
constructor(
|
||||
private readonly authModel: IAuthModel,
|
||||
readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly authModel: IAuthModel, readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
this.auth = configService.get<Auth>('AUTHENTICATION');
|
||||
}
|
||||
@@ -23,11 +21,7 @@ export class AuthRepository extends Repository {
|
||||
this.logger.verbose('creating auth');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving auth to db');
|
||||
const insert = await this.authModel.replaceOne(
|
||||
{ _id: instance },
|
||||
{ ...data },
|
||||
{ upsert: true },
|
||||
);
|
||||
const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
@@ -40,9 +34,7 @@ export class AuthRepository extends Repository {
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance,
|
||||
);
|
||||
this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance);
|
||||
|
||||
this.logger.verbose('auth created');
|
||||
return { insertCount: 1 };
|
||||
|
||||
62
src/whatsapp/repository/chamaai.repository.ts
Normal file
62
src/whatsapp/repository/chamaai.repository.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ChamaaiRaw, IChamaaiModel } from '../models';
|
||||
|
||||
export class ChamaaiRepository extends Repository {
|
||||
constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('ChamaaiRepository');
|
||||
|
||||
public async create(data: ChamaaiRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating chamaai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving chamaai to db');
|
||||
const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving chamaai to store');
|
||||
|
||||
this.writeStore<ChamaaiRaw>({
|
||||
path: join(this.storePath, 'chamaai'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance);
|
||||
|
||||
this.logger.verbose('chamaai created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<ChamaaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding chamaai');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding chamaai in db');
|
||||
return await this.chamaaiModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding chamaai in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'chamaai', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as ChamaaiRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,23 @@
|
||||
import { join } from 'path';
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { opendirSync, readFileSync, rmSync } from 'fs';
|
||||
import { ChatRaw, IChatModel } from '../models';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ChatRaw, IChatModel } from '../models';
|
||||
|
||||
export class ChatQuery {
|
||||
where: ChatRaw;
|
||||
}
|
||||
|
||||
export class ChatRepository extends Repository {
|
||||
constructor(
|
||||
private readonly chatModel: IChatModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('ChatRepository');
|
||||
|
||||
public async insert(
|
||||
data: ChatRaw[],
|
||||
instanceName: string,
|
||||
saveDb = false,
|
||||
): Promise<IInsert> {
|
||||
public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
this.logger.verbose('inserting chats');
|
||||
if (data.length === 0) {
|
||||
this.logger.verbose('no chats to insert');
|
||||
@@ -53,10 +47,7 @@ export class ChatRepository extends Repository {
|
||||
data: chat,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'chats saved to store in path: ' +
|
||||
join(this.storePath, 'chats', instanceName) +
|
||||
'/' +
|
||||
chat.id,
|
||||
'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -89,10 +80,9 @@ export class ChatRepository extends Repository {
|
||||
if (dirent.isFile()) {
|
||||
chats.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(this.storePath, 'chats', query.where.owner, dirent.name),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { join } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { IChatwootModel, ChatwootRaw } from '../models';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ChatwootRaw, IChatwootModel } from '../models';
|
||||
|
||||
export class ChatwootRepository extends Repository {
|
||||
constructor(
|
||||
private readonly chatwootModel: IChatwootModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
@@ -20,15 +18,9 @@ export class ChatwootRepository extends Repository {
|
||||
this.logger.verbose('creating chatwoot');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving chatwoot to db');
|
||||
const insert = await this.chatwootModel.replaceOne(
|
||||
{ _id: instance },
|
||||
{ ...data },
|
||||
{ upsert: true },
|
||||
);
|
||||
const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose(
|
||||
'chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot',
|
||||
);
|
||||
this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
@@ -40,12 +32,7 @@ export class ChatwootRepository extends Repository {
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose(
|
||||
'chatwoot saved to store in path: ' +
|
||||
join(this.storePath, 'chatwoot') +
|
||||
'/' +
|
||||
instance,
|
||||
);
|
||||
this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance);
|
||||
|
||||
this.logger.verbose('chatwoot created');
|
||||
return { insertCount: 1 };
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
import { opendirSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { ContactRaw, IContactModel } from '../models';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ContactRaw, IContactModel } from '../models';
|
||||
|
||||
export class ContactQuery {
|
||||
where: ContactRaw;
|
||||
}
|
||||
|
||||
export class ContactRepository extends Repository {
|
||||
constructor(
|
||||
private readonly contactModel: IContactModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('ContactRepository');
|
||||
|
||||
public async insert(
|
||||
data: ContactRaw[],
|
||||
instanceName: string,
|
||||
saveDb = false,
|
||||
): Promise<IInsert> {
|
||||
public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
this.logger.verbose('inserting contacts');
|
||||
|
||||
if (data.length === 0) {
|
||||
@@ -54,10 +48,7 @@ export class ContactRepository extends Repository {
|
||||
data: contact,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'contacts saved to store in path: ' +
|
||||
join(this.storePath, 'contacts', instanceName) +
|
||||
'/' +
|
||||
contact.id,
|
||||
'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -74,11 +65,7 @@ export class ContactRepository extends Repository {
|
||||
}
|
||||
}
|
||||
|
||||
public async update(
|
||||
data: ContactRaw[],
|
||||
instanceName: string,
|
||||
saveDb = false,
|
||||
): Promise<IInsert> {
|
||||
public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('updating contacts');
|
||||
|
||||
@@ -119,10 +106,7 @@ export class ContactRepository extends Repository {
|
||||
data: contact,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'contacts updated in store in path: ' +
|
||||
join(this.storePath, 'contacts', instanceName) +
|
||||
'/' +
|
||||
contact.id,
|
||||
'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -154,15 +138,9 @@ export class ContactRepository extends Repository {
|
||||
this.logger.verbose('finding contacts in store by id');
|
||||
contacts.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(
|
||||
this.storePath,
|
||||
'contacts',
|
||||
query.where.owner,
|
||||
query.where.id + '.json',
|
||||
),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@@ -175,10 +153,9 @@ export class ContactRepository extends Repository {
|
||||
if (dirent.isFile()) {
|
||||
contacts.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(this.storePath, 'contacts', query.where.owner, dirent.name),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { join } from 'path';
|
||||
import { IMessageModel, MessageRaw } from '../models';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { opendirSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IMessageModel, MessageRaw } from '../models';
|
||||
|
||||
export class MessageQuery {
|
||||
where: MessageRaw;
|
||||
@@ -11,20 +12,13 @@ export class MessageQuery {
|
||||
}
|
||||
|
||||
export class MessageRepository extends Repository {
|
||||
constructor(
|
||||
private readonly messageModel: IMessageModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('MessageRepository');
|
||||
|
||||
public async insert(
|
||||
data: MessageRaw[],
|
||||
instanceName: string,
|
||||
saveDb = false,
|
||||
): Promise<IInsert> {
|
||||
public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
|
||||
this.logger.verbose('inserting messages');
|
||||
|
||||
if (!Array.isArray(data) || data.length === 0) {
|
||||
@@ -74,10 +68,7 @@ export class MessageRepository extends Repository {
|
||||
data: message,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'messages saved to store in path: ' +
|
||||
join(this.storePath, 'messages', instanceName) +
|
||||
'/' +
|
||||
message.key.id,
|
||||
'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -119,15 +110,9 @@ export class MessageRepository extends Repository {
|
||||
this.logger.verbose('finding messages in store by id');
|
||||
messages.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(
|
||||
this.storePath,
|
||||
'messages',
|
||||
query.where.owner,
|
||||
query.where.key.id + '.json',
|
||||
),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@@ -140,10 +125,9 @@ export class MessageRepository extends Repository {
|
||||
if (dirent.isFile()) {
|
||||
messages.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(this.storePath, 'messages', query.where.owner, dirent.name),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { IMessageUpModel, MessageUpdateRaw } from '../models';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { join } from 'path';
|
||||
import { opendirSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService, StoreConf } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IMessageUpModel, MessageUpdateRaw } from '../models';
|
||||
|
||||
export class MessageUpQuery {
|
||||
where: MessageUpdateRaw;
|
||||
@@ -11,20 +12,13 @@ export class MessageUpQuery {
|
||||
}
|
||||
|
||||
export class MessageUpRepository extends Repository {
|
||||
constructor(
|
||||
private readonly messageUpModel: IMessageUpModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('MessageUpRepository');
|
||||
|
||||
public async insert(
|
||||
data: MessageUpdateRaw[],
|
||||
instanceName: string,
|
||||
saveDb?: boolean,
|
||||
): Promise<IInsert> {
|
||||
public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise<IInsert> {
|
||||
this.logger.verbose('inserting message up');
|
||||
|
||||
if (data.length === 0) {
|
||||
@@ -54,10 +48,7 @@ export class MessageUpRepository extends Repository {
|
||||
data: update,
|
||||
});
|
||||
this.logger.verbose(
|
||||
'message up saved to store in path: ' +
|
||||
join(this.storePath, 'message-up', instanceName) +
|
||||
'/' +
|
||||
update.id,
|
||||
'message up saved to store in path: ' + join(this.storePath, 'message-up', instanceName) + '/' + update.id,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -91,42 +82,32 @@ export class MessageUpRepository extends Repository {
|
||||
|
||||
messageUpdate.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(
|
||||
this.storePath,
|
||||
'message-up',
|
||||
query.where.owner,
|
||||
query.where.id + '.json',
|
||||
),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
this.logger.verbose('finding message up in store by owner');
|
||||
|
||||
const openDir = opendirSync(
|
||||
join(this.storePath, 'message-up', query.where.owner),
|
||||
{ encoding: 'utf-8' },
|
||||
);
|
||||
const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
for await (const dirent of openDir) {
|
||||
if (dirent.isFile()) {
|
||||
messageUpdate.push(
|
||||
JSON.parse(
|
||||
readFileSync(
|
||||
join(this.storePath, 'message-up', query.where.owner, dirent.name),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.verbose(
|
||||
'message up found in store: ' + messageUpdate.length + ' message up',
|
||||
);
|
||||
this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up');
|
||||
return messageUpdate
|
||||
.sort((x, y) => {
|
||||
return y.datetime - x.datetime;
|
||||
|
||||
62
src/whatsapp/repository/proxy.repository.ts
Normal file
62
src/whatsapp/repository/proxy.repository.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IProxyModel, ProxyRaw } from '../models';
|
||||
|
||||
export class ProxyRepository extends Repository {
|
||||
constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('ProxyRepository');
|
||||
|
||||
public async create(data: ProxyRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating proxy');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving proxy to db');
|
||||
const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving proxy to store');
|
||||
|
||||
this.writeStore<ProxyRaw>({
|
||||
path: join(this.storePath, 'proxy'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance);
|
||||
|
||||
this.logger.verbose('proxy created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<ProxyRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding proxy');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding proxy in db');
|
||||
return await this.proxyModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding proxy in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'proxy', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as ProxyRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/whatsapp/repository/rabbitmq.repository.ts
Normal file
62
src/whatsapp/repository/rabbitmq.repository.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IRabbitmqModel, RabbitmqRaw } from '../models';
|
||||
|
||||
export class RabbitmqRepository extends Repository {
|
||||
constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('RabbitmqRepository');
|
||||
|
||||
public async create(data: RabbitmqRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating rabbitmq');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving rabbitmq to db');
|
||||
const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving rabbitmq to store');
|
||||
|
||||
this.writeStore<RabbitmqRaw>({
|
||||
path: join(this.storePath, 'rabbitmq'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance);
|
||||
|
||||
this.logger.verbose('rabbitmq created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<RabbitmqRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding rabbitmq');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding rabbitmq in db');
|
||||
return await this.rabbitmqModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding rabbitmq in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as RabbitmqRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
import { MessageRepository } from './message.repository';
|
||||
import { ChatRepository } from './chat.repository';
|
||||
import { ContactRepository } from './contact.repository';
|
||||
import { MessageUpRepository } from './messageUp.repository';
|
||||
import { MongoClient } from 'mongodb';
|
||||
import { WebhookRepository } from './webhook.repository';
|
||||
import { ChatwootRepository } from './chatwoot.repository';
|
||||
|
||||
import { AuthRepository } from './auth.repository';
|
||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||
import { execSync } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import fs from 'fs';
|
||||
import { MongoClient } from 'mongodb';
|
||||
import { join } from 'path';
|
||||
|
||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { AuthRepository } from './auth.repository';
|
||||
import { ChamaaiRepository } from './chamaai.repository';
|
||||
import { ChatRepository } from './chat.repository';
|
||||
import { ChatwootRepository } from './chatwoot.repository';
|
||||
import { ContactRepository } from './contact.repository';
|
||||
import { MessageRepository } from './message.repository';
|
||||
import { MessageUpRepository } from './messageUp.repository';
|
||||
import { ProxyRepository } from './proxy.repository';
|
||||
import { RabbitmqRepository } from './rabbitmq.repository';
|
||||
import { SettingsRepository } from './settings.repository';
|
||||
import { TypebotRepository } from './typebot.repository';
|
||||
import { WebhookRepository } from './webhook.repository';
|
||||
import { WebsocketRepository } from './websocket.repository';
|
||||
export class RepositoryBroker {
|
||||
constructor(
|
||||
public readonly message: MessageRepository,
|
||||
@@ -20,6 +25,12 @@ export class RepositoryBroker {
|
||||
public readonly messageUpdate: MessageUpRepository,
|
||||
public readonly webhook: WebhookRepository,
|
||||
public readonly chatwoot: ChatwootRepository,
|
||||
public readonly settings: SettingsRepository,
|
||||
public readonly websocket: WebsocketRepository,
|
||||
public readonly rabbitmq: RabbitmqRepository,
|
||||
public readonly typebot: TypebotRepository,
|
||||
public readonly proxy: ProxyRepository,
|
||||
public readonly chamaai: ChamaaiRepository,
|
||||
public readonly auth: AuthRepository,
|
||||
private configService: ConfigService,
|
||||
dbServer?: MongoClient,
|
||||
@@ -42,20 +53,21 @@ export class RepositoryBroker {
|
||||
|
||||
this.logger.verbose('creating store path: ' + storePath);
|
||||
try {
|
||||
const authDir = join(
|
||||
storePath,
|
||||
'auth',
|
||||
this.configService.get<Auth>('AUTHENTICATION').TYPE,
|
||||
);
|
||||
const authDir = join(storePath, 'auth', this.configService.get<Auth>('AUTHENTICATION').TYPE);
|
||||
const chatsDir = join(storePath, 'chats');
|
||||
const contactsDir = join(storePath, 'contacts');
|
||||
const messagesDir = join(storePath, 'messages');
|
||||
const messageUpDir = join(storePath, 'message-up');
|
||||
const webhookDir = join(storePath, 'webhook');
|
||||
const chatwootDir = join(storePath, 'chatwoot');
|
||||
const settingsDir = join(storePath, 'settings');
|
||||
const websocketDir = join(storePath, 'websocket');
|
||||
const rabbitmqDir = join(storePath, 'rabbitmq');
|
||||
const typebotDir = join(storePath, 'typebot');
|
||||
const proxyDir = join(storePath, 'proxy');
|
||||
const chamaaiDir = join(storePath, 'chamaai');
|
||||
const tempDir = join(storePath, 'temp');
|
||||
|
||||
// Check if directories exist, create them if not
|
||||
if (!fs.existsSync(authDir)) {
|
||||
this.logger.verbose('creating auth dir: ' + authDir);
|
||||
fs.mkdirSync(authDir, { recursive: true });
|
||||
@@ -80,6 +92,50 @@ export class RepositoryBroker {
|
||||
this.logger.verbose('creating webhook dir: ' + webhookDir);
|
||||
fs.mkdirSync(webhookDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(chatwootDir)) {
|
||||
this.logger.verbose('creating chatwoot dir: ' + chatwootDir);
|
||||
fs.mkdirSync(chatwootDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(settingsDir)) {
|
||||
this.logger.verbose('creating settings dir: ' + settingsDir);
|
||||
fs.mkdirSync(settingsDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(websocketDir)) {
|
||||
this.logger.verbose('creating websocket dir: ' + websocketDir);
|
||||
fs.mkdirSync(websocketDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(rabbitmqDir)) {
|
||||
this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir);
|
||||
fs.mkdirSync(rabbitmqDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(typebotDir)) {
|
||||
this.logger.verbose('creating typebot dir: ' + typebotDir);
|
||||
fs.mkdirSync(typebotDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(proxyDir)) {
|
||||
this.logger.verbose('creating proxy dir: ' + proxyDir);
|
||||
fs.mkdirSync(proxyDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(chamaaiDir)) {
|
||||
this.logger.verbose('creating chamaai dir: ' + chamaaiDir);
|
||||
fs.mkdirSync(chamaaiDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(tempDir)) {
|
||||
this.logger.verbose('creating temp dir: ' + tempDir);
|
||||
fs.mkdirSync(tempDir, { recursive: true });
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const storePath = join(process.cwd(), 'store');
|
||||
|
||||
this.logger.verbose('creating store path: ' + storePath);
|
||||
|
||||
const tempDir = join(storePath, 'temp');
|
||||
const chatwootDir = join(storePath, 'chatwoot');
|
||||
|
||||
if (!fs.existsSync(chatwootDir)) {
|
||||
this.logger.verbose('creating chatwoot dir: ' + chatwootDir);
|
||||
fs.mkdirSync(chatwootDir, { recursive: true });
|
||||
|
||||
62
src/whatsapp/repository/settings.repository.ts
Normal file
62
src/whatsapp/repository/settings.repository.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ISettingsModel, SettingsRaw } from '../models';
|
||||
|
||||
export class SettingsRepository extends Repository {
|
||||
constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('SettingsRepository');
|
||||
|
||||
public async create(data: SettingsRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating settings');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving settings to db');
|
||||
const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving settings to store');
|
||||
|
||||
this.writeStore<SettingsRaw>({
|
||||
path: join(this.storePath, 'settings'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance);
|
||||
|
||||
this.logger.verbose('settings created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<SettingsRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding settings');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding settings in db');
|
||||
return await this.settingsModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding settings in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'settings', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as SettingsRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/whatsapp/repository/typebot.repository.ts
Normal file
68
src/whatsapp/repository/typebot.repository.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ITypebotModel, TypebotRaw } from '../models';
|
||||
|
||||
export class TypebotRepository extends Repository {
|
||||
constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('TypebotRepository');
|
||||
|
||||
public async create(data: TypebotRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating typebot');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving typebot to db');
|
||||
const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving typebot to store');
|
||||
|
||||
this.writeStore<TypebotRaw>({
|
||||
path: join(this.storePath, 'typebot'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance);
|
||||
|
||||
this.logger.verbose('typebot created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<TypebotRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding typebot');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding typebot in db');
|
||||
return await this.typebotModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding typebot in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'typebot', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as TypebotRaw;
|
||||
} catch (error) {
|
||||
return {
|
||||
enabled: false,
|
||||
url: '',
|
||||
typebot: '',
|
||||
expire: 0,
|
||||
sessions: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { join } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { IWebhookModel, WebhookRaw } from '../models';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IWebhookModel, WebhookRaw } from '../models';
|
||||
|
||||
export class WebhookRepository extends Repository {
|
||||
constructor(
|
||||
private readonly webhookModel: IWebhookModel,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
@@ -20,11 +18,7 @@ export class WebhookRepository extends Repository {
|
||||
this.logger.verbose('creating webhook');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving webhook to db');
|
||||
const insert = await this.webhookModel.replaceOne(
|
||||
{ _id: instance },
|
||||
{ ...data },
|
||||
{ upsert: true },
|
||||
);
|
||||
const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
@@ -38,12 +32,7 @@ export class WebhookRepository extends Repository {
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose(
|
||||
'webhook saved to store in path: ' +
|
||||
join(this.storePath, 'webhook') +
|
||||
'/' +
|
||||
instance,
|
||||
);
|
||||
this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance);
|
||||
|
||||
this.logger.verbose('webhook created');
|
||||
return { insertCount: 1 };
|
||||
|
||||
62
src/whatsapp/repository/websocket.repository.ts
Normal file
62
src/whatsapp/repository/websocket.repository.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { IInsert, Repository } from '../abstract/abstract.repository';
|
||||
import { IWebsocketModel, WebsocketRaw } from '../models';
|
||||
|
||||
export class WebsocketRepository extends Repository {
|
||||
constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) {
|
||||
super(configService);
|
||||
}
|
||||
|
||||
private readonly logger = new Logger('WebsocketRepository');
|
||||
|
||||
public async create(data: WebsocketRaw, instance: string): Promise<IInsert> {
|
||||
try {
|
||||
this.logger.verbose('creating websocket');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('saving websocket to db');
|
||||
const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
|
||||
|
||||
this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket');
|
||||
return { insertCount: insert.modifiedCount };
|
||||
}
|
||||
|
||||
this.logger.verbose('saving websocket to store');
|
||||
|
||||
this.writeStore<WebsocketRaw>({
|
||||
path: join(this.storePath, 'websocket'),
|
||||
fileName: instance,
|
||||
data,
|
||||
});
|
||||
|
||||
this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance);
|
||||
|
||||
this.logger.verbose('websocket created');
|
||||
return { insertCount: 1 };
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public async find(instance: string): Promise<WebsocketRaw> {
|
||||
try {
|
||||
this.logger.verbose('finding websocket');
|
||||
if (this.dbSettings.ENABLED) {
|
||||
this.logger.verbose('finding websocket in db');
|
||||
return await this.websocketModel.findOne({ _id: instance });
|
||||
}
|
||||
|
||||
this.logger.verbose('finding websocket in store');
|
||||
return JSON.parse(
|
||||
readFileSync(join(this.storePath, 'websocket', instance + '.json'), {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
) as WebsocketRaw;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/whatsapp/routers/chamaai.router.ts
Normal file
52
src/whatsapp/routers/chamaai.router.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { chamaaiSchema, instanceNameSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { ChamaaiDto } from '../dto/chamaai.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { chamaaiController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('ChamaaiRouter');
|
||||
|
||||
export class ChamaaiRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setChamaai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<ChamaaiDto>({
|
||||
request: req,
|
||||
schema: chamaaiSchema,
|
||||
ClassRef: ChamaaiDto,
|
||||
execute: (instance, data) => chamaaiController.createChamaai(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findChamaai');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => chamaaiController.findChamaai(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
archiveChatSchema,
|
||||
contactValidateSchema,
|
||||
@@ -13,9 +15,11 @@ import {
|
||||
readMessageSchema,
|
||||
whatsappNumberSchema,
|
||||
} from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import {
|
||||
ArchiveChatDto,
|
||||
DeleteMessage,
|
||||
getBase64FromMediaMessageDto,
|
||||
NumberDto,
|
||||
PrivacySettingDto,
|
||||
ProfileNameDto,
|
||||
@@ -23,17 +27,13 @@ import {
|
||||
ProfileStatusDto,
|
||||
ReadMessageDto,
|
||||
WhatsAppNumberDto,
|
||||
getBase64FromMediaMessageDto,
|
||||
} from '../dto/chat.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ContactQuery } from '../repository/contact.repository';
|
||||
import { MessageQuery } from '../repository/message.repository';
|
||||
import { chatController } from '../whatsapp.module';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { HttpStatus } from './index.router';
|
||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||
import { proto } from '@whiskeysockets/baileys';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { chatController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('ChatRouter');
|
||||
|
||||
@@ -92,27 +92,23 @@ export class ChatRouter extends RouterBroker {
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.delete(
|
||||
this.routerPath('deleteMessageForEveryone'),
|
||||
...guards,
|
||||
async (req, res) => {
|
||||
logger.verbose('request received in deleteMessageForEveryone');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
.delete(this.routerPath('deleteMessageForEveryone'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in deleteMessageForEveryone');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
|
||||
const response = await this.dataValidate<DeleteMessage>({
|
||||
request: req,
|
||||
schema: deleteMessageSchema,
|
||||
ClassRef: DeleteMessage,
|
||||
execute: (instance, data) => chatController.deleteMessage(instance, data),
|
||||
});
|
||||
const response = await this.dataValidate<DeleteMessage>({
|
||||
request: req,
|
||||
schema: deleteMessageSchema,
|
||||
ClassRef: DeleteMessage,
|
||||
execute: (instance, data) => chatController.deleteMessage(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
},
|
||||
)
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in fetchProfilePictureUrl');
|
||||
logger.verbose('request body: ');
|
||||
@@ -134,7 +130,7 @@ export class ChatRouter extends RouterBroker {
|
||||
logger.verbose('request received in fetchProfile');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
|
||||
@@ -176,8 +172,7 @@ export class ChatRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: null,
|
||||
ClassRef: getBase64FromMediaMessageDto,
|
||||
execute: (instance, data) =>
|
||||
chatController.getBase64FromMediaMessage(instance, data),
|
||||
execute: (instance, data) => chatController.getBase64FromMediaMessage(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
@@ -263,8 +258,7 @@ export class ChatRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: privacySettingsSchema,
|
||||
ClassRef: PrivacySettingDto,
|
||||
execute: (instance, data) =>
|
||||
chatController.updatePrivacySettings(instance, data),
|
||||
execute: (instance, data) => chatController.updatePrivacySettings(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
@@ -281,8 +275,7 @@ export class ChatRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: profilePictureSchema,
|
||||
ClassRef: ProfilePictureDto,
|
||||
execute: (instance, data) =>
|
||||
chatController.fetchBusinessProfile(instance, data),
|
||||
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
@@ -333,8 +326,7 @@ export class ChatRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: profilePictureSchema,
|
||||
ClassRef: ProfilePictureDto,
|
||||
execute: (instance, data) =>
|
||||
chatController.updateProfilePicture(instance, data),
|
||||
execute: (instance, data) => chatController.updateProfilePicture(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
@@ -351,8 +343,7 @@ export class ChatRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: profilePictureSchema,
|
||||
ClassRef: ProfilePictureDto,
|
||||
execute: (instance, data) =>
|
||||
chatController.removeProfilePicture(instance, data),
|
||||
execute: (instance) => chatController.removeProfilePicture(instance),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.OK).json(response);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
import { instanceNameSchema, chatwootSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { chatwootController } from '../whatsapp.module';
|
||||
import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { chatwootSchema, instanceNameSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
// import { ChatwootService } from '../services/chatwoot.service';
|
||||
import { chatwootController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('ChatwootRouter');
|
||||
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
createGroupSchema,
|
||||
getParticipantsSchema,
|
||||
groupInviteSchema,
|
||||
groupJidSchema,
|
||||
updateParticipantsSchema,
|
||||
updateSettingsSchema,
|
||||
groupSendInviteSchema,
|
||||
toggleEphemeralSchema,
|
||||
updateGroupDescriptionSchema,
|
||||
updateGroupPictureSchema,
|
||||
updateGroupSubjectSchema,
|
||||
updateGroupDescriptionSchema,
|
||||
groupInviteSchema,
|
||||
groupSendInviteSchema,
|
||||
getParticipantsSchema,
|
||||
updateParticipantsSchema,
|
||||
updateSettingsSchema,
|
||||
} from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import {
|
||||
CreateGroupDto,
|
||||
GetParticipant,
|
||||
GroupDescriptionDto,
|
||||
GroupInvite,
|
||||
GroupJid,
|
||||
GroupPictureDto,
|
||||
GroupSendInvite,
|
||||
GroupSubjectDto,
|
||||
GroupDescriptionDto,
|
||||
GroupToggleEphemeralDto,
|
||||
GroupUpdateParticipantDto,
|
||||
GroupUpdateSettingDto,
|
||||
GroupToggleEphemeralDto,
|
||||
GroupSendInvite,
|
||||
GetParticipant,
|
||||
} from '../dto/group.dto';
|
||||
import { groupController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('GroupRouter');
|
||||
|
||||
@@ -96,8 +97,7 @@ export class GroupRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: updateGroupDescriptionSchema,
|
||||
ClassRef: GroupDescriptionDto,
|
||||
execute: (instance, data) =>
|
||||
groupController.updateGroupDescription(instance, data),
|
||||
execute: (instance, data) => groupController.updateGroupDescription(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import { Router } from 'express';
|
||||
import fs from 'fs';
|
||||
|
||||
import { Auth, configService } from '../../config/env.config';
|
||||
import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard';
|
||||
import { authGuard } from '../guards/auth.guard';
|
||||
import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard';
|
||||
import { ChamaaiRouter } from './chamaai.router';
|
||||
import { ChatRouter } from './chat.router';
|
||||
import { ChatwootRouter } from './chatwoot.router';
|
||||
import { GroupRouter } from './group.router';
|
||||
import { InstanceRouter } from './instance.router';
|
||||
import { ProxyRouter } from './proxy.router';
|
||||
import { RabbitmqRouter } from './rabbitmq.router';
|
||||
import { MessageRouter } from './sendMessage.router';
|
||||
import { SettingsRouter } from './settings.router';
|
||||
import { TypebotRouter } from './typebot.router';
|
||||
import { ViewsRouter } from './view.router';
|
||||
import { WebhookRouter } from './webhook.router';
|
||||
import { ChatwootRouter } from './chatwoot.router';
|
||||
import fs from 'fs';
|
||||
import { WebsocketRouter } from './websocket.router';
|
||||
|
||||
enum HttpStatus {
|
||||
OK = 200,
|
||||
@@ -35,15 +42,18 @@ router
|
||||
version: packageJson.version,
|
||||
});
|
||||
})
|
||||
.use(
|
||||
'/instance',
|
||||
new InstanceRouter(configService, ...guards).router,
|
||||
new ViewsRouter(instanceExistsGuard).router,
|
||||
)
|
||||
.use('/instance', new InstanceRouter(configService, ...guards).router)
|
||||
.use('/manager', new ViewsRouter().router)
|
||||
.use('/message', new MessageRouter(...guards).router)
|
||||
.use('/chat', new ChatRouter(...guards).router)
|
||||
.use('/group', new GroupRouter(...guards).router)
|
||||
.use('/webhook', new WebhookRouter(...guards).router)
|
||||
.use('/chatwoot', new ChatwootRouter(...guards).router);
|
||||
.use('/chatwoot', new ChatwootRouter(...guards).router)
|
||||
.use('/settings', new SettingsRouter(...guards).router)
|
||||
.use('/websocket', new WebsocketRouter(...guards).router)
|
||||
.use('/rabbitmq', new RabbitmqRouter(...guards).router)
|
||||
.use('/typebot', new TypebotRouter(...guards).router)
|
||||
.use('/proxy', new ProxyRouter(...guards).router)
|
||||
.use('/chamaai', new ChamaaiRouter(...guards).router);
|
||||
|
||||
export { router, HttpStatus };
|
||||
export { HttpStatus, router };
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
import { instanceNameSchema, oldTokenSchema } from '../../validate/validate.schema';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { instanceController } from '../whatsapp.module';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { HttpStatus } from './index.router';
|
||||
import { OldToken } from '../services/auth.service';
|
||||
|
||||
import { Auth, ConfigService, Database } from '../../config/env.config';
|
||||
import { dbserver } from '../../db/db.connect';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { dbserver } from '../../libs/db.connect';
|
||||
import { instanceNameSchema, oldTokenSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { OldToken } from '../services/auth.service';
|
||||
import { instanceController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('InstanceRouter');
|
||||
|
||||
@@ -162,17 +163,13 @@ export class InstanceRouter extends RouterBroker {
|
||||
await dbserver.dropDatabase();
|
||||
return res
|
||||
.status(HttpStatus.CREATED)
|
||||
.json({ error: false, message: 'Database deleted' });
|
||||
.json({ status: 'SUCCESS', error: false, response: { message: 'database deleted' } });
|
||||
} catch (error) {
|
||||
return res
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.json({ error: true, message: error.message });
|
||||
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.json({ error: true, message: 'Database is not enabled' });
|
||||
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: 'Database is not enabled' });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
52
src/whatsapp/routers/proxy.router.ts
Normal file
52
src/whatsapp/routers/proxy.router.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, proxySchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ProxyDto } from '../dto/proxy.dto';
|
||||
import { proxyController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('ProxyRouter');
|
||||
|
||||
export class ProxyRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setProxy');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<ProxyDto>({
|
||||
request: req,
|
||||
schema: proxySchema,
|
||||
ClassRef: ProxyDto,
|
||||
execute: (instance, data) => proxyController.createProxy(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findProxy');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => proxyController.findProxy(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
52
src/whatsapp/routers/rabbitmq.router.ts
Normal file
52
src/whatsapp/routers/rabbitmq.router.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, rabbitmqSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RabbitmqDto } from '../dto/rabbitmq.dto';
|
||||
import { rabbitmqController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('RabbitmqRouter');
|
||||
|
||||
export class RabbitmqRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setRabbitmq');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<RabbitmqDto>({
|
||||
request: req,
|
||||
schema: rabbitmqSchema,
|
||||
ClassRef: RabbitmqDto,
|
||||
execute: (instance, data) => rabbitmqController.createRabbitmq(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findRabbitmq');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => rabbitmqController.findRabbitmq(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
audioMessageSchema,
|
||||
buttonMessageSchema,
|
||||
@@ -12,6 +14,7 @@ import {
|
||||
stickerMessageSchema,
|
||||
textMessageSchema,
|
||||
} from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import {
|
||||
SendAudioDto,
|
||||
SendButtonDto,
|
||||
@@ -26,9 +29,7 @@ import {
|
||||
SendTextDto,
|
||||
} from '../dto/sendMessage.dto';
|
||||
import { sendMessageController } from '../whatsapp.module';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { HttpStatus } from './index.router';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('MessageRouter');
|
||||
|
||||
@@ -79,8 +80,7 @@ export class MessageRouter extends RouterBroker {
|
||||
request: req,
|
||||
schema: audioMessageSchema,
|
||||
ClassRef: SendMediaDto,
|
||||
execute: (instance, data) =>
|
||||
sendMessageController.sendWhatsAppAudio(instance, data),
|
||||
execute: (instance, data) => sendMessageController.sendWhatsAppAudio(instance, data),
|
||||
});
|
||||
|
||||
return res.status(HttpStatus.CREATED).json(response);
|
||||
|
||||
53
src/whatsapp/routers/settings.router.ts
Normal file
53
src/whatsapp/routers/settings.router.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, settingsSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { SettingsDto } from '../dto/settings.dto';
|
||||
// import { SettingsService } from '../services/settings.service';
|
||||
import { settingsController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('SettingsRouter');
|
||||
|
||||
export class SettingsRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setSettings');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<SettingsDto>({
|
||||
request: req,
|
||||
schema: settingsSchema,
|
||||
ClassRef: SettingsDto,
|
||||
execute: (instance, data) => settingsController.createSettings(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findSettings');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => settingsController.findSettings(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
89
src/whatsapp/routers/typebot.router.ts
Normal file
89
src/whatsapp/routers/typebot.router.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
instanceNameSchema,
|
||||
typebotSchema,
|
||||
typebotStartSchema,
|
||||
typebotStatusSchema,
|
||||
} from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { TypebotDto } from '../dto/typebot.dto';
|
||||
import { typebotController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('TypebotRouter');
|
||||
|
||||
export class TypebotRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setTypebot');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<TypebotDto>({
|
||||
request: req,
|
||||
schema: typebotSchema,
|
||||
ClassRef: TypebotDto,
|
||||
execute: (instance, data) => typebotController.createTypebot(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findTypebot');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => typebotController.findTypebot(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.post(this.routerPath('changeStatus'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in changeStatusTypebot');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: typebotStatusSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance, data) => typebotController.changeStatus(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.post(this.routerPath('start'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in startTypebot');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: typebotStartSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance, data) => typebotController.startTypebot(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
import { Router } from 'express';
|
||||
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { viewsController } from '../whatsapp.module';
|
||||
|
||||
export class ViewsRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.router.get(this.routerPath('qrcode'), ...guards, (req, res) => {
|
||||
return viewsController.qrcode(req, res);
|
||||
this.router.get('/', (req, res) => {
|
||||
return viewsController.manager(req, res);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, webhookSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebhookDto } from '../dto/webhook.dto';
|
||||
import { webhookController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
const logger = new Logger('WebhookRouter');
|
||||
|
||||
|
||||
52
src/whatsapp/routers/websocket.router.ts
Normal file
52
src/whatsapp/routers/websocket.router.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { instanceNameSchema, websocketSchema } from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebsocketDto } from '../dto/websocket.dto';
|
||||
import { websocketController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
|
||||
const logger = new Logger('WebsocketRouter');
|
||||
|
||||
export class WebsocketRouter extends RouterBroker {
|
||||
constructor(...guards: RequestHandler[]) {
|
||||
super();
|
||||
this.router
|
||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in setWebsocket');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<WebsocketDto>({
|
||||
request: req,
|
||||
schema: websocketSchema,
|
||||
ClassRef: WebsocketDto,
|
||||
execute: (instance, data) => websocketController.createWebsocket(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.CREATED).json(response);
|
||||
})
|
||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||
logger.verbose('request received in findWebsocket');
|
||||
logger.verbose('request body: ');
|
||||
logger.verbose(req.body);
|
||||
|
||||
logger.verbose('request query: ');
|
||||
logger.verbose(req.query);
|
||||
const response = await this.dataValidate<InstanceDto>({
|
||||
request: req,
|
||||
schema: instanceNameSchema,
|
||||
ClassRef: InstanceDto,
|
||||
execute: (instance) => websocketController.findWebsocket(instance),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
});
|
||||
}
|
||||
|
||||
public readonly router = Router();
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Auth, ConfigService, Webhook } from '../../config/env.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { name as apiName } from '../../../package.json';
|
||||
import { verify, sign } from 'jsonwebtoken';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { v4 } from 'uuid';
|
||||
import { isJWT } from 'class-validator';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import axios from 'axios';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
import { isJWT } from 'class-validator';
|
||||
import { sign, verify } from 'jsonwebtoken';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { name as apiName } from '../../../package.json';
|
||||
import { Auth, ConfigService, Webhook } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { BadRequestException } from '../../exceptions';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export type JwtPayload = {
|
||||
instanceName: string;
|
||||
@@ -63,9 +64,7 @@ export class AuthService {
|
||||
private async apikey(instance: InstanceDto, token?: string) {
|
||||
const apikey = token ? token : v4().toUpperCase();
|
||||
|
||||
this.logger.verbose(
|
||||
token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey,
|
||||
);
|
||||
this.logger.verbose(token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey);
|
||||
|
||||
const auth = await this.repository.auth.create({ apikey }, instance.instanceName);
|
||||
|
||||
@@ -101,13 +100,9 @@ export class AuthService {
|
||||
public async generateHash(instance: InstanceDto, token?: string) {
|
||||
const options = this.configService.get<Auth>('AUTHENTICATION');
|
||||
|
||||
this.logger.verbose(
|
||||
'generating hash ' + options.TYPE + ' to instance: ' + instance.instanceName,
|
||||
);
|
||||
this.logger.verbose('generating hash ' + options.TYPE + ' to instance: ' + instance.instanceName);
|
||||
|
||||
return (await this[options.TYPE](instance, token)) as
|
||||
| { jwt: string }
|
||||
| { apikey: string };
|
||||
return (await this[options.TYPE](instance, token)) as { jwt: string } | { apikey: string };
|
||||
}
|
||||
|
||||
public async refreshToken({ oldToken }: OldToken) {
|
||||
@@ -150,10 +145,7 @@ export class AuthService {
|
||||
try {
|
||||
this.logger.verbose('checking webhook');
|
||||
const webhook = await this.repository.webhook.find(decode.instanceName);
|
||||
if (
|
||||
webhook?.enabled &&
|
||||
this.configService.get<Webhook>('WEBHOOK').EVENTS.NEW_JWT_TOKEN
|
||||
) {
|
||||
if (webhook?.enabled && this.configService.get<Webhook>('WEBHOOK').EVENTS.NEW_JWT_TOKEN) {
|
||||
this.logger.verbose('sending webhook');
|
||||
|
||||
const httpService = axios.create({ baseURL: webhook.url });
|
||||
|
||||
230
src/whatsapp/services/chamaai.service.ts
Normal file
230
src/whatsapp/services/chamaai.service.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
import axios from 'axios';
|
||||
import { writeFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { ChamaaiDto } from '../dto/chamaai.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ChamaaiRaw } from '../models';
|
||||
import { Events } from '../types/wa.types';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class ChamaaiService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {}
|
||||
|
||||
private readonly logger = new Logger(ChamaaiService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: ChamaaiDto) {
|
||||
this.logger.verbose('create chamaai: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setChamaai(data);
|
||||
|
||||
return { chamaai: { ...instance, chamaai: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<ChamaaiRaw> {
|
||||
try {
|
||||
this.logger.verbose('find chamaai: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findChamaai();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Chamaai not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { enabled: false, url: '', token: '', waNumber: '', answerByAudio: false };
|
||||
}
|
||||
}
|
||||
|
||||
private getTypeMessage(msg: any) {
|
||||
this.logger.verbose('get type message');
|
||||
|
||||
const types = {
|
||||
conversation: msg.conversation,
|
||||
extendedTextMessage: msg.extendedTextMessage?.text,
|
||||
};
|
||||
|
||||
this.logger.verbose('type message: ' + types);
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
private getMessageContent(types: any) {
|
||||
this.logger.verbose('get message content');
|
||||
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||
|
||||
const result = typeKey ? types[typeKey] : undefined;
|
||||
|
||||
this.logger.verbose('message content: ' + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private getConversationMessage(msg: any) {
|
||||
this.logger.verbose('get conversation message');
|
||||
|
||||
const types = this.getTypeMessage(msg);
|
||||
|
||||
const messageContent = this.getMessageContent(types);
|
||||
|
||||
this.logger.verbose('conversation message: ' + messageContent);
|
||||
|
||||
return messageContent;
|
||||
}
|
||||
|
||||
private calculateTypingTime(text: string) {
|
||||
const wordsPerMinute = 100;
|
||||
|
||||
const wordCount = text.split(' ').length;
|
||||
const typingTimeInMinutes = wordCount / wordsPerMinute;
|
||||
const typingTimeInMilliseconds = typingTimeInMinutes * 60;
|
||||
return typingTimeInMilliseconds;
|
||||
}
|
||||
|
||||
private convertToMilliseconds(count: number) {
|
||||
const averageCharactersPerSecond = 15;
|
||||
const characterCount = count;
|
||||
const speakingTimeInSeconds = characterCount / averageCharactersPerSecond;
|
||||
return speakingTimeInSeconds;
|
||||
}
|
||||
|
||||
private getRegexPatterns() {
|
||||
const patternsToCheck = [
|
||||
'.*atend.*humano.*',
|
||||
'.*falar.*com.*um.*humano.*',
|
||||
'.*fala.*humano.*',
|
||||
'.*atend.*humano.*',
|
||||
'.*fala.*atend.*',
|
||||
'.*preciso.*ajuda.*',
|
||||
'.*quero.*suporte.*',
|
||||
'.*preciso.*assiste.*',
|
||||
'.*ajuda.*atend.*',
|
||||
'.*chama.*atendente.*',
|
||||
'.*suporte.*urgente.*',
|
||||
'.*atend.*por.*favor.*',
|
||||
'.*quero.*falar.*com.*alguém.*',
|
||||
'.*falar.*com.*um.*humano.*',
|
||||
'.*transfer.*humano.*',
|
||||
'.*transfer.*atend.*',
|
||||
'.*equipe.*humano.*',
|
||||
'.*suporte.*humano.*',
|
||||
];
|
||||
|
||||
const regexPatterns = patternsToCheck.map((pattern) => new RegExp(pattern, 'iu'));
|
||||
return regexPatterns;
|
||||
}
|
||||
|
||||
public async sendChamaai(instance: InstanceDto, remoteJid: string, msg: any) {
|
||||
const content = this.getConversationMessage(msg.message);
|
||||
const msgType = msg.messageType;
|
||||
const find = await this.find(instance);
|
||||
const url = find.url;
|
||||
const token = find.token;
|
||||
const waNumber = find.waNumber;
|
||||
const answerByAudio = find.answerByAudio;
|
||||
|
||||
if (!content && msgType !== 'audioMessage') {
|
||||
return;
|
||||
}
|
||||
|
||||
let data;
|
||||
let endpoint;
|
||||
|
||||
if (msgType === 'audioMessage') {
|
||||
const downloadBase64 = await this.waMonitor.waInstances[instance.instanceName].getBase64FromMediaMessage({
|
||||
message: {
|
||||
...msg,
|
||||
},
|
||||
});
|
||||
|
||||
const random = Math.random().toString(36).substring(7);
|
||||
const nameFile = `${random}.ogg`;
|
||||
|
||||
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
||||
|
||||
const fileName = `${path.join(
|
||||
this.waMonitor.waInstances[instance.instanceName].storePath,
|
||||
'temp',
|
||||
`${nameFile}`,
|
||||
)}`;
|
||||
|
||||
writeFileSync(fileName, fileData, 'utf8');
|
||||
|
||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||
|
||||
const url = `${urlServer}/store/temp/${nameFile}`;
|
||||
|
||||
data = {
|
||||
waNumber: waNumber,
|
||||
audioUrl: url,
|
||||
queryNumber: remoteJid.split('@')[0],
|
||||
answerByAudio: answerByAudio,
|
||||
};
|
||||
endpoint = 'processMessageAudio';
|
||||
} else {
|
||||
data = {
|
||||
waNumber: waNumber,
|
||||
question: content,
|
||||
queryNumber: remoteJid.split('@')[0],
|
||||
answerByAudio: answerByAudio,
|
||||
};
|
||||
endpoint = 'processMessageText';
|
||||
}
|
||||
|
||||
const request = await axios.post(`${url}/${endpoint}`, data, {
|
||||
headers: {
|
||||
Authorization: `${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const answer = request.data?.answer;
|
||||
|
||||
const type = request.data?.type;
|
||||
|
||||
const characterCount = request.data?.characterCount;
|
||||
|
||||
if (answer) {
|
||||
if (type === 'text') {
|
||||
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: this.calculateTypingTime(answer) * 1000 || 1000,
|
||||
presence: 'composing',
|
||||
linkPreview: false,
|
||||
quoted: {
|
||||
key: msg.key,
|
||||
message: msg.message,
|
||||
},
|
||||
},
|
||||
textMessage: {
|
||||
text: answer,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (type === 'audio') {
|
||||
this.waMonitor.waInstances[instance.instanceName].audioWhatsapp({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: characterCount ? this.convertToMilliseconds(characterCount) * 1000 || 1000 : 1000,
|
||||
presence: 'recording',
|
||||
encoding: true,
|
||||
},
|
||||
audioMessage: {
|
||||
audio: answer,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (this.getRegexPatterns().some((pattern) => pattern.test(answer))) {
|
||||
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.CHAMA_AI_ACTION, {
|
||||
remoteJid: remoteJid,
|
||||
message: msg,
|
||||
answer: answer,
|
||||
action: 'transfer',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import path from 'path';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||
import { createReadStream, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
import { SendTextDto } from '../dto/sendMessage.dto';
|
||||
import { createReadStream, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
||||
import mimeTypes from 'mime-types';
|
||||
import { SendAudioDto } from '../dto/sendMessage.dto';
|
||||
import { SendMediaDto } from '../dto/sendMessage.dto';
|
||||
import path from 'path';
|
||||
|
||||
import { ConfigService } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { ROOT_DIR } from '../../config/path.config';
|
||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class ChatwootService {
|
||||
private messageCacheFile: string;
|
||||
@@ -22,10 +21,7 @@ export class ChatwootService {
|
||||
|
||||
private provider: any;
|
||||
|
||||
constructor(
|
||||
private readonly waMonitor: WAMonitoringService,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {
|
||||
this.messageCache = new Set();
|
||||
}
|
||||
|
||||
@@ -56,9 +52,7 @@ export class ChatwootService {
|
||||
private async getProvider(instance: InstanceDto) {
|
||||
this.logger.verbose('get provider to instance: ' + instance.instanceName);
|
||||
try {
|
||||
const provider = await this.waMonitor.waInstances[
|
||||
instance.instanceName
|
||||
].findChatwoot();
|
||||
const provider = await this.waMonitor.waInstances[instance.instanceName].findChatwoot();
|
||||
|
||||
if (!provider) {
|
||||
this.logger.warn('provider not found');
|
||||
@@ -154,6 +148,7 @@ export class ChatwootService {
|
||||
inboxName: string,
|
||||
webhookUrl: string,
|
||||
qrcode: boolean,
|
||||
number: string,
|
||||
) {
|
||||
this.logger.verbose('init instance chatwoot: ' + instance.instanceName);
|
||||
|
||||
@@ -170,9 +165,7 @@ export class ChatwootService {
|
||||
});
|
||||
|
||||
this.logger.verbose('check duplicate inbox');
|
||||
const checkDuplicate = findInbox.payload
|
||||
.map((inbox) => inbox.name)
|
||||
.includes(inboxName);
|
||||
const checkDuplicate = findInbox.payload.map((inbox) => inbox.name).includes(inboxName);
|
||||
|
||||
let inboxId: number;
|
||||
|
||||
@@ -218,6 +211,7 @@ export class ChatwootService {
|
||||
inboxId,
|
||||
false,
|
||||
'EvolutionAPI',
|
||||
'https://evolution-api.com/files/evolution-api-favicon.png',
|
||||
)) as any);
|
||||
|
||||
if (!contact) {
|
||||
@@ -229,12 +223,18 @@ export class ChatwootService {
|
||||
|
||||
if (qrcode) {
|
||||
this.logger.verbose('create conversation in chatwoot');
|
||||
const data = {
|
||||
contact_id: contactId.toString(),
|
||||
inbox_id: inboxId.toString(),
|
||||
};
|
||||
|
||||
if (this.provider.conversation_pending) {
|
||||
data['status'] = 'pending';
|
||||
}
|
||||
|
||||
const conversation = await client.conversations.create({
|
||||
accountId: this.provider.account_id,
|
||||
data: {
|
||||
contact_id: contactId.toString(),
|
||||
inbox_id: inboxId.toString(),
|
||||
},
|
||||
data,
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
@@ -243,11 +243,18 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
this.logger.verbose('create message for init instance in chatwoot');
|
||||
|
||||
let contentMsg = 'init';
|
||||
|
||||
if (number) {
|
||||
contentMsg = `init:${number}`;
|
||||
}
|
||||
|
||||
const message = await client.messages.create({
|
||||
accountId: this.provider.account_id,
|
||||
conversationId: conversation.id,
|
||||
data: {
|
||||
content: '/init',
|
||||
content: contentMsg,
|
||||
message_type: 'outgoing',
|
||||
},
|
||||
});
|
||||
@@ -269,6 +276,7 @@ export class ChatwootService {
|
||||
isGroup: boolean,
|
||||
name?: string,
|
||||
avatar_url?: string,
|
||||
jid?: string,
|
||||
) {
|
||||
this.logger.verbose('create contact to instance: ' + instance.instanceName);
|
||||
|
||||
@@ -286,6 +294,7 @@ export class ChatwootService {
|
||||
inbox_id: inboxId,
|
||||
name: name || phoneNumber,
|
||||
phone_number: `+${phoneNumber}`,
|
||||
identifier: jid,
|
||||
avatar_url: avatar_url,
|
||||
};
|
||||
} else {
|
||||
@@ -410,28 +419,25 @@ export class ChatwootService {
|
||||
|
||||
if (isGroup) {
|
||||
this.logger.verbose('get group name');
|
||||
const group = await this.waMonitor.waInstances[
|
||||
instance.instanceName
|
||||
].client.groupMetadata(chatId);
|
||||
const group = await this.waMonitor.waInstances[instance.instanceName].client.groupMetadata(chatId);
|
||||
|
||||
nameContact = `${group.subject} (GROUP)`;
|
||||
|
||||
this.logger.verbose('find or create participant in chatwoot');
|
||||
|
||||
const picture_url = await this.waMonitor.waInstances[
|
||||
instance.instanceName
|
||||
].profilePicture(body.key.participant.split('@')[0]);
|
||||
|
||||
const findParticipant = await this.findContact(
|
||||
instance,
|
||||
const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture(
|
||||
body.key.participant.split('@')[0],
|
||||
);
|
||||
|
||||
const findParticipant = await this.findContact(instance, body.key.participant.split('@')[0]);
|
||||
|
||||
if (findParticipant) {
|
||||
await this.updateContact(instance, findParticipant.id, {
|
||||
name: body.pushName,
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
if (!findParticipant.name || findParticipant.name === chatId) {
|
||||
await this.updateContact(instance, findParticipant.id, {
|
||||
name: body.pushName,
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await this.createContact(
|
||||
instance,
|
||||
@@ -440,28 +446,25 @@ export class ChatwootService {
|
||||
false,
|
||||
body.pushName,
|
||||
picture_url.profilePictureUrl || null,
|
||||
body.key.participant,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.verbose('find or create contact in chatwoot');
|
||||
|
||||
const picture_url = await this.waMonitor.waInstances[
|
||||
instance.instanceName
|
||||
].profilePicture(chatId);
|
||||
const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture(chatId);
|
||||
|
||||
const findContact = await this.findContact(instance, chatId);
|
||||
|
||||
let contact: any;
|
||||
if (body.key.fromMe) {
|
||||
contact = findContact;
|
||||
} else {
|
||||
if (findContact) {
|
||||
contact = await this.updateContact(instance, findContact.id, {
|
||||
name: nameContact,
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
} else {
|
||||
const jid = isGroup ? null : body.key.remoteJid;
|
||||
contact = await this.createContact(
|
||||
instance,
|
||||
chatId,
|
||||
@@ -469,6 +472,31 @@ export class ChatwootService {
|
||||
isGroup,
|
||||
nameContact,
|
||||
picture_url.profilePictureUrl || null,
|
||||
jid,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (findContact) {
|
||||
if (!findContact.name || findContact.name === chatId) {
|
||||
contact = await this.updateContact(instance, findContact.id, {
|
||||
name: nameContact,
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
} else {
|
||||
contact = await this.updateContact(instance, findContact.id, {
|
||||
avatar_url: picture_url.profilePictureUrl || null,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const jid = isGroup ? null : body.key.remoteJid;
|
||||
contact = await this.createContact(
|
||||
instance,
|
||||
chatId,
|
||||
filterInbox.id,
|
||||
isGroup,
|
||||
nameContact,
|
||||
picture_url.profilePictureUrl || null,
|
||||
jid,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -478,8 +506,7 @@ export class ChatwootService {
|
||||
return null;
|
||||
}
|
||||
|
||||
const contactId =
|
||||
contact?.payload?.id || contact?.payload?.contact?.id || contact?.id;
|
||||
const contactId = contact?.payload?.id || contact?.payload?.contact?.id || contact?.id;
|
||||
|
||||
if (!body.key.fromMe && contact.name === chatId && nameContact !== chatId) {
|
||||
this.logger.verbose('update contact name in chatwoot');
|
||||
@@ -495,11 +522,26 @@ export class ChatwootService {
|
||||
})) as any;
|
||||
|
||||
if (contactConversations) {
|
||||
let conversation: any;
|
||||
if (this.provider.reopen_conversation) {
|
||||
conversation = contactConversations.payload.find((conversation) => conversation.inbox_id == filterInbox.id);
|
||||
|
||||
if (this.provider.conversation_pending) {
|
||||
await client.conversations.toggleStatus({
|
||||
accountId: this.provider.account_id,
|
||||
conversationId: conversation.id,
|
||||
data: {
|
||||
status: 'pending',
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
conversation = contactConversations.payload.find(
|
||||
(conversation) => conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id,
|
||||
);
|
||||
}
|
||||
this.logger.verbose('return conversation if exists');
|
||||
const conversation = contactConversations.payload.find(
|
||||
(conversation) =>
|
||||
conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id,
|
||||
);
|
||||
|
||||
if (conversation) {
|
||||
this.logger.verbose('conversation found');
|
||||
return conversation.id;
|
||||
@@ -507,12 +549,18 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
this.logger.verbose('create conversation in chatwoot');
|
||||
const data = {
|
||||
contact_id: contactId.toString(),
|
||||
inbox_id: filterInbox.id.toString(),
|
||||
};
|
||||
|
||||
if (this.provider.conversation_pending) {
|
||||
data['status'] = 'pending';
|
||||
}
|
||||
|
||||
const conversation = await client.conversations.create({
|
||||
accountId: this.provider.account_id,
|
||||
data: {
|
||||
contact_id: `${contactId}`,
|
||||
inbox_id: `${filterInbox.id}`,
|
||||
},
|
||||
data,
|
||||
});
|
||||
|
||||
if (!conversation) {
|
||||
@@ -548,9 +596,7 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
this.logger.verbose('find inbox by name');
|
||||
const findByName = inbox.payload.find(
|
||||
(inbox) => inbox.name === instance.instanceName,
|
||||
);
|
||||
const findByName = inbox.payload.find((inbox) => inbox.name === instance.instanceName.split('-cwId-')[0]);
|
||||
|
||||
if (!findByName) {
|
||||
this.logger.warn('inbox not found');
|
||||
@@ -652,8 +698,7 @@ export class ChatwootService {
|
||||
|
||||
this.logger.verbose('find conversation by contact id');
|
||||
const conversation = findConversation.data.payload.find(
|
||||
(conversation) =>
|
||||
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
);
|
||||
|
||||
if (!conversation) {
|
||||
@@ -773,8 +818,7 @@ export class ChatwootService {
|
||||
|
||||
this.logger.verbose('find conversation by contact id');
|
||||
const conversation = findConversation.data.payload.find(
|
||||
(conversation) =>
|
||||
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
);
|
||||
|
||||
if (!conversation) {
|
||||
@@ -824,12 +868,7 @@ export class ChatwootService {
|
||||
}
|
||||
}
|
||||
|
||||
public async sendAttachment(
|
||||
waInstance: any,
|
||||
number: string,
|
||||
media: any,
|
||||
caption?: string,
|
||||
) {
|
||||
public async sendAttachment(waInstance: any, number: string, media: any, caption?: string) {
|
||||
this.logger.verbose('send attachment to instance: ' + waInstance.instanceName);
|
||||
|
||||
try {
|
||||
@@ -910,9 +949,10 @@ export class ChatwootService {
|
||||
|
||||
public async receiveWebhook(instance: InstanceDto, body: any) {
|
||||
try {
|
||||
this.logger.verbose(
|
||||
'receive webhook to chatwoot instance: ' + instance.instanceName,
|
||||
);
|
||||
// espera 500ms para evitar duplicidade de mensagens
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
||||
this.logger.verbose('receive webhook to chatwoot instance: ' + instance.instanceName);
|
||||
const client = await this.clientCw(instance);
|
||||
|
||||
if (!client) {
|
||||
@@ -921,12 +961,11 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
this.logger.verbose('check if is bot');
|
||||
if (!body?.conversation || body.private) return { message: 'bot' };
|
||||
if (!body?.conversation || body.private || body.event === 'message_updated') return { message: 'bot' };
|
||||
|
||||
this.logger.verbose('check if is group');
|
||||
const chatId =
|
||||
body.conversation.meta.sender?.phone_number?.replace('+', '') ||
|
||||
body.conversation.meta.sender?.identifier;
|
||||
body.conversation.meta.sender?.phone_number?.replace('+', '') || body.conversation.meta.sender?.identifier;
|
||||
const messageReceived = body.content;
|
||||
const senderName = body?.sender?.name;
|
||||
const waInstance = this.waMonitor.waInstances[instance.instanceName];
|
||||
@@ -936,20 +975,17 @@ export class ChatwootService {
|
||||
|
||||
const command = messageReceived.replace('/', '');
|
||||
|
||||
if (command === 'init' || command === 'iniciar') {
|
||||
if (command.includes('init') || command.includes('iniciar')) {
|
||||
this.logger.verbose('command init found');
|
||||
const state = waInstance?.connectionStatus?.state;
|
||||
|
||||
if (state !== 'open') {
|
||||
this.logger.verbose('connect to whatsapp');
|
||||
await waInstance.connectToWhatsapp();
|
||||
const number = command.split(':')[1];
|
||||
await waInstance.connectToWhatsapp(number);
|
||||
} else {
|
||||
this.logger.verbose('whatsapp already connected');
|
||||
await this.createBotMessage(
|
||||
instance,
|
||||
`🚨 ${body.inbox.name} instance is connected.`,
|
||||
'incoming',
|
||||
);
|
||||
await this.createBotMessage(instance, `🚨 ${body.inbox.name} instance is connected.`, 'incoming');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,20 +996,12 @@ export class ChatwootService {
|
||||
|
||||
if (!state) {
|
||||
this.logger.verbose('state not found');
|
||||
await this.createBotMessage(
|
||||
instance,
|
||||
`⚠️ ${body.inbox.name} instance not found.`,
|
||||
'incoming',
|
||||
);
|
||||
await this.createBotMessage(instance, `⚠️ ${body.inbox.name} instance not found.`, 'incoming');
|
||||
}
|
||||
|
||||
if (state) {
|
||||
this.logger.verbose('state: ' + state + ' found');
|
||||
await this.createBotMessage(
|
||||
instance,
|
||||
`⚠️ ${body.inbox.name} instance status: *${state}*`,
|
||||
'incoming',
|
||||
);
|
||||
await this.createBotMessage(instance, `⚠️ ${body.inbox.name} instance status: *${state}*`, 'incoming');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,48 +1017,12 @@ export class ChatwootService {
|
||||
await waInstance?.client?.logout('Log out instance: ' + instance.instanceName);
|
||||
await waInstance?.client?.ws?.close();
|
||||
}
|
||||
|
||||
if (command.includes('#inbox_whatsapp')) {
|
||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||
const apiKey = this.configService.get('AUTHENTICATION').API_KEY.KEY;
|
||||
|
||||
const data = {
|
||||
instanceName: command.split(':')[1],
|
||||
qrcode: true,
|
||||
chatwoot_account_id: this.provider.account_id,
|
||||
chatwoot_token: this.provider.token,
|
||||
chatwoot_url: this.provider.url,
|
||||
chatwoot_sign_msg: this.provider.sign_msg,
|
||||
};
|
||||
|
||||
const config = {
|
||||
method: 'post',
|
||||
maxBodyLength: Infinity,
|
||||
url: `${urlServer}/instance/create`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
apikey: apiKey,
|
||||
},
|
||||
data: data,
|
||||
};
|
||||
|
||||
await axios.request(config);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
body.message_type === 'outgoing' &&
|
||||
body?.conversation?.messages?.length &&
|
||||
chatId !== '123456'
|
||||
) {
|
||||
if (body.message_type === 'outgoing' && body?.conversation?.messages?.length && chatId !== '123456') {
|
||||
this.logger.verbose('check if is group');
|
||||
|
||||
this.messageCacheFile = path.join(
|
||||
ROOT_DIR,
|
||||
'store',
|
||||
'chatwoot',
|
||||
`${instance.instanceName}_cache.txt`,
|
||||
);
|
||||
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||
this.logger.verbose('cache file path: ' + this.messageCacheFile);
|
||||
|
||||
this.messageCache = this.loadMessageCache();
|
||||
@@ -1051,9 +1043,7 @@ export class ChatwootService {
|
||||
if (senderName === null || senderName === undefined) {
|
||||
formatText = messageReceived;
|
||||
} else {
|
||||
formatText = this.provider.sign_msg
|
||||
? `*${senderName}:*\n\n${messageReceived}`
|
||||
: messageReceived;
|
||||
formatText = this.provider.sign_msg ? `*${senderName}:*\n${messageReceived}` : messageReceived;
|
||||
}
|
||||
|
||||
for (const message of body.conversation.messages) {
|
||||
@@ -1067,12 +1057,7 @@ export class ChatwootService {
|
||||
formatText = null;
|
||||
}
|
||||
|
||||
await this.sendAttachment(
|
||||
waInstance,
|
||||
chatId,
|
||||
attachment.data_url,
|
||||
formatText,
|
||||
);
|
||||
await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
|
||||
}
|
||||
} else {
|
||||
this.logger.verbose('message is text');
|
||||
@@ -1094,17 +1079,13 @@ export class ChatwootService {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
body.message_type === 'template' &&
|
||||
body.content_type === 'input_csat' &&
|
||||
body.event === 'message_created'
|
||||
) {
|
||||
this.logger.verbose('check if is csat');
|
||||
if (body.message_type === 'template' && body.event === 'message_created') {
|
||||
this.logger.verbose('check if is template');
|
||||
|
||||
const data: SendTextDto = {
|
||||
number: chatId,
|
||||
textMessage: {
|
||||
text: body.content,
|
||||
text: body.content.replace(/\\\r\n|\\\n|\n/g, '\n'),
|
||||
},
|
||||
options: {
|
||||
delay: 1200,
|
||||
@@ -1153,13 +1134,14 @@ export class ChatwootService {
|
||||
videoMessage: msg.videoMessage?.caption,
|
||||
extendedTextMessage: msg.extendedTextMessage?.text,
|
||||
messageContextInfo: msg.messageContextInfo?.stanzaId,
|
||||
stickerMessage: msg.stickerMessage?.fileSha256.toString('base64'),
|
||||
stickerMessage: undefined,
|
||||
documentMessage: msg.documentMessage?.caption,
|
||||
documentWithCaptionMessage:
|
||||
msg.documentWithCaptionMessage?.message?.documentMessage?.caption,
|
||||
documentWithCaptionMessage: msg.documentWithCaptionMessage?.message?.documentMessage?.caption,
|
||||
audioMessage: msg.audioMessage?.caption,
|
||||
contactMessage: msg.contactMessage?.vcard,
|
||||
contactsArrayMessage: msg.contactsArrayMessage,
|
||||
locationMessage: msg.locationMessage,
|
||||
liveLocationMessage: msg.liveLocationMessage,
|
||||
};
|
||||
|
||||
this.logger.verbose('type message: ' + types);
|
||||
@@ -1173,6 +1155,21 @@ export class ChatwootService {
|
||||
|
||||
const result = typeKey ? types[typeKey] : undefined;
|
||||
|
||||
if (typeKey === 'locationMessage' || typeKey === 'liveLocationMessage') {
|
||||
const latitude = result.degreesLatitude;
|
||||
const longitude = result.degreesLongitude;
|
||||
|
||||
const formattedLocation = `**Location:**
|
||||
**latitude:** ${latitude}
|
||||
**longitude:** ${longitude}
|
||||
https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}
|
||||
`;
|
||||
|
||||
this.logger.verbose('message content: ' + formattedLocation);
|
||||
|
||||
return formattedLocation;
|
||||
}
|
||||
|
||||
if (typeKey === 'contactMessage') {
|
||||
const vCardData = result.split('\n');
|
||||
const contactInfo = {};
|
||||
@@ -1276,6 +1273,16 @@ export class ChatwootService {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.verbose('get conversation message');
|
||||
const bodyMessage = await this.getConversationMessage(body.message);
|
||||
|
||||
const isMedia = this.isMediaMessage(body.message);
|
||||
|
||||
if (!bodyMessage && !isMedia) {
|
||||
this.logger.warn('no body message found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.verbose('get conversation in chatwoot');
|
||||
const getConversion = await this.createConversation(instance, body);
|
||||
|
||||
@@ -1288,18 +1295,8 @@ export class ChatwootService {
|
||||
|
||||
this.logger.verbose('message type: ' + messageType);
|
||||
|
||||
const isMedia = this.isMediaMessage(body.message);
|
||||
|
||||
this.logger.verbose('is media: ' + isMedia);
|
||||
|
||||
this.logger.verbose('get conversation message');
|
||||
const bodyMessage = await this.getConversationMessage(body.message);
|
||||
|
||||
if (!bodyMessage && !isMedia) {
|
||||
this.logger.warn('no body message found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.verbose('check if is media');
|
||||
if (isMedia) {
|
||||
this.logger.verbose('message is media');
|
||||
@@ -1333,31 +1330,21 @@ export class ChatwootService {
|
||||
|
||||
if (!body.key.fromMe) {
|
||||
this.logger.verbose('message is not from me');
|
||||
content = `**${participantName}**\n\n${bodyMessage}`;
|
||||
content = `**${participantName}:**\n\n${bodyMessage}`;
|
||||
} else {
|
||||
this.logger.verbose('message is from me');
|
||||
content = `${bodyMessage}`;
|
||||
}
|
||||
|
||||
this.logger.verbose('send data to chatwoot');
|
||||
const send = await this.sendData(
|
||||
getConversion,
|
||||
fileName,
|
||||
messageType,
|
||||
content,
|
||||
);
|
||||
const send = await this.sendData(getConversion, fileName, messageType, content);
|
||||
|
||||
if (!send) {
|
||||
this.logger.warn('message not sent');
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageCacheFile = path.join(
|
||||
ROOT_DIR,
|
||||
'store',
|
||||
'chatwoot',
|
||||
`${instance.instanceName}_cache.txt`,
|
||||
);
|
||||
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||
|
||||
this.messageCache = this.loadMessageCache();
|
||||
|
||||
@@ -1371,24 +1358,14 @@ export class ChatwootService {
|
||||
this.logger.verbose('message is not group');
|
||||
|
||||
this.logger.verbose('send data to chatwoot');
|
||||
const send = await this.sendData(
|
||||
getConversion,
|
||||
fileName,
|
||||
messageType,
|
||||
bodyMessage,
|
||||
);
|
||||
const send = await this.sendData(getConversion, fileName, messageType, bodyMessage);
|
||||
|
||||
if (!send) {
|
||||
this.logger.warn('message not sent');
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageCacheFile = path.join(
|
||||
ROOT_DIR,
|
||||
'store',
|
||||
'chatwoot',
|
||||
`${instance.instanceName}_cache.txt`,
|
||||
);
|
||||
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||
|
||||
this.messageCache = this.loadMessageCache();
|
||||
|
||||
@@ -1417,24 +1394,14 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
this.logger.verbose('send data to chatwoot');
|
||||
const send = await this.createMessage(
|
||||
instance,
|
||||
getConversion,
|
||||
content,
|
||||
messageType,
|
||||
);
|
||||
const send = await this.createMessage(instance, getConversion, content, messageType);
|
||||
|
||||
if (!send) {
|
||||
this.logger.warn('message not sent');
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageCacheFile = path.join(
|
||||
ROOT_DIR,
|
||||
'store',
|
||||
'chatwoot',
|
||||
`${instance.instanceName}_cache.txt`,
|
||||
);
|
||||
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||
|
||||
this.messageCache = this.loadMessageCache();
|
||||
|
||||
@@ -1448,24 +1415,14 @@ export class ChatwootService {
|
||||
this.logger.verbose('message is not group');
|
||||
|
||||
this.logger.verbose('send data to chatwoot');
|
||||
const send = await this.createMessage(
|
||||
instance,
|
||||
getConversion,
|
||||
bodyMessage,
|
||||
messageType,
|
||||
);
|
||||
const send = await this.createMessage(instance, getConversion, bodyMessage, messageType);
|
||||
|
||||
if (!send) {
|
||||
this.logger.warn('message not sent');
|
||||
return;
|
||||
}
|
||||
|
||||
this.messageCacheFile = path.join(
|
||||
ROOT_DIR,
|
||||
'store',
|
||||
'chatwoot',
|
||||
`${instance.instanceName}_cache.txt`,
|
||||
);
|
||||
this.messageCacheFile = path.join(ROOT_DIR, 'store', 'chatwoot', `${instance.instanceName}_cache.txt`);
|
||||
|
||||
this.messageCache = this.loadMessageCache();
|
||||
|
||||
@@ -1494,37 +1451,30 @@ export class ChatwootService {
|
||||
await this.createBotMessage(instance, msgStatus, 'incoming');
|
||||
}
|
||||
|
||||
if (event === 'connection.update') {
|
||||
this.logger.verbose('event connection.update');
|
||||
// if (event === 'connection.update') {
|
||||
// this.logger.verbose('event connection.update');
|
||||
|
||||
if (body.status === 'open') {
|
||||
const msgConnection = `🚀 Connection successfully established!`;
|
||||
// if (body.status === 'open') {
|
||||
// const msgConnection = `🚀 Connection successfully established!`;
|
||||
|
||||
this.logger.verbose('send message to chatwoot');
|
||||
await this.createBotMessage(instance, msgConnection, 'incoming');
|
||||
}
|
||||
}
|
||||
// this.logger.verbose('send message to chatwoot');
|
||||
// await this.createBotMessage(instance, msgConnection, 'incoming');
|
||||
// }
|
||||
// }
|
||||
|
||||
if (event === 'qrcode.updated') {
|
||||
this.logger.verbose('event qrcode.updated');
|
||||
if (body.statusCode === 500) {
|
||||
this.logger.verbose('qrcode error');
|
||||
const erroQRcode = `🚨 QRCode generation limit reached, to generate a new QRCode, send the /init message again.`;
|
||||
const erroQRcode = `🚨 QRCode generation limit reached, to generate a new QRCode, send the 'init' message again.`;
|
||||
|
||||
this.logger.verbose('send message to chatwoot');
|
||||
return await this.createBotMessage(instance, erroQRcode, 'incoming');
|
||||
} else {
|
||||
this.logger.verbose('qrcode success');
|
||||
const fileData = Buffer.from(
|
||||
body?.qrcode.base64.replace('data:image/png;base64,', ''),
|
||||
'base64',
|
||||
);
|
||||
const fileData = Buffer.from(body?.qrcode.base64.replace('data:image/png;base64,', ''), 'base64');
|
||||
|
||||
const fileName = `${path.join(
|
||||
waInstance?.storePath,
|
||||
'temp',
|
||||
`${`${instance}.png`}`,
|
||||
)}`;
|
||||
const fileName = `${path.join(waInstance?.storePath, 'temp', `${`${instance}.png`}`)}`;
|
||||
|
||||
this.logger.verbose('temp file name: ' + fileName);
|
||||
|
||||
@@ -1532,14 +1482,18 @@ export class ChatwootService {
|
||||
writeFileSync(fileName, fileData, 'utf8');
|
||||
|
||||
this.logger.verbose('send qrcode to chatwoot');
|
||||
await this.createBotQr(
|
||||
instance,
|
||||
'QRCode successfully generated!',
|
||||
'incoming',
|
||||
fileName,
|
||||
);
|
||||
await this.createBotQr(instance, 'QRCode successfully generated!', 'incoming', fileName);
|
||||
|
||||
const msgQrCode = `⚡️ QRCode successfully generated!\n\nScan this QR code within the next 40 seconds:`;
|
||||
let msgQrCode = `⚡️ QRCode successfully generated!\n\nScan this QR code within the next 40 seconds.`;
|
||||
|
||||
if (body?.qrcode?.pairingCode) {
|
||||
msgQrCode =
|
||||
msgQrCode +
|
||||
`\n\n*Pairing Code:* ${body.qrcode.pairingCode.substring(0, 4)}-${body.qrcode.pairingCode.substring(
|
||||
4,
|
||||
8,
|
||||
)}`;
|
||||
}
|
||||
|
||||
this.logger.verbose('send message to chatwoot');
|
||||
await this.createBotMessage(instance, msgQrCode, 'incoming');
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import { opendirSync, readdirSync, rmSync } from 'fs';
|
||||
import { WAStartupService } from './whatsapp.service';
|
||||
import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config';
|
||||
import EventEmitter2 from 'eventemitter2';
|
||||
import { join } from 'path';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import {
|
||||
Auth,
|
||||
ConfigService,
|
||||
Database,
|
||||
DelInstance,
|
||||
HttpServer,
|
||||
Redis,
|
||||
} from '../../config/env.config';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { NotFoundException } from '../../exceptions';
|
||||
import { Db } from 'mongodb';
|
||||
import { initInstance } from '../whatsapp.module';
|
||||
import { RedisCache } from '../../db/redis.client';
|
||||
import { execSync } from 'child_process';
|
||||
import EventEmitter2 from 'eventemitter2';
|
||||
import { opendirSync, readdirSync, rmSync } from 'fs';
|
||||
import { Db } from 'mongodb';
|
||||
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 {
|
||||
AuthModel,
|
||||
ChatwootModel,
|
||||
ContactModel,
|
||||
MessageModel,
|
||||
MessageUpModel,
|
||||
SettingsModel,
|
||||
WebhookModel,
|
||||
} from '../models';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { WAStartupService } from './whatsapp.service';
|
||||
|
||||
export class WAMonitoringService {
|
||||
constructor(
|
||||
@@ -45,22 +48,20 @@ export class WAMonitoringService {
|
||||
|
||||
private dbInstance: Db;
|
||||
|
||||
private dbStore = dbserver;
|
||||
|
||||
private readonly logger = new Logger(WAMonitoringService.name);
|
||||
public readonly waInstances: Record<string, WAStartupService> = {};
|
||||
|
||||
public delInstanceTime(instance: string) {
|
||||
const time = this.configService.get<DelInstance>('DEL_INSTANCE');
|
||||
if (typeof time === 'number' && time > 0) {
|
||||
this.logger.verbose(
|
||||
`Instance "${instance}" don't have connection, will be removed in ${time} minutes`,
|
||||
);
|
||||
this.logger.verbose(`Instance "${instance}" don't have connection, will be removed in ${time} minutes`);
|
||||
|
||||
setTimeout(async () => {
|
||||
if (this.waInstances[instance]?.connectionStatus?.state !== 'open') {
|
||||
if (this.waInstances[instance]?.connectionStatus?.state === 'connecting') {
|
||||
await this.waInstances[instance]?.client?.logout(
|
||||
'Log out instance: ' + instance,
|
||||
);
|
||||
await this.waInstances[instance]?.client?.logout('Log out instance: ' + instance);
|
||||
this.waInstances[instance]?.client?.ws?.close();
|
||||
this.waInstances[instance]?.client?.end(undefined);
|
||||
delete this.waInstances[instance];
|
||||
@@ -90,10 +91,10 @@ export class WAMonitoringService {
|
||||
|
||||
const findChatwoot = await this.waInstances[key].findChatwoot();
|
||||
|
||||
if (findChatwoot.enabled) {
|
||||
if (findChatwoot && findChatwoot.enabled) {
|
||||
chatwoot = {
|
||||
...findChatwoot,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${key}`,
|
||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -112,21 +113,16 @@ export class WAMonitoringService {
|
||||
};
|
||||
|
||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
||||
instanceData.instance['serverUrl'] =
|
||||
this.configService.get<HttpServer>('SERVER').URL;
|
||||
instanceData.instance['serverUrl'] = this.configService.get<HttpServer>('SERVER').URL;
|
||||
|
||||
instanceData.instance['apikey'] = (
|
||||
await this.repository.auth.find(key)
|
||||
).apikey;
|
||||
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,
|
||||
);
|
||||
this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state);
|
||||
|
||||
const instanceData = {
|
||||
instance: {
|
||||
@@ -136,12 +132,9 @@ export class WAMonitoringService {
|
||||
};
|
||||
|
||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
||||
instanceData.instance['serverUrl'] =
|
||||
this.configService.get<HttpServer>('SERVER').URL;
|
||||
instanceData.instance['serverUrl'] = this.configService.get<HttpServer>('SERVER').URL;
|
||||
|
||||
instanceData.instance['apikey'] = (
|
||||
await this.repository.auth.find(key)
|
||||
).apikey;
|
||||
instanceData.instance['apikey'] = (await this.repository.auth.find(key))?.apikey;
|
||||
|
||||
instanceData.instance['chatwoot'] = chatwoot;
|
||||
}
|
||||
@@ -164,15 +157,11 @@ export class WAMonitoringService {
|
||||
collections.forEach(async (collection) => {
|
||||
const name = collection.namespace.replace(/^[\w-]+./, '');
|
||||
await this.dbInstance.collection(name).deleteMany({
|
||||
$or: [
|
||||
{ _id: { $regex: /^app.state.*/ } },
|
||||
{ _id: { $regex: /^session-.*/ } },
|
||||
],
|
||||
$or: [{ _id: { $regex: /^app.state.*/ } }, { _id: { $regex: /^session-.*/ } }],
|
||||
});
|
||||
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()) {
|
||||
@@ -210,6 +199,7 @@ export class WAMonitoringService {
|
||||
this.logger.verbose('cleaning up instance in redis: ' + instanceName);
|
||||
this.cache.reference = instanceName;
|
||||
await this.cache.delAll();
|
||||
this.cache.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,11 +208,8 @@ export class WAMonitoringService {
|
||||
}
|
||||
|
||||
public async cleaningStoreFiles(instanceName: string) {
|
||||
this.logger.verbose('cleaning store files instance: ' + instanceName);
|
||||
|
||||
if (!this.db.ENABLED) {
|
||||
const instance = this.waInstances[instanceName];
|
||||
|
||||
this.logger.verbose('cleaning store files instance: ' + instanceName);
|
||||
rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true });
|
||||
|
||||
execSync(`rm -rf ${join(STORE_DIR, 'chats', instanceName)}`);
|
||||
@@ -233,18 +220,34 @@ 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;
|
||||
}
|
||||
|
||||
this.logger.verbose('cleaning store database instance: ' + instanceName);
|
||||
|
||||
await AuthModel.deleteMany({ owner: instanceName });
|
||||
await ContactModel.deleteMany({ owner: instanceName });
|
||||
await MessageModel.deleteMany({ owner: instanceName });
|
||||
await MessageUpModel.deleteMany({ owner: instanceName });
|
||||
await AuthModel.deleteMany({ _id: instanceName });
|
||||
await WebhookModel.deleteMany({ _id: instanceName });
|
||||
await ChatwootModel.deleteMany({ _id: instanceName });
|
||||
await SettingsModel.deleteMany({ _id: instanceName });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||
instance.instanceName = name;
|
||||
this.logger.verbose('instance loaded: ' + name);
|
||||
|
||||
@@ -264,8 +267,8 @@ export class WAMonitoringService {
|
||||
keys.forEach(async (k) => await set(k.split(':')[1]));
|
||||
} else {
|
||||
this.logger.verbose('no instance keys found');
|
||||
initInstance();
|
||||
}
|
||||
this.cache.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,12 +278,9 @@ export class WAMonitoringService {
|
||||
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-]+\./, '')),
|
||||
);
|
||||
collections.forEach(async (coll) => await set(coll.namespace.replace(/^[\w-]+\./, '')));
|
||||
} else {
|
||||
this.logger.verbose('no collections found');
|
||||
initInstance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -301,7 +301,6 @@ export class WAMonitoringService {
|
||||
await set(dirent.name);
|
||||
} else {
|
||||
this.logger.verbose('no instance files found');
|
||||
initInstance();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -315,7 +314,9 @@ export class WAMonitoringService {
|
||||
try {
|
||||
this.logger.verbose('instance: ' + instanceName + ' - removing from memory');
|
||||
this.waInstances[instanceName] = undefined;
|
||||
} catch {}
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
}
|
||||
|
||||
try {
|
||||
this.logger.verbose('request cleaning up instance: ' + instanceName);
|
||||
@@ -340,11 +341,14 @@ export class WAMonitoringService {
|
||||
this.logger.verbose('checking instances without connection');
|
||||
this.eventEmitter.on('no.connection', async (instanceName) => {
|
||||
try {
|
||||
this.logger.verbose('instance: ' + instanceName + ' - removing from memory');
|
||||
this.waInstances[instanceName] = undefined;
|
||||
this.logger.verbose('logging out instance: ' + instanceName);
|
||||
await this.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
||||
|
||||
this.logger.verbose('request cleaning up instance: ' + instanceName);
|
||||
this.cleaningUp(instanceName);
|
||||
this.logger.verbose('close connection instance: ' + instanceName);
|
||||
this.waInstances[instanceName]?.client?.ws?.close();
|
||||
|
||||
this.waInstances[instanceName].instance.qrcode = { count: 0 };
|
||||
this.waInstances[instanceName].stateConnection.state = 'close';
|
||||
} catch (error) {
|
||||
this.logger.error({
|
||||
localError: 'noConnection',
|
||||
|
||||
33
src/whatsapp/services/proxy.service.ts
Normal file
33
src/whatsapp/services/proxy.service.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { ProxyDto } from '../dto/proxy.dto';
|
||||
import { ProxyRaw } from '../models';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class ProxyService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(ProxyService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: ProxyDto) {
|
||||
this.logger.verbose('create proxy: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setProxy(data);
|
||||
|
||||
return { proxy: { ...instance, proxy: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<ProxyRaw> {
|
||||
try {
|
||||
this.logger.verbose('find proxy: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findProxy();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Proxy not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { enabled: false, proxy: '' };
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/whatsapp/services/rabbitmq.service.ts
Normal file
35
src/whatsapp/services/rabbitmq.service.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { initQueues } from '../../libs/amqp.server';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { RabbitmqDto } from '../dto/rabbitmq.dto';
|
||||
import { RabbitmqRaw } from '../models';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class RabbitmqService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(RabbitmqService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: RabbitmqDto) {
|
||||
this.logger.verbose('create rabbitmq: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setRabbitmq(data);
|
||||
|
||||
initQueues(instance.instanceName, data.events);
|
||||
return { rabbitmq: { ...instance, rabbitmq: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<RabbitmqRaw> {
|
||||
try {
|
||||
this.logger.verbose('find rabbitmq: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findRabbitmq();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Rabbitmq not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { enabled: false, events: [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/whatsapp/services/settings.service.ts
Normal file
32
src/whatsapp/services/settings.service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { SettingsDto } from '../dto/settings.dto';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class SettingsService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(SettingsService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: SettingsDto) {
|
||||
this.logger.verbose('create settings: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setSettings(data);
|
||||
|
||||
return { settings: { ...instance, settings: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<SettingsDto> {
|
||||
try {
|
||||
this.logger.verbose('find settings: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findSettings();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Settings not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { reject_call: false, msg_call: '', groups_ignore: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
521
src/whatsapp/services/typebot.service.ts
Normal file
521
src/whatsapp/services/typebot.service.ts
Normal file
@@ -0,0 +1,521 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { Session, TypebotDto } from '../dto/typebot.dto';
|
||||
import { MessageRaw } from '../models';
|
||||
import { Events } from '../types/wa.types';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class TypebotService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(TypebotService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: TypebotDto) {
|
||||
this.logger.verbose('create typebot: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setTypebot(data);
|
||||
|
||||
return { typebot: { ...instance, typebot: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<TypebotDto> {
|
||||
try {
|
||||
this.logger.verbose('find typebot: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findTypebot();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Typebot not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { enabled: false, url: '', typebot: '', expire: 0, sessions: [] };
|
||||
}
|
||||
}
|
||||
|
||||
public async changeStatus(instance: InstanceDto, data: any) {
|
||||
const remoteJid = data.remoteJid;
|
||||
const status = data.status;
|
||||
|
||||
const findData = await this.find(instance);
|
||||
|
||||
const session = findData.sessions.find((session) => session.remoteJid === remoteJid);
|
||||
|
||||
if (session) {
|
||||
if (status === 'closed') {
|
||||
findData.sessions.splice(findData.sessions.indexOf(session), 1);
|
||||
|
||||
const typebotData = {
|
||||
enabled: true,
|
||||
url: findData.url,
|
||||
typebot: findData.typebot,
|
||||
expire: findData.expire,
|
||||
keyword_finish: findData.keyword_finish,
|
||||
delay_message: findData.delay_message,
|
||||
unknown_message: findData.unknown_message,
|
||||
listening_from_me: findData.listening_from_me,
|
||||
sessions: findData.sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
return { typebot: { ...instance, typebot: typebotData } };
|
||||
}
|
||||
|
||||
findData.sessions.map((session) => {
|
||||
if (session.remoteJid === remoteJid) {
|
||||
session.status = status;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const typebotData = {
|
||||
enabled: true,
|
||||
url: findData.url,
|
||||
typebot: findData.typebot,
|
||||
expire: findData.expire,
|
||||
keyword_finish: findData.keyword_finish,
|
||||
delay_message: findData.delay_message,
|
||||
unknown_message: findData.unknown_message,
|
||||
listening_from_me: findData.listening_from_me,
|
||||
sessions: findData.sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_CHANGE_STATUS, {
|
||||
remoteJid: remoteJid,
|
||||
status: status,
|
||||
url: findData.url,
|
||||
typebot: findData.typebot,
|
||||
session,
|
||||
});
|
||||
|
||||
return { typebot: { ...instance, typebot: typebotData } };
|
||||
}
|
||||
|
||||
public async startTypebot(instance: InstanceDto, data: any) {
|
||||
const remoteJid = data.remoteJid;
|
||||
const url = data.url;
|
||||
const typebot = data.typebot;
|
||||
const variables = data.variables;
|
||||
|
||||
const prefilledVariables = {
|
||||
remoteJid: remoteJid,
|
||||
};
|
||||
|
||||
variables.forEach((variable) => {
|
||||
prefilledVariables[variable.name] = variable.value;
|
||||
});
|
||||
|
||||
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||
|
||||
const reqData = {
|
||||
sessionId: id,
|
||||
startParams: {
|
||||
typebot: data.typebot,
|
||||
prefilledVariables: prefilledVariables,
|
||||
},
|
||||
};
|
||||
|
||||
const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
request.data.messages,
|
||||
request.data.input,
|
||||
request.data.clientSideActions,
|
||||
);
|
||||
|
||||
this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, {
|
||||
remoteJid: remoteJid,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
variables: variables,
|
||||
sessionId: id,
|
||||
});
|
||||
|
||||
return {
|
||||
typebot: {
|
||||
...instance,
|
||||
typebot: {
|
||||
url: url,
|
||||
remoteJid: remoteJid,
|
||||
typebot: typebot,
|
||||
variables: variables,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getTypeMessage(msg: any) {
|
||||
this.logger.verbose('get type message');
|
||||
|
||||
const types = {
|
||||
conversation: msg.conversation,
|
||||
extendedTextMessage: msg.extendedTextMessage?.text,
|
||||
};
|
||||
|
||||
this.logger.verbose('type message: ' + types);
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
private getMessageContent(types: any) {
|
||||
this.logger.verbose('get message content');
|
||||
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||
|
||||
const result = typeKey ? types[typeKey] : undefined;
|
||||
|
||||
this.logger.verbose('message content: ' + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private getConversationMessage(msg: any) {
|
||||
this.logger.verbose('get conversation message');
|
||||
|
||||
const types = this.getTypeMessage(msg);
|
||||
|
||||
const messageContent = this.getMessageContent(types);
|
||||
|
||||
this.logger.verbose('conversation message: ' + messageContent);
|
||||
|
||||
return messageContent;
|
||||
}
|
||||
|
||||
public async createNewSession(instance: InstanceDto, data: any) {
|
||||
const id = Math.floor(Math.random() * 10000000000).toString();
|
||||
const reqData = {
|
||||
sessionId: id,
|
||||
startParams: {
|
||||
typebot: data.typebot,
|
||||
prefilledVariables: {
|
||||
remoteJid: data.remoteJid,
|
||||
pushName: data.pushName,
|
||||
instanceName: instance.instanceName,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
if (request.data.sessionId) {
|
||||
data.sessions.push({
|
||||
remoteJid: data.remoteJid,
|
||||
sessionId: `${id}-${request.data.sessionId}`,
|
||||
status: 'opened',
|
||||
createdAt: Date.now(),
|
||||
updateAt: Date.now(),
|
||||
});
|
||||
|
||||
const typebotData = {
|
||||
enabled: true,
|
||||
url: data.url,
|
||||
typebot: data.typebot,
|
||||
expire: data.expire,
|
||||
keyword_finish: data.keyword_finish,
|
||||
delay_message: data.delay_message,
|
||||
unknown_message: data.unknown_message,
|
||||
listening_from_me: data.listening_from_me,
|
||||
sessions: data.sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
}
|
||||
|
||||
return request.data;
|
||||
}
|
||||
|
||||
public async sendWAMessage(
|
||||
instance: InstanceDto,
|
||||
remoteJid: string,
|
||||
messages: any[],
|
||||
input: any[],
|
||||
clientSideActions: any[],
|
||||
) {
|
||||
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input, clientSideActions).catch(
|
||||
(err) => {
|
||||
console.error('Erro ao processar mensagens:', err);
|
||||
},
|
||||
);
|
||||
|
||||
function findItemAndGetSecondsToWait(array, targetId) {
|
||||
if (!array) return null;
|
||||
|
||||
for (const item of array) {
|
||||
if (item.lastBubbleBlockId === targetId) {
|
||||
return item.wait?.secondsToWaitFor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function processMessages(instance, messages, input, clientSideActions) {
|
||||
for (const message of messages) {
|
||||
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
|
||||
|
||||
if (message.type === 'text') {
|
||||
let formattedText = '';
|
||||
|
||||
let linkPreview = false;
|
||||
|
||||
for (const richText of message.content.richText) {
|
||||
for (const element of richText.children) {
|
||||
let text = '';
|
||||
if (element.text) {
|
||||
text = element.text;
|
||||
}
|
||||
|
||||
if (element.bold) {
|
||||
text = `*${text}*`;
|
||||
}
|
||||
|
||||
if (element.italic) {
|
||||
text = `_${text}_`;
|
||||
}
|
||||
|
||||
if (element.underline) {
|
||||
text = `~${text}~`;
|
||||
}
|
||||
|
||||
if (element.url) {
|
||||
const linkText = element.children[0].text;
|
||||
text = `[${linkText}](${element.url})`;
|
||||
linkPreview = true;
|
||||
}
|
||||
|
||||
formattedText += text;
|
||||
}
|
||||
formattedText += '\n';
|
||||
}
|
||||
|
||||
formattedText = formattedText.replace(/\n$/, '');
|
||||
|
||||
await instance.textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||
presence: 'composing',
|
||||
linkPreview: linkPreview,
|
||||
},
|
||||
textMessage: {
|
||||
text: formattedText,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (message.type === 'image') {
|
||||
await instance.mediaMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
mediaMessage: {
|
||||
mediatype: 'image',
|
||||
media: message.content.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (message.type === 'video') {
|
||||
await instance.mediaMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
mediaMessage: {
|
||||
mediatype: 'video',
|
||||
media: message.content.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (message.type === 'audio') {
|
||||
await instance.audioWhatsapp({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||
presence: 'recording',
|
||||
encoding: true,
|
||||
},
|
||||
audioMessage: {
|
||||
audio: message.content.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (input) {
|
||||
if (input.type === 'choice input') {
|
||||
let formattedText = '';
|
||||
|
||||
const items = input.items;
|
||||
|
||||
for (const item of items) {
|
||||
formattedText += `▶️ ${item.content}\n`;
|
||||
}
|
||||
|
||||
formattedText = formattedText.replace(/\n$/, '');
|
||||
|
||||
await instance.textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: 1200,
|
||||
presence: 'composing',
|
||||
linkPreview: false,
|
||||
},
|
||||
textMessage: {
|
||||
text: formattedText,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: MessageRaw) {
|
||||
const findTypebot = await this.find(instance);
|
||||
const url = findTypebot.url;
|
||||
const typebot = findTypebot.typebot;
|
||||
const sessions = (findTypebot.sessions as Session[]) ?? [];
|
||||
const expire = findTypebot.expire;
|
||||
const keyword_finish = findTypebot.keyword_finish;
|
||||
const delay_message = findTypebot.delay_message;
|
||||
const unknown_message = findTypebot.unknown_message;
|
||||
const listening_from_me = findTypebot.listening_from_me;
|
||||
|
||||
const session = sessions.find((session) => session.remoteJid === remoteJid);
|
||||
|
||||
if (session && expire && expire > 0) {
|
||||
const now = Date.now();
|
||||
|
||||
const diff = now - session.updateAt;
|
||||
|
||||
const diffInMinutes = Math.floor(diff / 1000 / 60);
|
||||
|
||||
if (diffInMinutes > expire) {
|
||||
sessions.splice(sessions.indexOf(session), 1);
|
||||
|
||||
const data = await this.createNewSession(instance, {
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions: sessions,
|
||||
remoteJid: remoteJid,
|
||||
pushName: msg.pushName,
|
||||
});
|
||||
|
||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (session && session.status !== 'opened') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
const data = await this.createNewSession(instance, {
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions: sessions,
|
||||
remoteJid: remoteJid,
|
||||
pushName: msg.pushName,
|
||||
});
|
||||
|
||||
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sessions.map((session) => {
|
||||
if (session.remoteJid === remoteJid) {
|
||||
session.updateAt = Date.now();
|
||||
}
|
||||
});
|
||||
|
||||
const typebotData = {
|
||||
enabled: true,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
const content = this.getConversationMessage(msg.message);
|
||||
|
||||
if (!content) {
|
||||
if (unknown_message) {
|
||||
this.waMonitor.waInstances[instance.instanceName].textMessage({
|
||||
number: remoteJid.split('@')[0],
|
||||
options: {
|
||||
delay: delay_message || 1000,
|
||||
presence: 'composing',
|
||||
},
|
||||
textMessage: {
|
||||
text: unknown_message,
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.toLowerCase() === keyword_finish.toLowerCase()) {
|
||||
sessions.splice(sessions.indexOf(session), 1);
|
||||
|
||||
const typebotData = {
|
||||
enabled: true,
|
||||
url: url,
|
||||
typebot: typebot,
|
||||
expire: expire,
|
||||
keyword_finish: keyword_finish,
|
||||
delay_message: delay_message,
|
||||
unknown_message: unknown_message,
|
||||
listening_from_me: listening_from_me,
|
||||
sessions,
|
||||
};
|
||||
|
||||
this.create(instance, typebotData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const reqData = {
|
||||
message: content,
|
||||
sessionId: session.sessionId.split('-')[1],
|
||||
};
|
||||
|
||||
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
|
||||
|
||||
await this.sendWAMessage(
|
||||
instance,
|
||||
remoteJid,
|
||||
request.data.messages,
|
||||
request.data.input,
|
||||
request.data.clientSideActions,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebhookDto } from '../dto/webhook.dto';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
|
||||
export class WebhookService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
@@ -18,9 +18,7 @@ export class WebhookService {
|
||||
public async find(instance: InstanceDto): Promise<WebhookDto> {
|
||||
try {
|
||||
this.logger.verbose('find webhook: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[
|
||||
instance.instanceName
|
||||
].findWebhook();
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findWebhook();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Webhook not found');
|
||||
|
||||
33
src/whatsapp/services/websocket.service.ts
Normal file
33
src/whatsapp/services/websocket.service.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { WebsocketDto } from '../dto/websocket.dto';
|
||||
import { WebsocketRaw } from '../models';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
|
||||
export class WebsocketService {
|
||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||
|
||||
private readonly logger = new Logger(WebsocketService.name);
|
||||
|
||||
public create(instance: InstanceDto, data: WebsocketDto) {
|
||||
this.logger.verbose('create websocket: ' + instance.instanceName);
|
||||
this.waMonitor.waInstances[instance.instanceName].setWebsocket(data);
|
||||
|
||||
return { websocket: { ...instance, websocket: data } };
|
||||
}
|
||||
|
||||
public async find(instance: InstanceDto): Promise<WebsocketRaw> {
|
||||
try {
|
||||
this.logger.verbose('find websocket: ' + instance.instanceName);
|
||||
const result = await this.waMonitor.waInstances[instance.instanceName].findWebsocket();
|
||||
|
||||
if (Object.keys(result).length === 0) {
|
||||
throw new Error('Websocket not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { enabled: false, events: [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,12 +22,22 @@ export enum Events {
|
||||
GROUPS_UPSERT = 'groups.upsert',
|
||||
GROUPS_UPDATE = 'groups.update',
|
||||
GROUP_PARTICIPANTS_UPDATE = 'group-participants.update',
|
||||
CALL = 'call',
|
||||
TYPEBOT_START = 'typebot.start',
|
||||
TYPEBOT_CHANGE_STATUS = 'typebot.change-status',
|
||||
CHAMA_AI_ACTION = 'chama-ai.action',
|
||||
}
|
||||
|
||||
export declare namespace wa {
|
||||
export type QrCode = { count?: number; base64?: string; code?: string };
|
||||
export type QrCode = {
|
||||
count?: number;
|
||||
pairingCode?: string;
|
||||
base64?: string;
|
||||
code?: string;
|
||||
};
|
||||
export type Instance = {
|
||||
qrcode?: QrCode;
|
||||
pairingCode?: string;
|
||||
authState?: { state: AuthenticationState; saveCreds: () => void };
|
||||
name?: string;
|
||||
wuid?: string;
|
||||
@@ -49,6 +59,59 @@ export declare namespace wa {
|
||||
url?: string;
|
||||
name_inbox?: string;
|
||||
sign_msg?: boolean;
|
||||
number?: string;
|
||||
reopen_conversation?: boolean;
|
||||
conversation_pending?: boolean;
|
||||
};
|
||||
|
||||
export type LocalSettings = {
|
||||
reject_call?: boolean;
|
||||
msg_call?: string;
|
||||
groups_ignore?: boolean;
|
||||
always_online?: boolean;
|
||||
read_messages?: boolean;
|
||||
read_status?: boolean;
|
||||
};
|
||||
|
||||
export type LocalWebsocket = {
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
};
|
||||
|
||||
export type LocalRabbitmq = {
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
};
|
||||
|
||||
type Session = {
|
||||
remoteJid?: string;
|
||||
sessionId?: string;
|
||||
createdAt?: number;
|
||||
};
|
||||
|
||||
export type LocalTypebot = {
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
typebot?: string;
|
||||
expire?: number;
|
||||
keyword_finish?: string;
|
||||
delay_message?: number;
|
||||
unknown_message?: string;
|
||||
listening_from_me?: boolean;
|
||||
sessions?: Session[];
|
||||
};
|
||||
|
||||
export type LocalProxy = {
|
||||
enabled?: boolean;
|
||||
proxy?: string;
|
||||
};
|
||||
|
||||
export type LocalChamaai = {
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
token?: string;
|
||||
waNumber?: string;
|
||||
answerByAudio?: boolean;
|
||||
};
|
||||
|
||||
export type StateConnection = {
|
||||
@@ -57,22 +120,10 @@ export declare namespace wa {
|
||||
statusReason?: number;
|
||||
};
|
||||
|
||||
export type StatusMessage =
|
||||
| 'ERROR'
|
||||
| 'PENDING'
|
||||
| 'SERVER_ACK'
|
||||
| 'DELIVERY_ACK'
|
||||
| 'READ'
|
||||
| 'PLAYED';
|
||||
export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED';
|
||||
}
|
||||
|
||||
export const TypeMediaMessage = [
|
||||
'imageMessage',
|
||||
'documentMessage',
|
||||
'audioMessage',
|
||||
'videoMessage',
|
||||
'stickerMessage',
|
||||
];
|
||||
export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage'];
|
||||
|
||||
export const MessageSubtype = [
|
||||
'ephemeralMessage',
|
||||
|
||||
@@ -1,39 +1,60 @@
|
||||
import { Auth, configService } from '../config/env.config';
|
||||
import { Logger } from '../config/logger.config';
|
||||
import { configService } from '../config/env.config';
|
||||
import { eventEmitter } from '../config/event.config';
|
||||
import { MessageRepository } from './repository/message.repository';
|
||||
import { WAMonitoringService } from './services/monitor.service';
|
||||
import { ChatRepository } from './repository/chat.repository';
|
||||
import { ContactRepository } from './repository/contact.repository';
|
||||
import { MessageUpRepository } from './repository/messageUp.repository';
|
||||
import { Logger } from '../config/logger.config';
|
||||
import { dbserver } from '../libs/db.connect';
|
||||
import { RedisCache } from '../libs/redis.client';
|
||||
import { ChamaaiController } from './controllers/chamaai.controller';
|
||||
import { ChatController } from './controllers/chat.controller';
|
||||
import { InstanceController } from './controllers/instance.controller';
|
||||
import { SendMessageController } from './controllers/sendMessage.controller';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { GroupController } from './controllers/group.controller';
|
||||
import { ViewsController } from './controllers/views.controller';
|
||||
import { WebhookService } from './services/webhook.service';
|
||||
import { WebhookController } from './controllers/webhook.controller';
|
||||
import { ChatwootService } from './services/chatwoot.service';
|
||||
import { ChatwootController } from './controllers/chatwoot.controller';
|
||||
import { RepositoryBroker } from './repository/repository.manager';
|
||||
import { GroupController } from './controllers/group.controller';
|
||||
import { InstanceController } from './controllers/instance.controller';
|
||||
import { ProxyController } from './controllers/proxy.controller';
|
||||
import { RabbitmqController } from './controllers/rabbitmq.controller';
|
||||
import { SendMessageController } from './controllers/sendMessage.controller';
|
||||
import { SettingsController } from './controllers/settings.controller';
|
||||
import { TypebotController } from './controllers/typebot.controller';
|
||||
import { ViewsController } from './controllers/views.controller';
|
||||
import { WebhookController } from './controllers/webhook.controller';
|
||||
import { WebsocketController } from './controllers/websocket.controller';
|
||||
import {
|
||||
AuthModel,
|
||||
ChamaaiModel,
|
||||
ChatModel,
|
||||
ChatwootModel,
|
||||
ContactModel,
|
||||
MessageModel,
|
||||
MessageUpModel,
|
||||
ChatwootModel,
|
||||
ProxyModel,
|
||||
RabbitmqModel,
|
||||
SettingsModel,
|
||||
TypebotModel,
|
||||
WebhookModel,
|
||||
WebsocketModel,
|
||||
} from './models';
|
||||
import { dbserver } from '../db/db.connect';
|
||||
import { WebhookRepository } from './repository/webhook.repository';
|
||||
import { ChatwootRepository } from './repository/chatwoot.repository';
|
||||
import { AuthRepository } from './repository/auth.repository';
|
||||
import { WAStartupService } from './services/whatsapp.service';
|
||||
import { delay } from '@whiskeysockets/baileys';
|
||||
import { Events } from './types/wa.types';
|
||||
import { RedisCache } from '../db/redis.client';
|
||||
import { ChamaaiRepository } from './repository/chamaai.repository';
|
||||
import { ChatRepository } from './repository/chat.repository';
|
||||
import { ChatwootRepository } from './repository/chatwoot.repository';
|
||||
import { ContactRepository } from './repository/contact.repository';
|
||||
import { MessageRepository } from './repository/message.repository';
|
||||
import { MessageUpRepository } from './repository/messageUp.repository';
|
||||
import { ProxyRepository } from './repository/proxy.repository';
|
||||
import { RabbitmqRepository } from './repository/rabbitmq.repository';
|
||||
import { RepositoryBroker } from './repository/repository.manager';
|
||||
import { SettingsRepository } from './repository/settings.repository';
|
||||
import { TypebotRepository } from './repository/typebot.repository';
|
||||
import { WebhookRepository } from './repository/webhook.repository';
|
||||
import { WebsocketRepository } from './repository/websocket.repository';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { ChamaaiService } from './services/chamaai.service';
|
||||
import { ChatwootService } from './services/chatwoot.service';
|
||||
import { WAMonitoringService } from './services/monitor.service';
|
||||
import { ProxyService } from './services/proxy.service';
|
||||
import { RabbitmqService } from './services/rabbitmq.service';
|
||||
import { SettingsService } from './services/settings.service';
|
||||
import { TypebotService } from './services/typebot.service';
|
||||
import { WebhookService } from './services/webhook.service';
|
||||
import { WebsocketService } from './services/websocket.service';
|
||||
|
||||
const logger = new Logger('WA MODULE');
|
||||
|
||||
@@ -41,8 +62,14 @@ const messageRepository = new MessageRepository(MessageModel, configService);
|
||||
const chatRepository = new ChatRepository(ChatModel, configService);
|
||||
const contactRepository = new ContactRepository(ContactModel, configService);
|
||||
const messageUpdateRepository = new MessageUpRepository(MessageUpModel, configService);
|
||||
const typebotRepository = new TypebotRepository(TypebotModel, configService);
|
||||
const webhookRepository = new WebhookRepository(WebhookModel, configService);
|
||||
const websocketRepository = new WebsocketRepository(WebsocketModel, configService);
|
||||
const proxyRepository = new ProxyRepository(ProxyModel, configService);
|
||||
const chamaaiRepository = new ChamaaiRepository(ChamaaiModel, configService);
|
||||
const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService);
|
||||
const chatwootRepository = new ChatwootRepository(ChatwootModel, configService);
|
||||
const settingsRepository = new SettingsRepository(SettingsModel, configService);
|
||||
const authRepository = new AuthRepository(AuthModel, configService);
|
||||
|
||||
export const repository = new RepositoryBroker(
|
||||
@@ -52,6 +79,12 @@ export const repository = new RepositoryBroker(
|
||||
messageUpdateRepository,
|
||||
webhookRepository,
|
||||
chatwootRepository,
|
||||
settingsRepository,
|
||||
websocketRepository,
|
||||
rabbitmqRepository,
|
||||
typebotRepository,
|
||||
proxyRepository,
|
||||
chamaaiRepository,
|
||||
authRepository,
|
||||
configService,
|
||||
dbserver?.getClient(),
|
||||
@@ -59,23 +92,42 @@ export const repository = new RepositoryBroker(
|
||||
|
||||
export const cache = new RedisCache();
|
||||
|
||||
export const waMonitor = new WAMonitoringService(
|
||||
eventEmitter,
|
||||
configService,
|
||||
repository,
|
||||
cache,
|
||||
);
|
||||
export const waMonitor = new WAMonitoringService(eventEmitter, configService, repository, cache);
|
||||
|
||||
const authService = new AuthService(configService, waMonitor, repository);
|
||||
|
||||
const typebotService = new TypebotService(waMonitor);
|
||||
|
||||
export const typebotController = new TypebotController(typebotService);
|
||||
|
||||
const webhookService = new WebhookService(waMonitor);
|
||||
|
||||
export const webhookController = new WebhookController(webhookService);
|
||||
|
||||
const websocketService = new WebsocketService(waMonitor);
|
||||
|
||||
export const websocketController = new WebsocketController(websocketService);
|
||||
|
||||
const proxyService = new ProxyService(waMonitor);
|
||||
|
||||
export const proxyController = new ProxyController(proxyService);
|
||||
|
||||
const chamaaiService = new ChamaaiService(waMonitor, configService);
|
||||
|
||||
export const chamaaiController = new ChamaaiController(chamaaiService);
|
||||
|
||||
const rabbitmqService = new RabbitmqService(waMonitor);
|
||||
|
||||
export const rabbitmqController = new RabbitmqController(rabbitmqService);
|
||||
|
||||
const chatwootService = new ChatwootService(waMonitor, configService);
|
||||
|
||||
export const chatwootController = new ChatwootController(chatwootService, configService);
|
||||
|
||||
const settingsService = new SettingsService(waMonitor);
|
||||
|
||||
export const settingsController = new SettingsController(settingsService);
|
||||
|
||||
export const instanceController = new InstanceController(
|
||||
waMonitor,
|
||||
configService,
|
||||
@@ -84,6 +136,10 @@ export const instanceController = new InstanceController(
|
||||
authService,
|
||||
webhookService,
|
||||
chatwootService,
|
||||
settingsService,
|
||||
websocketService,
|
||||
rabbitmqService,
|
||||
typebotService,
|
||||
cache,
|
||||
);
|
||||
export const viewsController = new ViewsController(waMonitor, configService);
|
||||
@@ -91,111 +147,4 @@ export const sendMessageController = new SendMessageController(waMonitor);
|
||||
export const chatController = new ChatController(waMonitor);
|
||||
export const groupController = new GroupController(waMonitor);
|
||||
|
||||
export async function initInstance() {
|
||||
const instance = new WAStartupService(configService, eventEmitter, repository, cache);
|
||||
|
||||
const mode = configService.get<Auth>('AUTHENTICATION').INSTANCE.MODE;
|
||||
|
||||
logger.verbose('Sending data webhook for event: ' + Events.APPLICATION_STARTUP);
|
||||
instance.sendDataWebhook(
|
||||
Events.APPLICATION_STARTUP,
|
||||
{
|
||||
message: 'Application startup',
|
||||
mode,
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
||||
if (mode === 'container') {
|
||||
logger.verbose('Application startup in container mode');
|
||||
|
||||
const instanceName = configService.get<Auth>('AUTHENTICATION').INSTANCE.NAME;
|
||||
logger.verbose('Instance name: ' + instanceName);
|
||||
|
||||
const instanceWebhook =
|
||||
configService.get<Auth>('AUTHENTICATION').INSTANCE.WEBHOOK_URL;
|
||||
logger.verbose('Instance webhook: ' + instanceWebhook);
|
||||
|
||||
// const chatwootAccountId =
|
||||
// configService.get<Auth>('AUTHENTICATION').INSTANCE.CHATWOOT_ACCOUNT_ID;
|
||||
// logger.verbose('Chatwoot account id: ' + chatwootAccountId);
|
||||
|
||||
// const chatwootToken =
|
||||
// configService.get<Auth>('AUTHENTICATION').INSTANCE.CHATWOOT_TOKEN;
|
||||
// logger.verbose('Chatwoot token: ' + chatwootToken);
|
||||
|
||||
// const chatwootUrl = configService.get<Auth>('AUTHENTICATION').INSTANCE.CHATWOOT_URL;
|
||||
// logger.verbose('Chatwoot url: ' + chatwootUrl);
|
||||
|
||||
instance.instanceName = instanceName;
|
||||
|
||||
waMonitor.waInstances[instance.instanceName] = instance;
|
||||
waMonitor.delInstanceTime(instance.instanceName);
|
||||
|
||||
const hash = await authService.generateHash({
|
||||
instanceName: instance.instanceName,
|
||||
token: configService.get<Auth>('AUTHENTICATION').API_KEY.KEY,
|
||||
});
|
||||
logger.verbose('Hash generated: ' + hash);
|
||||
|
||||
if (instanceWebhook) {
|
||||
logger.verbose('Creating webhook for instance: ' + instanceName);
|
||||
try {
|
||||
webhookService.create(instance, { enabled: true, url: instanceWebhook });
|
||||
logger.verbose('Webhook created');
|
||||
} catch (error) {
|
||||
logger.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// if (chatwootUrl && chatwootToken && chatwootAccountId) {
|
||||
// logger.verbose('Creating chatwoot for instance: ' + instanceName);
|
||||
// try {
|
||||
// chatwootService.create(instance, {
|
||||
// enabled: true,
|
||||
// url: chatwootUrl,
|
||||
// token: chatwootToken,
|
||||
// account_id: chatwootAccountId,
|
||||
// sign_msg: false,
|
||||
// });
|
||||
// logger.verbose('Chatwoot created');
|
||||
// } catch (error) {
|
||||
// logger.log(error);
|
||||
// }
|
||||
// }
|
||||
|
||||
try {
|
||||
const state = instance.connectionStatus?.state;
|
||||
|
||||
switch (state) {
|
||||
case 'close':
|
||||
await instance.connectToWhatsapp();
|
||||
await delay(2000);
|
||||
return instance.qrCode;
|
||||
case 'connecting':
|
||||
return instance.qrCode;
|
||||
default:
|
||||
return await this.connectionState({ instanceName });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log(error);
|
||||
}
|
||||
|
||||
const result = {
|
||||
instance: {
|
||||
instanceName: instance.instanceName,
|
||||
status: 'created',
|
||||
},
|
||||
hash,
|
||||
webhook: instanceWebhook,
|
||||
};
|
||||
|
||||
logger.info(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.info('Module - ON');
|
||||
|
||||
Reference in New Issue
Block a user