first commit

This commit is contained in:
2026-07-16 20:48:43 -03:00
commit 5696cee264
1111 changed files with 322270 additions and 0 deletions
@@ -0,0 +1,87 @@
import {
FindWapServerParams,
IWapServer,
IWapServerAdapter,
PaginateWapServerParams,
PaginateWapServerResults,
} from "./WapServer.Interface";
import { Document, Model, Schema, model, FilterQuery } from "mongoose";
export interface IWapServerDocument extends Omit<IWapServer, "id">, Document {}
export class WapServerAdapterMongoose implements IWapServerAdapter {
schema: Schema;
serverList: Model<IWapServerDocument>;
constructor() {
this.schema = new Schema({
name: { type: String, required: false },
description: { type: String, required: false },
ipv4: { type: String, required: true },
ipv6: { type: String, required: false },
countBots: { type: Number, required: true, default: 0 },
maxBots: { type: Number, required: true, default: 20 },
active: { type: Boolean, required: true, default: true },
port: { type: Number, required: true, default: 3000 },
});
this.serverList = model<IWapServerDocument>("WapServer", this.schema);
}
public async find(data: FindWapServerParams): Promise<IWapServer[]> {
return this.serverList.find(data).exec();
}
public async findOne(data: FindWapServerParams): Promise<IWapServerDocument | null> {
return this.serverList.findOne(data).exec();
}
private buildSearchCriteria(filters: FindWapServerParams): FilterQuery<IWapServerDocument> {
const searchCriteria: FilterQuery<IWapServerDocument> = {};
if (filters.id) searchCriteria._id = filters.id;
if (filters.name) {
searchCriteria.name = { $regex: filters.name, $options: "i" };
}
if (filters.description) {
searchCriteria.description = { $regex: filters.description, $options: "i" };
}
if (filters.active !== undefined) {
searchCriteria.active = filters.active;
}
if (filters.countBotsFrom) {
searchCriteria.countBots = { $gte: filters.countBotsFrom };
}
if (filters.countBotsTo) {
searchCriteria.countBots = { $lte: filters.countBotsTo };
}
return searchCriteria;
}
public async paginate(filters: PaginateWapServerParams): Promise<PaginateWapServerResults> {
const searchCriteria = this.buildSearchCriteria(filters);
const count = await this.serverList.countDocuments(searchCriteria).exec();
const skip = (filters.page - 1) * filters.limit;
const results = await this.serverList
.find(searchCriteria)
.skip(skip)
.limit(filters.limit)
.sort({ createdAt: -1 })
.exec();
let pages = Math.ceil(count / filters.limit);
if (pages == 0) {
pages = 1;
}
return { data: results, page: filters.page, pages: pages };
}
}
@@ -0,0 +1,143 @@
import { IPayload } from "../SysAdminPayload/SysAdminPayload.interface";
import { IWapServerDocument } from "./WapServer.Adapter.Mongoose";
export type FindWapServerParams = {
id?: string;
name?: string;
description?: string;
countBots?: number;
maxBots?: number;
active?: boolean;
countBotsFrom?: number;
countBotsTo?: number;
};
export type AssingAvailableServerParams = {
companyId: string;
sessionUser: string;
};
export type BotEventParams = AssingAvailableServerParams & {};
export type BotRunningStatus =
| "created"
| "running"
| "paused"
| "restarting"
| "removing"
| "exited"
| "dead";
export type BotEventError = {
error: string;
code: number;
};
export enum SERVER_STATE {
"RUNNING" = "running",
"NOT_WORKING" = "not_working",
"NOT_ASSIGNED" = "not_assigned",
}
export enum BOT_STATE {
"EXISTS" = "exists",
"NOT_EXISTS" = "not_exists",
}
export enum BOT_SESSION_STATUS {
"LOGED" = "ok",
"UNLOGED" = "fail",
}
export type BotCheckStatus = {
state: BOT_STATE;
status: BotRunningStatus;
serverState: SERVER_STATE;
};
export type BotCheckSession = {
session: BOT_SESSION_STATUS;
};
export type SendBotMessageParams = {
companyId: string;
number: string;
message: string;
sessionUser: string;
};
export enum VALIDATE_BOT_ENVENT_ERRORS {
"INVALID_USER" = "invalid_user",
"INVALID_ORG" = "invalid_org",
"NO_PERMISSION" = "no_permission",
"NO_BOT_ALLOWED" = "no_bot_allowed",
"NO_SUBSCRIPTION_ACTIVE" = "no_subscription_active",
"NO_SERVER_ASSIGNED" = "no_server_assigned",
}
export interface ValidateBotEventStatus {
status: boolean;
error: string;
serverUrl?: string;
code?: VALIDATE_BOT_ENVENT_ERRORS;
}
export interface BotView {
exists: boolean;
runningState: BotRunningStatus;
serverId?: string;
serverName?: string;
serverDescription?: string;
serverState?: SERVER_STATE;
botSession?: BOT_SESSION_STATUS;
automaticNotifications: boolean;
}
export interface IWapServer {
id?: string;
name?: string;
description?: string;
ipv4: string;
ipv6: string;
countBots: number;
maxBots: number;
active: boolean;
}
export type PaginateWapServerParams = FindWapServerParams & {
page: number;
limit: number;
};
export type PaginateWapServerResults = {
data: IWapServer[];
page: number;
pages: number;
};
export type SysAdminGetWapServerParams = PaginateWapServerParams & {
payload: IPayload;
};
export interface IWapServerAdapter {
find(data: FindWapServerParams): Promise<IWapServer[]>;
findOne(data: FindWapServerParams): Promise<IWapServerDocument | null>;
paginate(filters: PaginateWapServerParams): Promise<PaginateWapServerResults>;
}
export interface IWapServerManager {
servers: IWapServerAdapter;
findServers(): Promise<IWapServer[]>;
getAvailableServer(): Promise<IWapServer>;
assignAvailableServer(data: AssingAvailableServerParams): Promise<IWapServer>;
quitServer(data: AssingAvailableServerParams): Promise<void>;
createBot(data: BotEventParams): Promise<void>;
startBot(data: BotEventParams): Promise<void>;
stopBot(data: BotEventParams): Promise<void>;
deleteBot(data: BotEventParams): Promise<void>;
checkBot(data: BotEventParams): Promise<BotCheckStatus>;
checkSession(data: BotEventParams): Promise<BotCheckSession>;
botView(data: BotEventParams): Promise<BotView>;
getQr(data: BotEventParams): Promise<string>;
sendMessage(data: SendBotMessageParams): Promise<void>;
sysAdminGetWapServers(data: PaginateWapServerParams): Promise<PaginateWapServerResults>;
}
+720
View File
@@ -0,0 +1,720 @@
import UsersManager from "../Users/Users";
import CompaniesManager from "../Companies/Companies";
import { NoPermissionMessage } from "../../helpers/NoPermissionMessage";
import EmployeesList from "../Employees/Employee";
import { EmployeeRoles } from "../Employees/Employees.Interface";
import { WapServerAdapterMongoose } from "./WapServer.Adapter.Mongoose";
import {
AssingAvailableServerParams,
BotCheckSession,
BotCheckStatus,
BotEventParams,
BotEventError,
BotView,
IWapServer,
IWapServerManager,
SendBotMessageParams,
ValidateBotEventStatus,
BOT_STATE,
SERVER_STATE,
BOT_SESSION_STATUS,
VALIDATE_BOT_ENVENT_ERRORS,
PaginateWapServerResults,
PaginateWapServerParams,
} from "./WapServer.Interface";
import PlanSubscriptionsList from "../PlanSubscriptions/PlanSubscriptons";
import { PlanFeatures } from "../Plans/Plans.interface";
import axios, { AxiosError } from "axios";
import { isNull } from "../../helpers/IsNull";
export interface CreateBotResult {
organizationId: string;
port: number;
error: string;
message: string;
}
class WapServerManager implements IWapServerManager {
servers: WapServerAdapterMongoose;
constructor() {
this.servers = new WapServerAdapterMongoose();
}
public async botView(data: AssingAvailableServerParams): Promise<BotView> {
const sessionUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!sessionUser) {
throw new Error("El usuario no es valido.");
}
const companyCheck = await CompaniesManager.companies.findOne({ _id: data.companyId });
if (!companyCheck) {
throw new Error("La compañia no existe");
}
if (!(await EmployeesList.checkPermission(companyCheck, data.sessionUser, EmployeeRoles.ADMIN))) {
throw new Error(NoPermissionMessage());
}
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
switch (validationStatus.code) {
case VALIDATE_BOT_ENVENT_ERRORS.NO_SERVER_ASSIGNED:
return {
runningState: "dead",
serverId: undefined,
serverName: undefined,
serverDescription: undefined,
serverState: SERVER_STATE.NOT_ASSIGNED,
exists: false,
automaticNotifications: isNull<boolean>(companyCheck.automaticNotifications, false),
};
default:
throw new Error(validationStatus.error);
}
}
if (!companyCheck.wapServerId) {
return {
runningState: "dead",
serverId: undefined,
serverName: undefined,
serverDescription: undefined,
serverState: SERVER_STATE.NOT_WORKING,
exists: false,
automaticNotifications: isNull<boolean>(companyCheck.automaticNotifications, false),
};
}
const server = await this.servers.serverList.findOne({ _id: companyCheck.wapServerId });
if (server) {
try {
const chkStatus = await this.checkBot({
sessionUser: data.sessionUser,
companyId: data.companyId,
});
let botSession = BOT_SESSION_STATUS.UNLOGED;
if (chkStatus.status.indexOf("Up") >= 0) {
botSession = (await this.checkSession(data)).session;
}
return {
serverId: server.id,
serverName: server.name,
serverDescription: server.description,
serverState: chkStatus.serverState,
exists: chkStatus.state == BOT_STATE.EXISTS ? true : false,
runningState: chkStatus.status,
botSession: botSession,
automaticNotifications: isNull<boolean>(companyCheck.automaticNotifications, false),
} as BotView;
} catch (error) {
return {
serverId: server.id,
serverName: server.name,
serverDescription: server.description,
serverState: SERVER_STATE.NOT_WORKING,
exists: false,
runningState: "dead",
automaticNotifications: isNull<boolean>(companyCheck.automaticNotifications, false),
};
}
}
return {
serverId: undefined,
serverName: undefined,
serverDescription: undefined,
exists: false,
runningState: "dead",
automaticNotifications: isNull<boolean>(companyCheck.automaticNotifications, false),
};
}
public async findServers(): Promise<IWapServer[]> {
const servidores = await this.servers.find({});
return servidores;
}
private getBotAdminApiUrl(url: string): string {
//return `https://${url}:${process.env.DEFAULT_BOT_ADMIN_PORT}/`;
//return `https://${url}/`;
return url;
}
public async getAvailableServer(): Promise<IWapServer> {
const servidores = await this.servers.find({ active: true });
if (servidores.length == 0) {
throw new Error("No se encontraron servidores disponibles");
}
const servidoresConCapacidad = servidores.filter((s) => {
return s.countBots < s.maxBots;
});
if (servidoresConCapacidad.length == 0) {
throw new Error("No se encontraron servidores disponibles");
}
const returnServer = servidoresConCapacidad.sort((a, b) => a.countBots - b.countBots).shift();
if (!returnServer) {
throw new Error("No se encontraron servidores disponibles");
}
return returnServer;
}
public async quitServer(data: AssingAvailableServerParams): Promise<void> {
const sessionUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!sessionUser) {
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
}
//Validar que la organizacion exista.
const companyCheck = await CompaniesManager.companies.findOne({ _id: data.companyId });
if (!companyCheck) {
throw new Error("La compañia no existe");
}
//Validar que el usuario sea el administrador de la organizacion.
if (!(await EmployeesList.checkPermission(companyCheck, data.sessionUser, EmployeeRoles.ADMIN))) {
throw new Error(NoPermissionMessage());
}
//Descontar 1 al contador de bots del servidor.
if (companyCheck && companyCheck.wapServerId) {
const server = await this.servers.serverList.findOne({
_id: companyCheck.wapServerId,
});
if (server) {
server.countBots = server.countBots - 1;
if (server.countBots < 0) {
server.countBots = 0;
}
await server.save();
}
}
companyCheck.wapServerId = undefined;
await companyCheck.save();
}
public async assignAvailableServer(data: AssingAvailableServerParams): Promise<IWapServer> {
const sessionUser = await UsersManager.users.findOne({ _id: data.sessionUser });
if (!sessionUser) {
throw new Error("No se ha encontrado el usuario o no tiene permisos para realizar esta acción");
}
//Validar que la organizacion exista.
const companyCheck = await CompaniesManager.companies.findOne({ _id: data.companyId });
if (!companyCheck) {
throw new Error("La compañia no existe");
}
//Validar que el usuario sea el administrador de la organizacion.
if (!(await EmployeesList.checkPermission(companyCheck, data.sessionUser, EmployeeRoles.ADMIN))) {
throw new Error(NoPermissionMessage());
}
//Obtener el id del usuario owner de la organizacion.
const organizationOwner = companyCheck.ownerId;
//Validar que el owner de la organizacion tenga un plan que permita bots.
if (
!PlanSubscriptionsList.checkFeature({
userId: organizationOwner,
feature: PlanFeatures.HAS_BOT,
})
) {
throw new Error("El plan de la organizacion no permite bots.");
}
//Validar que el plan este activo.
if (!PlanSubscriptionsList.isSubscriptionActive({ sessionUser: organizationOwner })) {
throw new Error("La organizacion no tiene una suscripcion activa.");
}
//Validar que la organizacion no tenga ningun servidor asignado.
let organizationServerId = companyCheck.wapServerId;
if (organizationServerId) {
throw new Error("La organizacion ya tiene un servidor asignado.");
}
//Obtener el servidor con menos bots activos.
const availableServer = await this.getAvailableServer();
if (!availableServer) {
throw new Error("No se encontraron servidores disponibles.");
}
const server = await this.servers.serverList.findOne({ _id: availableServer.id });
if (!server) {
throw new Error("No se encontro el servidor");
}
//Guardar en la coleccion Companies los datos del servidor asignado.
await CompaniesManager.updateCompany({
wapServerId: availableServer.id,
id: data.companyId,
sessionUser: data.sessionUser,
});
//Incrementear la cantidad de bots en el servidor elegido.
server.countBots = server.countBots + 1;
await server.save();
return server;
}
private async validateBotEvent(
sessionUserId: string,
companyId?: string,
): Promise<ValidateBotEventStatus> {
if (!sessionUserId) {
return {
status: false,
error: "No se ha encontrado el usuario",
code: VALIDATE_BOT_ENVENT_ERRORS.INVALID_USER,
};
}
const sessionUser = await UsersManager.users.findOne({ _id: sessionUserId });
if (!sessionUser) {
return {
status: false,
error: "No se ha encontrado el usuario o no tiene permisos para realizar esta acción",
code: VALIDATE_BOT_ENVENT_ERRORS.INVALID_USER,
};
}
if (!companyId) {
return {
status: false,
error: "No se ha encontrado la compañia",
code: VALIDATE_BOT_ENVENT_ERRORS.INVALID_ORG,
};
}
//Validar que la organizacion exista.
const companyCheck = await CompaniesManager.companies.findOne({ _id: companyId });
if (!companyCheck) {
return {
status: false,
error: "La compañia no existe",
code: VALIDATE_BOT_ENVENT_ERRORS.INVALID_ORG,
};
}
//Validar que el usuario sea el administrador de la organizacion.
if (!(await EmployeesList.checkPermission(companyCheck, sessionUserId, EmployeeRoles.ADMIN))) {
return {
status: false,
error: NoPermissionMessage(),
code: VALIDATE_BOT_ENVENT_ERRORS.NO_PERMISSION,
};
}
//Obtener el id del usuario owner de la organizacion.
const organizationOwner = companyCheck.ownerId;
const checkFeature = await PlanSubscriptionsList.checkFeature({
userId: organizationOwner,
feature: PlanFeatures.WAP_NOTIFICATIONS,
});
//Validar que el owner de la organizacion tenga un plan que permita bots.
if (!checkFeature) {
const serverAssigned = await this.servers.serverList.findOne({
_id: companyCheck.wapServerId,
});
if (!serverAssigned) {
return {
status: false,
error: "No se ha asignado un servidor a la compañia",
code: VALIDATE_BOT_ENVENT_ERRORS.NO_SERVER_ASSIGNED,
};
}
return {
status: false,
error: "El plan de la organizacion no permite bots.",
code: VALIDATE_BOT_ENVENT_ERRORS.NO_BOT_ALLOWED,
serverUrl: serverAssigned.ipv4,
};
}
//Validar que el plan este activo.
const checkSubscriptionActive = await PlanSubscriptionsList.isSubscriptionActive({
sessionUser: organizationOwner,
});
if (!checkSubscriptionActive) {
return {
status: false,
error: "La organizacion no tiene una suscripcion activa.",
code: VALIDATE_BOT_ENVENT_ERRORS.NO_SUBSCRIPTION_ACTIVE,
};
}
const serverAssigned = await this.servers.serverList.findOne({
_id: companyCheck.wapServerId,
});
if (!serverAssigned) {
return {
status: false,
error: "No se ha asignado un servidor a la compañia",
code: VALIDATE_BOT_ENVENT_ERRORS.NO_SERVER_ASSIGNED,
};
}
return {
status: true,
error: "",
serverUrl: serverAssigned.ipv4,
};
}
public async createBot(data: BotEventParams): Promise<void> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {
organizationId: data.companyId,
};
const response = await axios.post(this.getBotAdminApiUrl(url) + "containers/create", dataApi, {
headers: {
"Content-Type": "application/json",
},
});
const result: CreateBotResult = response.data;
if (result.error) {
throw new Error(result.error);
}
//Podria guardar el puerto asignado al bot.
//Pero en realidad no hace falta, ya que conociendo el servidor
//Donde se ejecuta el bot puedo averiguar el puerto si el que se encarga
//de enviar el mensaje de wap es el mismo bot admin.
//La idea seria que el server de tx le envia un post al bot admin para enviar un mensaje de wap y luego
//el bot admin averigua cual es el puerto donde se esta ejecutando el bot y envia la solicitud.
//De esta manera nunca hay una conexion directa entre la api principal (expuesta) y el bot.
//Por lo tanto por el momento solo retorno sin novedades...
return;
} catch (error) {
console.log(error);
throw new Error("Ha ocurrido un error al crear el bot.");
}
}
public async startBot(data: BotEventParams): Promise<void> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {};
const response = await axios.post(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/start",
dataApi,
{
headers: {
"Content-Type": "application/json",
},
},
);
const result: CreateBotResult = response.data;
if (result.error) {
throw new Error(result.error);
}
return;
} catch (error) {
if (error instanceof AxiosError) {
const axiosError = error as AxiosError;
if (axiosError.response) {
const responseError = axiosError.response;
console.log(responseError.data);
}
}
throw new Error("Ha ocurrido un error al iniciar el bot.");
}
}
public async stopBot(data: BotEventParams): Promise<void> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {};
const response = await axios.post(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/stop",
dataApi,
{
headers: {
"Content-Type": "application/json",
},
},
);
const result: CreateBotResult = response.data;
if (result.error) {
throw new Error(result.error);
}
return;
} catch (error) {
console.log(error);
throw new Error("Ha ocurrido un error al detener el bot.");
}
}
public async deleteBot(data: BotEventParams): Promise<void> {
//Como quiere borrarlo no voy a validar si tiene una suscripcion activa.
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
/*if (!validationStatus.status) {
throw new Error(validationStatus.error);
}*/
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const response = await axios.delete(this.getBotAdminApiUrl(url) + "containers/" + data.companyId);
const result: CreateBotResult = response.data;
if (result.error) {
throw new Error(result.error);
}
return;
} catch (error) {
throw new Error("Ha ocurrido un error al detener el bot.");
}
}
public async checkBot(data: BotEventParams): Promise<BotCheckStatus> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {};
const response = await axios.post(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/status",
dataApi,
{
headers: {
"Content-Type": "application/json",
},
},
);
return response.data as BotCheckStatus;
} catch (error) {
if (error instanceof AxiosError) {
const errorAxios: AxiosError = error;
if (errorAxios.response) {
const errorData = errorAxios.response.data as BotEventError;
if (errorData.code == 404) {
return {
state: BOT_STATE.NOT_EXISTS,
status: "dead",
serverState: SERVER_STATE.RUNNING,
};
} else {
throw new Error("Ha ocurrido un error al obtener el estado del bot.");
}
} else {
//no hay comunicacion con el bot-api-admin.
return {
state: BOT_STATE.NOT_EXISTS,
status: "dead",
serverState: SERVER_STATE.NOT_WORKING,
};
throw new Error("Ha ocurrido un error al obtener el estado del bot.");
}
} else {
throw new Error("Ha ocurrido un error al obtener el estado del bot.");
}
}
}
public async checkSession(data: BotEventParams): Promise<BotCheckSession> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {};
const response = await axios.post(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/session",
dataApi,
{
headers: {
"Content-Type": "application/json",
},
},
);
if (response.data.message == "ok") {
return {
session: BOT_SESSION_STATUS.LOGED,
};
}
return {
session: BOT_SESSION_STATUS.UNLOGED,
};
} catch (error) {
console.log(error);
throw new Error("Ha ocurrido un error al obtener el estado del bot.");
}
}
public async sendMessage(data: SendBotMessageParams): Promise<void> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const dataApi = {
number: data.number,
message: data.message,
};
const response = await axios.post(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/send",
dataApi,
{
headers: {
"Content-Type": "application/json",
},
},
);
const result: CreateBotResult = response.data;
if (result.error) {
throw new Error(result.error);
}
return;
} catch (error) {
throw new Error("Ha ocurrido un error al enviar el mensaje.");
}
}
public async getQr(data: BotEventParams): Promise<string> {
const validationStatus = await this.validateBotEvent(data.sessionUser, data.companyId);
if (!validationStatus.status) {
throw new Error(validationStatus.error);
}
const url = validationStatus.serverUrl;
if (!url) {
throw new Error("No se ha asignado un servidor a la organizacion");
}
try {
const response = await axios.get(
this.getBotAdminApiUrl(url) + "containers/" + data.companyId + "/qr",
{ responseType: "arraybuffer" },
);
const base64Image = Buffer.from(response.data, "binary").toString("base64");
return base64Image;
} catch (error) {
throw new Error("Ha ocurrido un error al obtener el estado del bot.");
}
}
public async sysAdminGetWapServers(data: PaginateWapServerParams): Promise<PaginateWapServerResults> {
const servers = await this.servers.paginate(data);
return servers;
}
}
const WapServerList = new WapServerManager();
export default WapServerList;