prima orm: instance controller ok

This commit is contained in:
Davidson Gomes 2024-06-06 16:14:22 -03:00
parent b309d686ec
commit 99c8cc0242
9 changed files with 50 additions and 129 deletions

View File

@ -12,6 +12,8 @@
* Connection to mongodb removed * Connection to mongodb removed
* Standardized all request bodies to use camelCase * Standardized all request bodies to use camelCase
* Change in webhook information from owner to instanceId * Change in webhook information from owner to instanceId
* Changed the .env file configuration, removed the yml version and added .env to the repository root
* Removed the mobile type connection with Baileys
# 1.8.0 (2024-05-27 16:10) # 1.8.0 (2024-05-27 16:10)

View File

@ -56,6 +56,8 @@ model Instance {
Websocket Websocket? Websocket Websocket?
Typebot Typebot? Typebot Typebot?
Session Session? Session Session?
MessageUpdate MessageUpdate[]
TypebotSession TypebotSession[]
} }
model Session { model Session {
@ -130,6 +132,8 @@ model MessageUpdate {
status String @db.VarChar(30) status String @db.VarChar(30)
Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade)
messageId Int messageId Int
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String
} }
model Webhook { model Webhook {
@ -277,4 +281,6 @@ model TypebotSession {
Typebot Typebot @relation(fields: [typebotId], references: [id], onDelete: Cascade) Typebot Typebot @relation(fields: [typebotId], references: [id], onDelete: Cascade)
typebotId Int typebotId Int
Message Message[] Message Message[]
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String
} }

View File

@ -58,7 +58,6 @@ export class InstanceController {
webhookEvents, webhookEvents,
qrcode, qrcode,
number, number,
mobile,
integration, integration,
token, token,
chatwootAccountId, chatwootAccountId,
@ -130,7 +129,7 @@ export class InstanceController {
const instanceId = v4(); const instanceId = v4();
await this.waMonitor.saveInstance({ instanceId, integration, instanceName, token, number, mobile }); await this.waMonitor.saveInstance({ instanceId, integration, instanceName, token, number });
instance.instanceName = instanceName; instance.instanceName = instanceName;
instance.instanceId = instanceId; instance.instanceId = instanceId;
@ -442,7 +441,7 @@ export class InstanceController {
if (qrcode) { if (qrcode) {
this.logger.verbose('creating qrcode'); this.logger.verbose('creating qrcode');
await instance.connectToWhatsapp(number, mobile); await instance.connectToWhatsapp(number);
await delay(5000); await delay(5000);
getQrcode = instance.qrCode; getQrcode = instance.qrCode;
} }
@ -608,7 +607,7 @@ export class InstanceController {
} }
} }
public async connectToWhatsapp({ instanceName, number = null, mobile = null }: InstanceDto) { public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) {
try { try {
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance'); this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
@ -631,7 +630,7 @@ export class InstanceController {
if (state == 'close') { if (state == 'close') {
this.logger.verbose('connecting'); this.logger.verbose('connecting');
await instance.connectToWhatsapp(number, mobile); await instance.connectToWhatsapp(number);
await delay(5000); await delay(5000);
return instance.qrCode; return instance.qrCode;
@ -672,20 +671,6 @@ export class InstanceController {
} }
} }
public async registerMobileCode({ instanceName }: InstanceDto, { mobileCode }: any) {
try {
this.logger.verbose('requested registerMobileCode from ' + instanceName + ' instance');
const instance = this.waMonitor.waInstances[instanceName];
console.log('mobileCode', mobileCode);
await instance.receiveMobileCode(mobileCode);
return { status: 'SUCCESS', error: false, response: { message: 'Mobile code registered' } };
} catch (error) {
this.logger.error(error);
}
}
public async connectionState({ instanceName }: InstanceDto) { public async connectionState({ instanceName }: InstanceDto) {
this.logger.verbose('requested connectionState from ' + instanceName + ' instance'); this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
return { return {

View File

@ -7,7 +7,6 @@ export class InstanceDto {
instanceId?: string; instanceId?: string;
qrcode?: boolean; qrcode?: boolean;
number?: string; number?: string;
mobile?: boolean;
integration?: string; integration?: string;
token?: string; token?: string;
webhook?: string; webhook?: string;

View File

@ -165,10 +165,10 @@ class ChatwootImport {
remoteJid: string; remoteJid: string;
}; };
return ( const aMessageTimestamp = a.messageTimestamp as any as number;
parseInt(aKey.remoteJid) - parseInt(bKey.remoteJid) || const bMessageTimestamp = b.messageTimestamp as any as number;
(a.messageTimestamp as number) - (b.messageTimestamp as number)
); return parseInt(aKey.remoteJid) - parseInt(bKey.remoteJid) || aMessageTimestamp - bMessageTimestamp;
}); });
const allMessagesMappedByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesOrdered); const allMessagesMappedByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesOrdered);
@ -176,8 +176,8 @@ class ChatwootImport {
const phoneNumbersWithTimestamp = new Map<string, firstLastTimestamp>(); const phoneNumbersWithTimestamp = new Map<string, firstLastTimestamp>();
allMessagesMappedByPhoneNumber.forEach((messages: Message[], phoneNumber: string) => { allMessagesMappedByPhoneNumber.forEach((messages: Message[], phoneNumber: string) => {
phoneNumbersWithTimestamp.set(phoneNumber, { phoneNumbersWithTimestamp.set(phoneNumber, {
first: messages[0]?.messageTimestamp as number, first: messages[0]?.messageTimestamp as any as number,
last: messages[messages.length - 1]?.messageTimestamp as number, last: messages[messages.length - 1]?.messageTimestamp as any as number,
}); });
}); });

View File

@ -47,22 +47,6 @@ export class InstanceRouter extends RouterBroker {
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('registerMobileCode'), ...guards, async (req, res) => {
logger.verbose('request received in registerMobileCode');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<null>({
request: req,
schema: instanceNameSchema,
ClassRef: SetPresenceDto,
execute: (instance, data) => instanceController.registerMobileCode(instance, data),
});
return res.status(HttpStatus.OK).json(response);
})
.get(this.routerPath('connect'), ...guards, async (req, res) => { .get(this.routerPath('connect'), ...guards, async (req, res) => {
logger.verbose('request received in connectInstance'); logger.verbose('request received in connectInstance');
logger.verbose('request body: '); logger.verbose('request body: ');

View File

@ -24,7 +24,6 @@ import makeWASocket, {
MessageUpsertType, MessageUpsertType,
MiscMessageGenerationOptions, MiscMessageGenerationOptions,
ParticipantAction, ParticipantAction,
PHONENUMBER_MCC,
prepareWAMessageMedia, prepareWAMessageMedia,
proto, proto,
useMultiFileAuthState, useMultiFileAuthState,
@ -44,7 +43,6 @@ import { isBase64, isURL } from 'class-validator';
import EventEmitter2 from 'eventemitter2'; import EventEmitter2 from 'eventemitter2';
// import ffmpeg from 'fluent-ffmpeg'; // import ffmpeg from 'fluent-ffmpeg';
import fs, { existsSync, readFileSync } from 'fs'; import fs, { existsSync, readFileSync } from 'fs';
import { parsePhoneNumber } from 'libphonenumber-js';
import Long from 'long'; import Long from 'long';
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
import { getMIMEType } from 'node-mime-types'; import { getMIMEType } from 'node-mime-types';
@ -143,7 +141,6 @@ export class BaileysStartupService extends ChannelStartupService {
this.logger.verbose('BaileysStartupService initialized'); this.logger.verbose('BaileysStartupService initialized');
this.cleanStore(); this.cleanStore();
this.instance.qrcode = { count: 0 }; this.instance.qrcode = { count: 0 };
this.mobile = false;
this.recoveringMessages(); this.recoveringMessages();
this.cronForceUpdateGroupMetadataCache(); this.cronForceUpdateGroupMetadataCache();
@ -159,7 +156,6 @@ export class BaileysStartupService extends ChannelStartupService {
public stateConnection: wa.StateConnection = { state: 'close' }; public stateConnection: wa.StateConnection = { state: 'close' };
public phoneNumber: string; public phoneNumber: string;
public mobile: boolean;
private async recoveringMessages() { private async recoveringMessages() {
this.logger.info('Recovering messages lost'); this.logger.info('Recovering messages lost');
@ -452,13 +448,8 @@ export class BaileysStartupService extends ChannelStartupService {
); );
} }
} }
if (connection === 'connecting') {
if (this.mobile) this.sendMobileCode();
}
} }
// TODO: Refactor this method for prisma
private async getMessage(key: proto.IMessageKey, full = false) { private async getMessage(key: proto.IMessageKey, full = false) {
this.logger.verbose('Getting message with key: ' + JSON.stringify(key)); this.logger.verbose('Getting message with key: ' + JSON.stringify(key));
try { try {
@ -525,7 +516,7 @@ export class BaileysStartupService extends ChannelStartupService {
return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name)); return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name));
} }
public async connectToWhatsapp(number?: string, mobile?: boolean): Promise<WASocket> { public async connectToWhatsapp(number?: string): Promise<WASocket> {
this.logger.verbose('Connecting to whatsapp'); this.logger.verbose('Connecting to whatsapp');
try { try {
this.loadWebhook(); this.loadWebhook();
@ -539,12 +530,6 @@ export class BaileysStartupService extends ChannelStartupService {
this.instance.authState = await this.defineAuthState(); this.instance.authState = await this.defineAuthState();
if (!mobile) {
this.mobile = false;
} else {
this.mobile = mobile;
}
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE'); const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()]; const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
this.logger.verbose('Browser: ' + JSON.stringify(browser)); this.logger.verbose('Browser: ' + JSON.stringify(browser));
@ -598,7 +583,6 @@ export class BaileysStartupService extends ChannelStartupService {
}, },
logger: P({ level: this.logBaileys }), logger: P({ level: this.logBaileys }),
printQRInTerminal: false, printQRInTerminal: false,
mobile,
browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser, browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser,
version, version,
markOnlineOnConnect: this.localSettings.alwaysOnline, markOnlineOnConnect: this.localSettings.alwaysOnline,
@ -663,64 +647,6 @@ export class BaileysStartupService extends ChannelStartupService {
} }
} }
private async sendMobileCode() {
const { registration } = this.client.authState.creds || null;
let phoneNumber = registration.phoneNumber || this.phoneNumber;
if (!phoneNumber.startsWith('+')) {
phoneNumber = '+' + phoneNumber;
}
if (!phoneNumber) {
this.logger.error('Phone number not found');
return;
}
const parsedPhoneNumber = parsePhoneNumber(phoneNumber);
if (!parsedPhoneNumber?.isValid()) {
this.logger.error('Phone number invalid');
return;
}
registration.phoneNumber = parsedPhoneNumber.format('E.164');
registration.phoneNumberCountryCode = parsedPhoneNumber.countryCallingCode;
registration.phoneNumberNationalNumber = parsedPhoneNumber.nationalNumber;
const mcc = await PHONENUMBER_MCC[parsedPhoneNumber.countryCallingCode];
if (!mcc) {
this.logger.error('MCC not found');
return;
}
registration.phoneNumberMobileCountryCode = mcc;
registration.method = 'sms';
try {
const response = await this.client.requestRegistrationCode(registration);
if (['ok', 'sent'].includes(response?.status)) {
this.logger.verbose('Registration code sent successfully');
return response;
}
} catch (error) {
this.logger.error(error);
}
}
public async receiveMobileCode(code: string) {
await this.client
.register(code.replace(/["']/g, '').trim().toLowerCase())
.then(async () => {
this.logger.verbose('Registration code received successfully');
})
.catch((error) => {
this.logger.error(error);
});
}
public async reloadConnection(): Promise<WASocket> { public async reloadConnection(): Promise<WASocket> {
try { try {
this.instance.authState = await this.defineAuthState(); this.instance.authState = await this.defineAuthState();
@ -1429,6 +1355,7 @@ export class BaileysStartupService extends ChannelStartupService {
participant: key?.remoteJid, participant: key?.remoteJid,
status: 'DELETED', status: 'DELETED',
dateTime: Date.now(), dateTime: Date.now(),
instanceId: this.instanceId,
}; };
this.logger.verbose(message); this.logger.verbose(message);
@ -1458,6 +1385,7 @@ export class BaileysStartupService extends ChannelStartupService {
status: status[update.status], status: status[update.status],
dateTime: Date.now(), dateTime: Date.now(),
pollUpdates, pollUpdates,
instanceId: this.instanceId,
}; };
this.logger.verbose(message); this.logger.verbose(message);
@ -3289,7 +3217,6 @@ export class BaileysStartupService extends ChannelStartupService {
if (!isJidGroup(groupJid)) return null; if (!isJidGroup(groupJid)) return null;
if (await groupMetadataCache.has(groupJid)) { if (await groupMetadataCache.has(groupJid)) {
console.log('Has cache for group: ' + groupJid);
const meta = await groupMetadataCache.get(groupJid); const meta = await groupMetadataCache.get(groupJid);
if (Date.now() - meta.timestamp > 3600000) { if (Date.now() - meta.timestamp > 3600000) {

View File

@ -541,6 +541,7 @@ export class BusinessStartupService extends ChannelStartupService {
participant: key?.remoteJid, participant: key?.remoteJid,
status: 'DELETED', status: 'DELETED',
dateTime: Date.now(), dateTime: Date.now(),
instanceId: this.instanceId,
}; };
this.logger.verbose(message); this.logger.verbose(message);
@ -569,6 +570,7 @@ export class BusinessStartupService extends ChannelStartupService {
participant: key?.remoteJid, participant: key?.remoteJid,
status: item.status.toUpperCase(), status: item.status.toUpperCase(),
dateTime: Date.now(), dateTime: Date.now(),
instanceId: this.instanceId,
}; };
this.logger.verbose(message); this.logger.verbose(message);

View File

@ -209,7 +209,12 @@ export class WAMonitoringService {
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) {
this.logger.verbose('cleaning up instance in database: ' + instanceName); this.logger.verbose('cleaning up instance in database: ' + instanceName);
// TODO: deleta instancia await this.prismaRepository.instance.update({
where: { name: instanceName },
data: { connectionStatus: 'close' },
});
await this.prismaRepository.session.deleteMany({ where: { sessionId: instanceName } });
return; return;
} }
@ -254,7 +259,27 @@ export class WAMonitoringService {
this.logger.verbose('cleaning store database instance: ' + instanceName); this.logger.verbose('cleaning store database instance: ' + instanceName);
// TODO: deleta dados da instancia await this.prismaRepository.session.deleteMany({ where: { sessionId: instanceName } });
await this.prismaRepository.chat.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.contact.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.messageUpdate.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.message.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.integration.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.auth.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.webhook.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.chatwoot.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.proxy.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.rabbitmq.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.sqs.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.typebotSession.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.typebot.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.websocket.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.setting.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.label.deleteMany({ where: { instanceId: instanceName } });
await this.prismaRepository.instance.delete({ where: { name: instanceName } });
} }
public async loadInstance() { public async loadInstance() {
@ -276,8 +301,6 @@ export class WAMonitoringService {
} }
public async saveInstance(data: any) { public async saveInstance(data: any) {
this.logger.verbose('Save instance');
try { try {
const msgParsed = JSON.parse(JSON.stringify(data)); const msgParsed = JSON.parse(JSON.stringify(data));
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) {
@ -289,7 +312,6 @@ export class WAMonitoringService {
}, },
}); });
console.log('saveInstance');
await this.prismaRepository.integration.create({ await this.prismaRepository.integration.create({
data: { data: {
instanceId: data.instanceId, instanceId: data.instanceId,
@ -309,7 +331,6 @@ export class WAMonitoringService {
} }
private async setInstance(id: string, name: string) { private async setInstance(id: string, name: string) {
console.log('setInstance', name);
const integration = await this.prismaRepository.integration.findUnique({ const integration = await this.prismaRepository.integration.findUnique({
where: { instanceId: id }, where: { instanceId: id },
}); });
@ -355,7 +376,6 @@ export class WAMonitoringService {
} }
private async loadInstancesFromRedis() { private async loadInstancesFromRedis() {
console.log('loadInstancesFromRedis');
this.logger.verbose('Redis enabled'); this.logger.verbose('Redis enabled');
const keys = await this.cache.keys(); const keys = await this.cache.keys();
@ -368,11 +388,9 @@ export class WAMonitoringService {
} }
private async loadInstancesFromDatabasePostgres() { private async loadInstancesFromDatabasePostgres() {
console.log('loadInstancesFromDatabasePostgres');
this.logger.verbose('Database enabled'); this.logger.verbose('Database enabled');
const instances = await this.prismaRepository.instance.findMany(); const instances = await this.prismaRepository.instance.findMany();
console.log('instances', instances);
if (instances.length === 0) { if (instances.length === 0) {
this.logger.verbose('No instances found'); this.logger.verbose('No instances found');
return; return;
@ -382,7 +400,6 @@ export class WAMonitoringService {
} }
private async loadInstancesFromProvider() { private async loadInstancesFromProvider() {
console.log('loadInstancesFromProvider');
this.logger.verbose('Provider in files enabled'); this.logger.verbose('Provider in files enabled');
const [instances] = await this.providerFiles.allInstances(); const [instances] = await this.providerFiles.allInstances();
@ -395,7 +412,6 @@ export class WAMonitoringService {
} }
private async loadInstancesFromFiles() { private async loadInstancesFromFiles() {
console.log('loadInstancesFromFiles');
this.logger.verbose('Store in files enabled'); this.logger.verbose('Store in files enabled');
const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' });
const instanceDirs = []; const instanceDirs = [];