mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-26 10:28:38 -06:00
docs:Update code comments, add JSDoc annotations
This commit is contained in:
parent
bddd6408ac
commit
aef6deb89b
@ -3,19 +3,28 @@ import * as amqp from 'amqplib/callback_api';
|
|||||||
import { configService, Rabbitmq } from '../config/env.config';
|
import { configService, Rabbitmq } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
|
// Create a logger instance specifically for AMQP-related logs.
|
||||||
const logger = new Logger('AMQP');
|
const logger = new Logger('AMQP');
|
||||||
|
|
||||||
|
// Declare an AMQP channel, initially set to null.
|
||||||
let amqpChannel: amqp.Channel | null = null;
|
let amqpChannel: amqp.Channel | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the AMQP (Advanced Message Queuing Protocol) connection.
|
||||||
|
* @returns {Promise<void>} A promise that resolves when the AMQP connection is established.
|
||||||
|
*/
|
||||||
export const initAMQP = () => {
|
export const initAMQP = () => {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
|
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
|
||||||
|
|
||||||
|
// Connect to the RabbitMQ server.
|
||||||
amqp.connect(uri, (error, connection) => {
|
amqp.connect(uri, (error, connection) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create an AMQP channel for communication.
|
||||||
connection.createChannel((channelError, channel) => {
|
connection.createChannel((channelError, channel) => {
|
||||||
if (channelError) {
|
if (channelError) {
|
||||||
reject(channelError);
|
reject(channelError);
|
||||||
@ -24,6 +33,7 @@ export const initAMQP = () => {
|
|||||||
|
|
||||||
const exchangeName = 'evolution_exchange';
|
const exchangeName = 'evolution_exchange';
|
||||||
|
|
||||||
|
// Declare an exchange with topic routing.
|
||||||
channel.assertExchange(exchangeName, 'topic', {
|
channel.assertExchange(exchangeName, 'topic', {
|
||||||
durable: true,
|
durable: true,
|
||||||
autoDelete: false,
|
autoDelete: false,
|
||||||
@ -38,13 +48,23 @@ export const initAMQP = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initialized AMQP channel.
|
||||||
|
* @returns {amqp.Channel | null} The initialized AMQP channel or null if not initialized.
|
||||||
|
*/
|
||||||
export const getAMQP = (): amqp.Channel | null => {
|
export const getAMQP = (): amqp.Channel | null => {
|
||||||
return amqpChannel;
|
return amqpChannel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes queues for specified events.
|
||||||
|
* @param {string} instanceName - The name of the instance.
|
||||||
|
* @param {string[]} events - An array of event names.
|
||||||
|
*/
|
||||||
export const initQueues = (instanceName: string, events: string[]) => {
|
export const initQueues = (instanceName: string, events: string[]) => {
|
||||||
if (!events || !events.length) return;
|
if (!events || !events.length) return;
|
||||||
|
|
||||||
|
// Transform event names into queue names.
|
||||||
const queues = events.map((event) => {
|
const queues = events.map((event) => {
|
||||||
return `${event.replace(/_/g, '.').toLowerCase()}`;
|
return `${event.replace(/_/g, '.').toLowerCase()}`;
|
||||||
});
|
});
|
||||||
@ -53,6 +73,7 @@ export const initQueues = (instanceName: string, events: string[]) => {
|
|||||||
const amqp = getAMQP();
|
const amqp = getAMQP();
|
||||||
const exchangeName = instanceName ?? 'evolution_exchange';
|
const exchangeName = instanceName ?? 'evolution_exchange';
|
||||||
|
|
||||||
|
// Assert the exchange with topic routing.
|
||||||
amqp.assertExchange(exchangeName, 'topic', {
|
amqp.assertExchange(exchangeName, 'topic', {
|
||||||
durable: true,
|
durable: true,
|
||||||
autoDelete: false,
|
autoDelete: false,
|
||||||
@ -60,6 +81,7 @@ export const initQueues = (instanceName: string, events: string[]) => {
|
|||||||
|
|
||||||
const queueName = `${instanceName}.${event}`;
|
const queueName = `${instanceName}.${event}`;
|
||||||
|
|
||||||
|
// Assert a queue with quorum support.
|
||||||
amqp.assertQueue(queueName, {
|
amqp.assertQueue(queueName, {
|
||||||
durable: true,
|
durable: true,
|
||||||
autoDelete: false,
|
autoDelete: false,
|
||||||
@ -68,6 +90,7 @@ export const initQueues = (instanceName: string, events: string[]) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bind the queue to the exchange with the corresponding event.
|
||||||
amqp.bindQueue(queueName, exchangeName, event);
|
amqp.bindQueue(queueName, exchangeName, event);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -3,23 +3,73 @@ import mongoose from 'mongoose';
|
|||||||
import { configService, Database } from '../config/env.config';
|
import { configService, Database } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object for logging MongoDB-related messages.
|
||||||
|
* @type {Logger}
|
||||||
|
*/
|
||||||
const logger = new Logger('MongoDB');
|
const logger = new Logger('MongoDB');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database settings retrieved from the configuration file.
|
||||||
|
* @type {Database}
|
||||||
|
*/
|
||||||
const db = configService.get<Database>('DATABASE');
|
const db = configService.get<Database>('DATABASE');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that creates and returns a connection to MongoDB using Mongoose.
|
||||||
|
* @returns {mongoose.Connection | undefined} MongoDB connection or `undefined` if the connection is not enabled.
|
||||||
|
*/
|
||||||
export const dbserver = (() => {
|
export const dbserver = (() => {
|
||||||
if (db.ENABLED) {
|
if (db.ENABLED) {
|
||||||
|
/**
|
||||||
|
* Log message indicating an attempt to connect to MongoDB.
|
||||||
|
*/
|
||||||
logger.verbose('connecting');
|
logger.verbose('connecting');
|
||||||
const dbs = mongoose.createConnection(db.CONNECTION.URI, {
|
|
||||||
|
/**
|
||||||
|
* Options for the MongoDB connection.
|
||||||
|
* @type {mongoose.ConnectionOptions}
|
||||||
|
*/
|
||||||
|
const connectionOptions = {
|
||||||
dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api',
|
dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api',
|
||||||
});
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creation of the MongoDB connection.
|
||||||
|
* @type {mongoose.Connection}
|
||||||
|
*/
|
||||||
|
const dbs = mongoose.createConnection(db.CONNECTION.URI, connectionOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log message indicating the successful connection to MongoDB.
|
||||||
|
*/
|
||||||
logger.verbose('connected in ' + db.CONNECTION.URI);
|
logger.verbose('connected in ' + db.CONNECTION.URI);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informative log message about the connected database name.
|
||||||
|
*/
|
||||||
logger.info('ON - dbName: ' + dbs['$dbName']);
|
logger.info('ON - dbName: ' + dbs['$dbName']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event handler for the beforeExit process event.
|
||||||
|
*/
|
||||||
process.on('beforeExit', () => {
|
process.on('beforeExit', () => {
|
||||||
|
/**
|
||||||
|
* Log message indicating the destruction of the MongoDB connection instance.
|
||||||
|
*/
|
||||||
logger.verbose('instance destroyed');
|
logger.verbose('instance destroyed');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the MongoDB connection.
|
||||||
|
* @param {boolean} [force=false] - Indicates whether the destruction should be forced.
|
||||||
|
* @param {function(Error)} [callback] - Callback function to handle errors during destruction.
|
||||||
|
*/
|
||||||
dbserver.destroy(true, (error) => logger.error(error));
|
dbserver.destroy(true, (error) => logger.error(error));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MongoDB connection.
|
||||||
|
*/
|
||||||
return dbs;
|
return dbs;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -4,13 +4,24 @@ import { BufferJSON } from '@whiskeysockets/baileys';
|
|||||||
import { Redis } from '../config/env.config';
|
import { Redis } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing a Redis cache.
|
||||||
|
*/
|
||||||
export class RedisCache {
|
export class RedisCache {
|
||||||
|
/**
|
||||||
|
* Disconnects from the Redis server.
|
||||||
|
*/
|
||||||
async disconnect() {
|
async disconnect() {
|
||||||
await this.client.disconnect();
|
await this.client.disconnect();
|
||||||
this.statusConnection = false;
|
this.statusConnection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of RedisCache.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.logger.verbose('instance created');
|
this.logger.verbose('instance created');
|
||||||
|
|
||||||
process.on('beforeExit', async () => {
|
process.on('beforeExit', async () => {
|
||||||
this.logger.verbose('instance destroyed');
|
this.logger.verbose('instance destroyed');
|
||||||
if (this.statusConnection) {
|
if (this.statusConnection) {
|
||||||
@ -24,11 +35,19 @@ export class RedisCache {
|
|||||||
private instanceName: string;
|
private instanceName: string;
|
||||||
private redisEnv: Redis;
|
private redisEnv: Redis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reference for the Redis instance.
|
||||||
|
* @param {string} reference - The reference to set.
|
||||||
|
*/
|
||||||
public set reference(reference: string) {
|
public set reference(reference: string) {
|
||||||
this.logger.verbose('set reference: ' + reference);
|
this.logger.verbose('set reference: ' + reference);
|
||||||
this.instanceName = reference;
|
this.instanceName = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the Redis server.
|
||||||
|
* @param {Redis} redisEnv - The Redis configuration.
|
||||||
|
*/
|
||||||
public async connect(redisEnv: Redis) {
|
public async connect(redisEnv: Redis) {
|
||||||
this.logger.verbose('connecting');
|
this.logger.verbose('connecting');
|
||||||
this.client = createClient({ url: redisEnv.URI });
|
this.client = createClient({ url: redisEnv.URI });
|
||||||
@ -41,6 +60,10 @@ export class RedisCache {
|
|||||||
private readonly logger = new Logger(RedisCache.name);
|
private readonly logger = new Logger(RedisCache.name);
|
||||||
private client: RedisClientType;
|
private client: RedisClientType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves keys for the Redis instance.
|
||||||
|
* @returns {Promise<string[]>} An array of keys.
|
||||||
|
*/
|
||||||
public async instanceKeys(): Promise<string[]> {
|
public async instanceKeys(): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('instance keys: ' + this.redisEnv.PREFIX_KEY + ':*');
|
this.logger.verbose('instance keys: ' + this.redisEnv.PREFIX_KEY + ':*');
|
||||||
@ -50,6 +73,11 @@ export class RedisCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a specific key exists.
|
||||||
|
* @param {string} key - The key to check.
|
||||||
|
* @returns {Promise<boolean>} `true` if the key exists, otherwise `false`.
|
||||||
|
*/
|
||||||
public async keyExists(key?: string) {
|
public async keyExists(key?: string) {
|
||||||
if (key) {
|
if (key) {
|
||||||
this.logger.verbose('keyExists: ' + key);
|
this.logger.verbose('keyExists: ' + key);
|
||||||
@ -59,6 +87,12 @@ export class RedisCache {
|
|||||||
return !!(await this.instanceKeys()).find((i) => i === this.instanceName);
|
return !!(await this.instanceKeys()).find((i) => i === this.instanceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to Redis cache.
|
||||||
|
* @param {string} field - The field to write data to.
|
||||||
|
* @param {any} data - The data to write.
|
||||||
|
* @returns {Promise<boolean>} `true` if the write is successful, otherwise `false`.
|
||||||
|
*/
|
||||||
public async writeData(field: string, data: any) {
|
public async writeData(field: string, data: any) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('writeData: ' + field);
|
this.logger.verbose('writeData: ' + field);
|
||||||
@ -70,6 +104,11 @@ export class RedisCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data from Redis cache.
|
||||||
|
* @param {string} field - The field to read data from.
|
||||||
|
* @returns {Promise<any | null>} The data if found, otherwise `null`.
|
||||||
|
*/
|
||||||
public async readData(field: string) {
|
public async readData(field: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('readData: ' + field);
|
this.logger.verbose('readData: ' + field);
|
||||||
@ -87,6 +126,11 @@ export class RedisCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes data from Redis cache.
|
||||||
|
* @param {string} field - The field to remove data from.
|
||||||
|
* @returns {Promise<boolean>} `true` if the removal is successful, otherwise `false`.
|
||||||
|
*/
|
||||||
public async removeData(field: string) {
|
public async removeData(field: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('removeData: ' + field);
|
this.logger.verbose('removeData: ' + field);
|
||||||
@ -96,6 +140,11 @@ export class RedisCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all data associated with the Redis instance.
|
||||||
|
* @param {string} hash - The hash to delete, defaults to the instance name.
|
||||||
|
* @returns {Promise<boolean>} `true` if the deletion is successful, otherwise `false`.
|
||||||
|
*/
|
||||||
public async delAll(hash?: string) {
|
public async delAll(hash?: string) {
|
||||||
try {
|
try {
|
||||||
this.logger.verbose('instance delAll: ' + hash);
|
this.logger.verbose('instance delAll: ' + hash);
|
||||||
|
@ -4,23 +4,35 @@ import { Server as SocketIO } from 'socket.io';
|
|||||||
import { configService, Cors, Websocket } from '../config/env.config';
|
import { configService, Cors, Websocket } from '../config/env.config';
|
||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
|
|
||||||
|
// Create a logger instance specifically for socket-related logs.
|
||||||
const logger = new Logger('Socket');
|
const logger = new Logger('Socket');
|
||||||
|
|
||||||
|
// Declare the Socket.IO instance.
|
||||||
let io: SocketIO;
|
let io: SocketIO;
|
||||||
|
|
||||||
const cors = configService.get<Cors>('CORS').ORIGIN;
|
// Get the allowed origins from the configuration.
|
||||||
|
const corsOrigins = configService.get<Cors>('CORS').ORIGIN;
|
||||||
|
|
||||||
export const initIO = (httpServer: Server) => {
|
/**
|
||||||
|
* Initialize Socket.IO with the provided HTTP server.
|
||||||
|
* @param {Server} httpServer - The HTTP server to attach Socket.IO to.
|
||||||
|
* @returns {SocketIO | null} The Socket.IO instance if enabled, or null if disabled.
|
||||||
|
*/
|
||||||
|
export const initIO = (httpServer: Server): SocketIO | null => {
|
||||||
|
// Check if WebSocket is enabled in the configuration.
|
||||||
if (configService.get<Websocket>('WEBSOCKET')?.ENABLED) {
|
if (configService.get<Websocket>('WEBSOCKET')?.ENABLED) {
|
||||||
|
// Create a new Socket.IO instance with CORS configuration.
|
||||||
io = new SocketIO(httpServer, {
|
io = new SocketIO(httpServer, {
|
||||||
cors: {
|
cors: {
|
||||||
origin: cors,
|
origin: corsOrigins,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle the 'connection' event when a user connects.
|
||||||
io.on('connection', (socket) => {
|
io.on('connection', (socket) => {
|
||||||
logger.info('User connected');
|
logger.info('User connected');
|
||||||
|
|
||||||
|
// Handle the 'disconnect' event when a user disconnects.
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
logger.info('User disconnected');
|
logger.info('User disconnected');
|
||||||
});
|
});
|
||||||
@ -29,12 +41,20 @@ export const initIO = (httpServer: Server) => {
|
|||||||
logger.info('Socket.io initialized');
|
logger.info('Socket.io initialized');
|
||||||
return io;
|
return io;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WebSocket is disabled, return null.
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Socket.IO instance.
|
||||||
|
* @throws {Error} Throws an error if Socket.IO is not initialized.
|
||||||
|
* @returns {SocketIO} The initialized Socket.IO instance.
|
||||||
|
*/
|
||||||
export const getIO = (): SocketIO => {
|
export const getIO = (): SocketIO => {
|
||||||
logger.verbose('Getting Socket.io');
|
logger.verbose('Getting Socket.io');
|
||||||
|
|
||||||
|
// If Socket.IO is not initialized, throw an error.
|
||||||
if (!io) {
|
if (!io) {
|
||||||
logger.error('Socket.io not initialized');
|
logger.error('Socket.io not initialized');
|
||||||
throw new Error('Socket.io not initialized');
|
throw new Error('Socket.io not initialized');
|
||||||
|
26
src/main.ts
26
src/main.ts
@ -16,16 +16,27 @@ import { ServerUP } from './utils/server-up';
|
|||||||
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
import { HttpStatus, router } from './whatsapp/routers/index.router';
|
||||||
import { waMonitor } from './whatsapp/whatsapp.module';
|
import { waMonitor } from './whatsapp/whatsapp.module';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes WhatsApp monitoring.
|
||||||
|
*/
|
||||||
function initWA() {
|
function initWA() {
|
||||||
waMonitor.loadInstance();
|
waMonitor.loadInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap the application.
|
||||||
|
*/
|
||||||
function bootstrap() {
|
function bootstrap() {
|
||||||
const logger = new Logger('SERVER');
|
const logger = new Logger('SERVER');
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
|
/**
|
||||||
|
* Determine if the request origin is allowed by CORS.
|
||||||
|
* @param requestOrigin The origin of the incoming request.
|
||||||
|
* @param callback The callback function to invoke.
|
||||||
|
*/
|
||||||
origin(requestOrigin, callback) {
|
origin(requestOrigin, callback) {
|
||||||
const { ORIGIN } = configService.get<Cors>('CORS');
|
const { ORIGIN } = configService.get<Cors>('CORS');
|
||||||
if (ORIGIN.includes('*')) {
|
if (ORIGIN.includes('*')) {
|
||||||
@ -53,12 +64,19 @@ function bootstrap() {
|
|||||||
app.use('/', router);
|
app.use('/', router);
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
|
/**
|
||||||
|
* Error handling middleware.
|
||||||
|
* @param err The error object.
|
||||||
|
* @param req The Express request object.
|
||||||
|
* @param res The Express response object.
|
||||||
|
* @param next The next function to invoke.
|
||||||
|
*/
|
||||||
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
(err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
const webhook = configService.get<Webhook>('WEBHOOK');
|
const webhook = configService.get<Webhook>('WEBHOOK');
|
||||||
|
|
||||||
if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) {
|
if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) {
|
||||||
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
const tzoffset = new Date().getTimezoneOffset() * 60000; // offset in milliseconds
|
||||||
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
||||||
const now = localISOTime;
|
const now = localISOTime;
|
||||||
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
|
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
|
||||||
@ -98,6 +116,12 @@ function bootstrap() {
|
|||||||
|
|
||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 404 Not Found middleware.
|
||||||
|
* @param req The Express request object.
|
||||||
|
* @param res The Express response object.
|
||||||
|
* @param next The next function to invoke.
|
||||||
|
*/
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const { method, url } = req;
|
const { method, url } = req;
|
||||||
|
|
||||||
|
@ -8,22 +8,38 @@ import { configService, SslConf } from '../config/env.config';
|
|||||||
export class ServerUP {
|
export class ServerUP {
|
||||||
static #app: Express;
|
static #app: Express;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Express application instance.
|
||||||
|
* @param {Express} e - The Express application instance.
|
||||||
|
*/
|
||||||
static set app(e: Express) {
|
static set app(e: Express) {
|
||||||
this.#app = e;
|
this.#app = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an HTTPS server instance with SSL configuration.
|
||||||
|
* @returns {https.Server} An HTTPS server instance.
|
||||||
|
*/
|
||||||
static get https() {
|
static get https() {
|
||||||
|
// Retrieve SSL certificate and private key paths from configuration.
|
||||||
const { FULLCHAIN, PRIVKEY } = configService.get<SslConf>('SSL_CONF');
|
const { FULLCHAIN, PRIVKEY } = configService.get<SslConf>('SSL_CONF');
|
||||||
|
|
||||||
|
// Create an HTTPS server using the SSL certificate and private key.
|
||||||
return https.createServer(
|
return https.createServer(
|
||||||
{
|
{
|
||||||
cert: readFileSync(FULLCHAIN),
|
cert: readFileSync(FULLCHAIN), // Read SSL certificate file.
|
||||||
key: readFileSync(PRIVKEY),
|
key: readFileSync(PRIVKEY), // Read private key file.
|
||||||
},
|
},
|
||||||
ServerUP.#app,
|
ServerUP.#app,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an HTTP server instance.
|
||||||
|
* @returns {http.Server} An HTTP server instance.
|
||||||
|
*/
|
||||||
static get http() {
|
static get http() {
|
||||||
|
// Create an HTTP server using the Express application instance.
|
||||||
return http.createServer(ServerUP.#app);
|
return http.createServer(ServerUP.#app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,25 @@ import { configService, Database } from '../config/env.config';
|
|||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
import { dbserver } from '../libs/db.connect';
|
import { dbserver } from '../libs/db.connect';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a function to handle AuthenticationState and credentials using a MongoDB collection.
|
||||||
|
* @param {string} coll - The name of the MongoDB collection.
|
||||||
|
* @returns {Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }>} An object with AuthenticationState and saveCreds function.
|
||||||
|
*/
|
||||||
export async function useMultiFileAuthStateDb(
|
export async function useMultiFileAuthStateDb(
|
||||||
coll: string,
|
coll: string,
|
||||||
): Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }> {
|
): Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }> {
|
||||||
const logger = new Logger(useMultiFileAuthStateDb.name);
|
const logger = new Logger(useMultiFileAuthStateDb.name);
|
||||||
|
|
||||||
|
// Get the MongoDB client from the database server connection.
|
||||||
const client = dbserver.getClient();
|
const client = dbserver.getClient();
|
||||||
|
|
||||||
|
// Construct the collection name based on the database prefix.
|
||||||
const collection = client
|
const collection = client
|
||||||
.db(configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances')
|
.db(configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||||
.collection(coll);
|
.collection(coll);
|
||||||
|
|
||||||
|
// Helper function to write data to the MongoDB collection.
|
||||||
const writeData = async (data: any, key: string): Promise<any> => {
|
const writeData = async (data: any, key: string): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
await client.connect();
|
await client.connect();
|
||||||
@ -33,6 +41,7 @@ export async function useMultiFileAuthStateDb(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to read data from the MongoDB collection.
|
||||||
const readData = async (key: string): Promise<any> => {
|
const readData = async (key: string): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
await client.connect();
|
await client.connect();
|
||||||
@ -44,6 +53,7 @@ export async function useMultiFileAuthStateDb(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to remove data from the MongoDB collection.
|
||||||
const removeData = async (key: string) => {
|
const removeData = async (key: string) => {
|
||||||
try {
|
try {
|
||||||
await client.connect();
|
await client.connect();
|
||||||
@ -53,6 +63,7 @@ export async function useMultiFileAuthStateDb(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initialize AuthenticationCreds using stored or default values.
|
||||||
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -60,8 +71,6 @@ export async function useMultiFileAuthStateDb(
|
|||||||
creds,
|
creds,
|
||||||
keys: {
|
keys: {
|
||||||
get: async (type, ids: string[]) => {
|
get: async (type, ids: string[]) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
const data: { [_: string]: SignalDataTypeMap[type] } = {};
|
const data: { [_: string]: SignalDataTypeMap[type] } = {};
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
ids.map(async (id) => {
|
ids.map(async (id) => {
|
||||||
@ -90,6 +99,7 @@ export async function useMultiFileAuthStateDb(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Save the credentials to the MongoDB collection.
|
||||||
saveCreds: async () => {
|
saveCreds: async () => {
|
||||||
return writeData(creds, 'creds');
|
return writeData(creds, 'creds');
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,11 @@ import {
|
|||||||
import { Logger } from '../config/logger.config';
|
import { Logger } from '../config/logger.config';
|
||||||
import { RedisCache } from '../libs/redis.client';
|
import { RedisCache } from '../libs/redis.client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a function to handle AuthenticationState and credentials using a Redis cache.
|
||||||
|
* @param {RedisCache} cache - The RedisCache instance to store and retrieve data.
|
||||||
|
* @returns {Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }>} An object with AuthenticationState and saveCreds function.
|
||||||
|
*/
|
||||||
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
||||||
state: AuthenticationState;
|
state: AuthenticationState;
|
||||||
saveCreds: () => Promise<void>;
|
saveCreds: () => Promise<void>;
|
||||||
@ -27,11 +32,12 @@ export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
|||||||
try {
|
try {
|
||||||
return await cache.readData(key);
|
return await cache.readData(key);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error({ readData: 'writeData', error });
|
logger.error({ readData: 'readData', error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to remove data from the Redis cache.
|
||||||
const removeData = async (key: string) => {
|
const removeData = async (key: string) => {
|
||||||
try {
|
try {
|
||||||
return await cache.removeData(key);
|
return await cache.removeData(key);
|
||||||
@ -40,6 +46,7 @@ export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initialize AuthenticationCreds using stored or default values.
|
||||||
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -77,6 +84,7 @@ export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Save the credentials to the Redis cache.
|
||||||
saveCreds: async () => {
|
saveCreds: async () => {
|
||||||
return await writeData(creds, 'creds');
|
return await writeData(creds, 'creds');
|
||||||
},
|
},
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
|
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a utility function to generate JSON schema for non-empty properties.
|
||||||
|
*
|
||||||
|
* @param {string[]} propertyNames - The names of properties to check for non-emptiness.
|
||||||
|
* @returns {JSONSchema7} A JSON schema with non-empty property checks.
|
||||||
|
*/
|
||||||
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
||||||
const properties = {};
|
const properties = {};
|
||||||
propertyNames.forEach(
|
propertyNames.forEach(
|
||||||
(property) =>
|
(property) =>
|
||||||
(properties[property] = {
|
(properties[property] = {
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
description: `The "${property}" cannot be empty`,
|
description: `The "${property}" cannot be empty`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
if: {
|
if: {
|
||||||
@ -21,6 +27,11 @@ const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Instance Schema
|
// Instance Schema
|
||||||
|
/**
|
||||||
|
* JSON schema for an instance with properties like instanceName, webhook, and more.
|
||||||
|
*
|
||||||
|
* @type {JSONSchema7}
|
||||||
|
*/
|
||||||
export const instanceNameSchema: JSONSchema7 = {
|
export const instanceNameSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -11,6 +11,9 @@ import { InstanceDto } from '../dto/instance.dto';
|
|||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the payload of a JWT token.
|
||||||
|
*/
|
||||||
export type JwtPayload = {
|
export type JwtPayload = {
|
||||||
instanceName: string;
|
instanceName: string;
|
||||||
apiName: string;
|
apiName: string;
|
||||||
@ -19,19 +22,36 @@ export type JwtPayload = {
|
|||||||
tokenId: string;
|
tokenId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the structure of an old JWT token.
|
||||||
|
*/
|
||||||
export class OldToken {
|
export class OldToken {
|
||||||
oldToken: string;
|
oldToken: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Service responsible for authentication-related operations.
|
||||||
|
*/
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
/**
|
||||||
|
* Creates an instance of AuthService.
|
||||||
|
* @param configService The configuration service.
|
||||||
|
* @param waMonitor The monitoring service for WhatsApp instances.
|
||||||
|
* @param repository The repository manager for database operations.
|
||||||
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly waMonitor: WAMonitoringService,
|
private readonly waMonitor: WAMonitoringService,
|
||||||
private readonly repository: RepositoryBroker,
|
private readonly repository: RepositoryBroker,
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
private readonly logger = new Logger(AuthService.name);
|
private readonly logger = new Logger(AuthService.name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a JWT token for a given instance.
|
||||||
|
* @param instance The instance DTO for which to generate the token.
|
||||||
|
* @returns An object containing the generated JWT token.
|
||||||
|
* @throws BadRequestException if an error occurs during token generation.
|
||||||
|
*/
|
||||||
private async jwt(instance: InstanceDto) {
|
private async jwt(instance: InstanceDto) {
|
||||||
const jwtOpts = this.configService.get<Auth>('AUTHENTICATION').JWT;
|
const jwtOpts = this.configService.get<Auth>('AUTHENTICATION').JWT;
|
||||||
const token = sign(
|
const token = sign(
|
||||||
@ -61,6 +81,13 @@ export class AuthService {
|
|||||||
return { jwt: token };
|
return { jwt: token };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an API key for a given instance.
|
||||||
|
* @param instance The instance DTO for which to generate the API key.
|
||||||
|
* @param token (Optional) An existing API key to use.
|
||||||
|
* @returns An object containing the generated or defined API key.
|
||||||
|
* @throws BadRequestException if an error occurs during API key generation.
|
||||||
|
*/
|
||||||
private async apikey(instance: InstanceDto, token?: string) {
|
private async apikey(instance: InstanceDto, token?: string) {
|
||||||
const apikey = token ? token : v4().toUpperCase();
|
const apikey = token ? token : v4().toUpperCase();
|
||||||
|
|
||||||
@ -81,6 +108,11 @@ export class AuthService {
|
|||||||
return { apikey };
|
return { apikey };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for the existence of a duplicate token among instances.
|
||||||
|
* @param token The token to check for duplication.
|
||||||
|
* @returns `true` if the token is not duplicated among instances, otherwise throws a BadRequestException.
|
||||||
|
*/
|
||||||
public async checkDuplicateToken(token: string) {
|
public async checkDuplicateToken(token: string) {
|
||||||
const instances = await this.waMonitor.instanceInfo();
|
const instances = await this.waMonitor.instanceInfo();
|
||||||
|
|
||||||
@ -97,6 +129,12 @@ export class AuthService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an authentication hash (JWT token or API key) based on the authentication type.
|
||||||
|
* @param instance The instance DTO for which to generate the hash.
|
||||||
|
* @param token (Optional) An existing token to use (for API key generation).
|
||||||
|
* @returns An object containing the generated authentication hash (JWT token or API key).
|
||||||
|
*/
|
||||||
public async generateHash(instance: InstanceDto, token?: string) {
|
public async generateHash(instance: InstanceDto, token?: string) {
|
||||||
const options = this.configService.get<Auth>('AUTHENTICATION');
|
const options = this.configService.get<Auth>('AUTHENTICATION');
|
||||||
|
|
||||||
@ -105,6 +143,12 @@ export class AuthService {
|
|||||||
return (await this[options.TYPE](instance, token)) as { jwt: string } | { apikey: string };
|
return (await this[options.TYPE](instance, token)) as { jwt: string } | { apikey: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes a JWT token based on an old JWT token.
|
||||||
|
* @param oldToken An old JWT token to refresh.
|
||||||
|
* @returns An object containing the refreshed JWT token and instanceName.
|
||||||
|
* @throws BadRequestException if the oldToken is invalid or an error occurs during token refresh.
|
||||||
|
*/
|
||||||
public async refreshToken({ oldToken }: OldToken) {
|
public async refreshToken({ oldToken }: OldToken) {
|
||||||
this.logger.verbose('refreshing token');
|
this.logger.verbose('refreshing token');
|
||||||
|
|
||||||
|
@ -24,41 +24,95 @@ import {
|
|||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
import { WAStartupService } from './whatsapp.service';
|
import { WAStartupService } from './whatsapp.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a service for monitoring WhatsApp instances.
|
||||||
|
*/
|
||||||
export class WAMonitoringService {
|
export class WAMonitoringService {
|
||||||
|
/**
|
||||||
|
* Creates an instance of WAMonitoringService.
|
||||||
|
* @param {EventEmitter2} eventEmitter - Event emitter for handling events.
|
||||||
|
* @param {ConfigService} configService - Configuration service.
|
||||||
|
* @param {RepositoryBroker} repository - Repository broker for database operations.
|
||||||
|
* @param {RedisCache} cache - Redis cache for storing data.
|
||||||
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private readonly eventEmitter: EventEmitter2,
|
private readonly eventEmitter: EventEmitter2,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly repository: RepositoryBroker,
|
private readonly repository: RepositoryBroker,
|
||||||
private readonly cache: RedisCache,
|
private readonly cache: RedisCache,
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* Logger instance for logging service activities.
|
||||||
|
* @private
|
||||||
|
* @type {Logger}
|
||||||
|
*/
|
||||||
this.logger.verbose('instance created');
|
this.logger.verbose('instance created');
|
||||||
|
|
||||||
|
// Initialize service functionalities
|
||||||
this.removeInstance();
|
this.removeInstance();
|
||||||
this.noConnection();
|
this.noConnection();
|
||||||
this.delInstanceFiles();
|
this.delInstanceFiles();
|
||||||
|
|
||||||
|
// Load configuration settings
|
||||||
Object.assign(this.db, configService.get<Database>('DATABASE'));
|
Object.assign(this.db, configService.get<Database>('DATABASE'));
|
||||||
Object.assign(this.redis, configService.get<Redis>('REDIS'));
|
Object.assign(this.redis, configService.get<Redis>('REDIS'));
|
||||||
|
|
||||||
|
// Initialize the MongoDB database instance
|
||||||
this.dbInstance = this.db.ENABLED
|
this.dbInstance = this.db.ENABLED
|
||||||
? this.repository.dbServer?.db(this.db.CONNECTION.DB_PREFIX_NAME + '-instances')
|
? this.repository.dbServer?.db(this.db.CONNECTION.DB_PREFIX_NAME + '-instances')
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration settings for the database.
|
||||||
|
* @private
|
||||||
|
* @type {Partial<Database>}
|
||||||
|
*/
|
||||||
private readonly db: Partial<Database> = {};
|
private readonly db: Partial<Database> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration settings for Redis.
|
||||||
|
* @private
|
||||||
|
* @type {Partial<Redis>}
|
||||||
|
*/
|
||||||
private readonly redis: Partial<Redis> = {};
|
private readonly redis: Partial<Redis> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database instance for instance management.
|
||||||
|
* @private
|
||||||
|
* @type {Db}
|
||||||
|
*/
|
||||||
private dbInstance: Db;
|
private dbInstance: Db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database store connection.
|
||||||
|
* @private
|
||||||
|
* @type {Db}
|
||||||
|
*/
|
||||||
private dbStore = dbserver;
|
private dbStore = dbserver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger instance for logging service activities.
|
||||||
|
* @private
|
||||||
|
* @type {Logger}
|
||||||
|
*/
|
||||||
private readonly logger = new Logger(WAMonitoringService.name);
|
private readonly logger = new Logger(WAMonitoringService.name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dictionary of WhatsApp instances being monitored.
|
||||||
|
* @public
|
||||||
|
* @type {Record<string, WAStartupService>}
|
||||||
|
*/
|
||||||
public readonly waInstances: Record<string, WAStartupService> = {};
|
public readonly waInstances: Record<string, WAStartupService> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates a timer to remove an instance after a specific time of inactivity.
|
||||||
|
* @param {string} instance - The name of the instance to monitor.
|
||||||
|
*/
|
||||||
public delInstanceTime(instance: string) {
|
public delInstanceTime(instance: string) {
|
||||||
const time = this.configService.get<DelInstance>('DEL_INSTANCE');
|
const time = this.configService.get<DelInstance>('DEL_INSTANCE');
|
||||||
if (typeof time === 'number' && time > 0) {
|
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}" doesn't have a connection, will be removed in ${time} minutes`);
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (this.waInstances[instance]?.connectionStatus?.state !== 'open') {
|
if (this.waInstances[instance]?.connectionStatus?.state !== 'open') {
|
||||||
@ -75,67 +129,74 @@ export class WAMonitoringService {
|
|||||||
}, 1000 * 60 * time);
|
}, 1000 * 60 * time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* ocultado por francis inicio
|
/* ocultado por francis inicio
|
||||||
public async instanceInfo(instanceName?: string) {
|
public async instanceInfo(instanceName?: string) {
|
||||||
this.logger.verbose('get instance info');
|
this.logger.verbose('get instance info');
|
||||||
|
|
||||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
|
|
||||||
const instances: any[] = await Promise.all(
|
const instances: any[] = await Promise.all(
|
||||||
Object.entries(this.waInstances).map(async ([key, value]) => {
|
Object.entries(this.waInstances).map(async ([key, value]) => {
|
||||||
const status = value?.connectionStatus?.state || 'unknown';
|
const status = value?.connectionStatus?.state || 'unknown';
|
||||||
|
|
||||||
if (status === 'unknown') {
|
if (status === 'unknown') {
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
if (status === 'open') {
|
|
||||||
this.logger.verbose('instance: ' + key + ' - connectionStatus: open');
|
|
||||||
}
|
|
||||||
|
|
||||||
const instanceData: any = {
|
|
||||||
instance: {
|
|
||||||
instanceName: key,
|
|
||||||
owner: value.wuid,
|
|
||||||
profileName: (await value.getProfileName()) || 'not loaded',
|
|
||||||
profilePictureUrl: value.profilePictureUrl,
|
|
||||||
profileStatus: (await value.getProfileStatus()) || '',
|
|
||||||
status: status,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
|
||||||
instanceData.instance.serverUrl = urlServer;
|
|
||||||
instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey;
|
|
||||||
|
|
||||||
const findChatwoot = await this.waInstances[key].findChatwoot();
|
|
||||||
if (findChatwoot && findChatwoot.enabled) {
|
|
||||||
instanceData.instance.chatwoot = {
|
|
||||||
...findChatwoot,
|
|
||||||
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (status === 'open') {
|
||||||
return instanceData;
|
this.logger.verbose('instance: ' + key + ' - connectionStatus: open');
|
||||||
}),
|
}
|
||||||
).then((results) => results.filter((instance) => instance !== null));
|
|
||||||
|
const instanceData: any = {
|
||||||
this.logger.verbose('return instance info: ' + instances.length);
|
instance: {
|
||||||
|
instanceName: key,
|
||||||
if (instanceName) {
|
owner: value.wuid,
|
||||||
const instance = instances.find((i) => i.instance.instanceName === instanceName);
|
profileName: (await value.getProfileName()) || 'not loaded',
|
||||||
return instance || [];
|
profilePictureUrl: value.profilePictureUrl,
|
||||||
|
profileStatus: (await value.getProfileStatus()) || '',
|
||||||
|
status: status,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) {
|
||||||
|
instanceData.instance.serverUrl = urlServer;
|
||||||
|
instanceData.instance.apikey = (await this.repository.auth.find(key))?.apikey;
|
||||||
|
|
||||||
|
const findChatwoot = await this.waInstances[key].findChatwoot();
|
||||||
|
if (findChatwoot && findChatwoot.enabled) {
|
||||||
|
instanceData.instance.chatwoot = {
|
||||||
|
...findChatwoot,
|
||||||
|
webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceData;
|
||||||
|
}),
|
||||||
|
).then((results) => results.filter((instance) => instance !== null));
|
||||||
|
|
||||||
|
this.logger.verbose('return instance info: ' + instances.length);
|
||||||
|
|
||||||
|
if (instanceName) {
|
||||||
|
const instance = instances.find((i) => i.instance.instanceName === instanceName);
|
||||||
|
return instance || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ocultado por francis fim */
|
||||||
|
|
||||||
return instances;
|
// inserido por francis inicio
|
||||||
}
|
|
||||||
|
|
||||||
ocultado por francis fim */
|
|
||||||
|
|
||||||
// inserido por francis inicio
|
/**
|
||||||
|
* Retrieves information about WhatsApp instances, including details about the connection, owner, and status.
|
||||||
public async instanceInfo(instanceName?: string) {
|
* @param instanceName The name of the WhatsApp instance to retrieve information for. Optional.
|
||||||
|
* @returns An array of objects containing information about WhatsApp instances.
|
||||||
|
* @throws NotFoundException If `instanceName` is specified, and the instance is not found.
|
||||||
|
*/
|
||||||
|
public async instanceInfo(instanceName?: string) {
|
||||||
this.logger.verbose('get instance info');
|
this.logger.verbose('get instance info');
|
||||||
if (instanceName && !this.waInstances[instanceName]) {
|
if (instanceName && !this.waInstances[instanceName]) {
|
||||||
throw new NotFoundException(`Instance "${instanceName}" not found`);
|
throw new NotFoundException(`Instance "${instanceName}" not found`);
|
||||||
@ -212,8 +273,7 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// inserido por francis fim
|
// inserido por francis fim
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -221,6 +281,9 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a cron job to delete instance files at regular intervals.
|
||||||
|
*/
|
||||||
private delInstanceFiles() {
|
private delInstanceFiles() {
|
||||||
this.logger.verbose('cron to delete instance files started');
|
this.logger.verbose('cron to delete instance files started');
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
@ -255,6 +318,10 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
}, 3600 * 1000 * 2);
|
}, 3600 * 1000 * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans data for a specific WhatsApp instance, including the database, cache, or files, depending on the configuration.
|
||||||
|
* @param instanceName The name of the WhatsApp instance to clean up.
|
||||||
|
*/
|
||||||
public async cleaningUp(instanceName: string) {
|
public async cleaningUp(instanceName: string) {
|
||||||
this.logger.verbose('cleaning up instance: ' + instanceName);
|
this.logger.verbose('cleaning up instance: ' + instanceName);
|
||||||
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) {
|
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) {
|
||||||
@ -278,6 +345,11 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true });
|
rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans storage files for a specific WhatsApp instance, including messages, contacts, etc.
|
||||||
|
*
|
||||||
|
* @param instanceName The name of the WhatsApp instance to clean storage files for.
|
||||||
|
*/
|
||||||
public async cleaningStoreFiles(instanceName: string) {
|
public async cleaningStoreFiles(instanceName: string) {
|
||||||
if (!this.db.ENABLED) {
|
if (!this.db.ENABLED) {
|
||||||
this.logger.verbose('cleaning store files instance: ' + instanceName);
|
this.logger.verbose('cleaning store files instance: ' + instanceName);
|
||||||
@ -314,7 +386,9 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Loads WhatsApp instances based on storage settings, such as Redis, a database, or local files.
|
||||||
|
*/
|
||||||
public async loadInstance() {
|
public async loadInstance() {
|
||||||
this.logger.verbose('Loading instances');
|
this.logger.verbose('Loading instances');
|
||||||
|
|
||||||
@ -330,7 +404,11 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Configures a new WhatsApp instance and connects it to the WhatsApp service.
|
||||||
|
*
|
||||||
|
* @param name The name of the WhatsApp instance to configure.
|
||||||
|
*/
|
||||||
private async setInstance(name: string) {
|
private async setInstance(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;
|
instance.instanceName = name;
|
||||||
@ -394,7 +472,11 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Removes a WhatsApp instance from memory and performs associated data cleanup.
|
||||||
|
*
|
||||||
|
* @param instanceName The name of the WhatsApp instance to remove.
|
||||||
|
*/
|
||||||
private removeInstance() {
|
private removeInstance() {
|
||||||
this.eventEmitter.on('remove.instance', async (instanceName: string) => {
|
this.eventEmitter.on('remove.instance', async (instanceName: string) => {
|
||||||
this.logger.verbose('remove instance: ' + instanceName);
|
this.logger.verbose('remove instance: ' + instanceName);
|
||||||
@ -423,7 +505,9 @@ public async instanceInfo(instanceName?: string) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Checks for WhatsApp instances without a connection and takes appropriate actions, such as logout and connection closure.
|
||||||
|
*/
|
||||||
private noConnection() {
|
private noConnection() {
|
||||||
this.logger.verbose('checking instances without connection');
|
this.logger.verbose('checking instances without connection');
|
||||||
this.eventEmitter.on('no.connection', async (instanceName) => {
|
this.eventEmitter.on('no.connection', async (instanceName) => {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-namespace */
|
/* eslint-disable @typescript-eslint/no-namespace */
|
||||||
import { AuthenticationState, WAConnectionState } from '@whiskeysockets/baileys';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of various application events.
|
||||||
|
*/
|
||||||
export enum Events {
|
export enum Events {
|
||||||
APPLICATION_STARTUP = 'application.startup',
|
APPLICATION_STARTUP = 'application.startup',
|
||||||
QRCODE_UPDATED = 'qrcode.updated',
|
QRCODE_UPDATED = 'qrcode.updated',
|
||||||
@ -28,13 +30,23 @@ export enum Events {
|
|||||||
CHAMA_AI_ACTION = 'chama-ai.action',
|
CHAMA_AI_ACTION = 'chama-ai.action',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace containing various WhatsApp-related types.
|
||||||
|
*/
|
||||||
export declare namespace wa {
|
export declare namespace wa {
|
||||||
|
/**
|
||||||
|
* Represents a QR code for pairing with WhatsApp.
|
||||||
|
*/
|
||||||
export type QrCode = {
|
export type QrCode = {
|
||||||
count?: number;
|
count?: number;
|
||||||
pairingCode?: string;
|
pairingCode?: string;
|
||||||
base64?: string;
|
base64?: string;
|
||||||
code?: string;
|
code?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents information about a WhatsApp instance.
|
||||||
|
*/
|
||||||
export type Instance = {
|
export type Instance = {
|
||||||
qrcode?: QrCode;
|
qrcode?: QrCode;
|
||||||
pairingCode?: string;
|
pairingCode?: string;
|
||||||
@ -45,6 +57,9 @@ export declare namespace wa {
|
|||||||
profilePictureUrl?: string;
|
profilePictureUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local webhook settings.
|
||||||
|
*/
|
||||||
export type LocalWebHook = {
|
export type LocalWebHook = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
@ -52,6 +67,9 @@ export declare namespace wa {
|
|||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local Chatwoot settings.
|
||||||
|
*/
|
||||||
export type LocalChatwoot = {
|
export type LocalChatwoot = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
account_id?: string;
|
account_id?: string;
|
||||||
@ -64,6 +82,9 @@ export declare namespace wa {
|
|||||||
conversation_pending?: boolean;
|
conversation_pending?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local settings.
|
||||||
|
*/
|
||||||
export type LocalSettings = {
|
export type LocalSettings = {
|
||||||
reject_call?: boolean;
|
reject_call?: boolean;
|
||||||
msg_call?: string;
|
msg_call?: string;
|
||||||
@ -73,22 +94,34 @@ export declare namespace wa {
|
|||||||
read_status?: boolean;
|
read_status?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local WebSocket settings.
|
||||||
|
*/
|
||||||
export type LocalWebsocket = {
|
export type LocalWebsocket = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local RabbitMQ settings.
|
||||||
|
*/
|
||||||
export type LocalRabbitmq = {
|
export type LocalRabbitmq = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
events?: string[];
|
events?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a session within a Typebot instance.
|
||||||
|
*/
|
||||||
type Session = {
|
type Session = {
|
||||||
remoteJid?: string;
|
remoteJid?: string;
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
createdAt?: number;
|
createdAt?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local Typebot settings.
|
||||||
|
*/
|
||||||
export type LocalTypebot = {
|
export type LocalTypebot = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
@ -101,11 +134,17 @@ export declare namespace wa {
|
|||||||
sessions?: Session[];
|
sessions?: Session[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local proxy settings.
|
||||||
|
*/
|
||||||
export type LocalProxy = {
|
export type LocalProxy = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents local Chamaai settings.
|
||||||
|
*/
|
||||||
export type LocalChamaai = {
|
export type LocalChamaai = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
@ -114,17 +153,29 @@ export declare namespace wa {
|
|||||||
answerByAudio?: boolean;
|
answerByAudio?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the state of a connection with a WhatsApp instance.
|
||||||
|
*/
|
||||||
export type StateConnection = {
|
export type StateConnection = {
|
||||||
instance?: string;
|
instance?: string;
|
||||||
state?: WAConnectionState | 'refused';
|
state?: WAConnectionState | 'refused';
|
||||||
statusReason?: number;
|
statusReason?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a status message type.
|
||||||
|
*/
|
||||||
export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED';
|
export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of media message types.
|
||||||
|
*/
|
||||||
export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage'];
|
export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of message subtype types.
|
||||||
|
*/
|
||||||
export const MessageSubtype = [
|
export const MessageSubtype = [
|
||||||
'ephemeralMessage',
|
'ephemeralMessage',
|
||||||
'documentWithCaptionMessage',
|
'documentWithCaptionMessage',
|
||||||
|
Loading…
Reference in New Issue
Block a user