mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-16 12:12:55 -06:00
Simplify events structure and fix minor issues
This commit is contained in:
parent
beb7942d7c
commit
05ee65f422
@ -2,7 +2,7 @@ import { InstanceDto, SetPresenceDto } from '@api/dto/instance.dto';
|
|||||||
import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service';
|
import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service';
|
||||||
import { ProviderFiles } from '@api/provider/sessions';
|
import { ProviderFiles } from '@api/provider/sessions';
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { channelController, eventController } from '@api/server.module';
|
import { channelController, eventManager } from '@api/server.module';
|
||||||
import { CacheService } from '@api/services/cache.service';
|
import { CacheService } from '@api/services/cache.service';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { SettingsService } from '@api/services/settings.service';
|
import { SettingsService } from '@api/services/settings.service';
|
||||||
@ -81,7 +81,7 @@ export class InstanceController {
|
|||||||
this.waMonitor.delInstanceTime(instance.instanceName);
|
this.waMonitor.delInstanceTime(instance.instanceName);
|
||||||
|
|
||||||
// set events
|
// set events
|
||||||
await eventController.setInstance(instance.instanceName, instanceData);
|
await eventManager.setInstance(instance.instanceName, instanceData);
|
||||||
|
|
||||||
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
|
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
|
||||||
instanceName: instanceData.instanceName,
|
instanceName: instanceData.instanceName,
|
||||||
@ -154,22 +154,18 @@ export class InstanceController {
|
|||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
webhook: {
|
webhook: {
|
||||||
webhookUrl: instanceData.webhookUrl,
|
webhookUrl: instanceData.webhook.url,
|
||||||
webhookByEvents: instanceData.webhookByEvents,
|
webhookByEvents: instanceData.webhook.byEvents,
|
||||||
webhookBase64: instanceData.webhookBase64,
|
webhookBase64: instanceData.webhook.base64,
|
||||||
// events: getWebhookEvents,
|
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
enabled: instanceData.websocketEnabled,
|
enabled: instanceData.websocket.enabled,
|
||||||
// events: getWebsocketEvents,
|
|
||||||
},
|
},
|
||||||
rabbitmq: {
|
rabbitmq: {
|
||||||
enabled: instanceData.rabbitmqEnabled,
|
enabled: instanceData.rabbitmq.enabled,
|
||||||
// events: getRabbitmqEvents,
|
|
||||||
},
|
},
|
||||||
sqs: {
|
sqs: {
|
||||||
enabled: instanceData.sqsEnabled,
|
enabled: instanceData.sqs.enabled,
|
||||||
// events: getSqsEvents,
|
|
||||||
},
|
},
|
||||||
settings,
|
settings,
|
||||||
qrcode: getQrcode,
|
qrcode: getQrcode,
|
||||||
@ -245,22 +241,18 @@ export class InstanceController {
|
|||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
webhook: {
|
webhook: {
|
||||||
webhookUrl: instanceData.webhookUrl,
|
webhookUrl: instanceData.webhook.url,
|
||||||
webhookByEvents: instanceData.webhookByEvents,
|
webhookByEvents: instanceData.webhook.byEvents,
|
||||||
webhookBase64: instanceData.webhookBase64,
|
webhookBase64: instanceData.webhook.base64,
|
||||||
// events: getWebhookEvents,
|
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
enabled: instanceData.websocketEnabled,
|
enabled: instanceData.websocket.enabled,
|
||||||
// events: getWebsocketEvents,
|
|
||||||
},
|
},
|
||||||
rabbitmq: {
|
rabbitmq: {
|
||||||
enabled: instanceData.rabbitmqEnabled,
|
enabled: instanceData.rabbitmq.enabled,
|
||||||
// events: getRabbitmqEvents,
|
|
||||||
},
|
},
|
||||||
sqs: {
|
sqs: {
|
||||||
enabled: instanceData.sqsEnabled,
|
enabled: instanceData.sqs.enabled,
|
||||||
// events: getSqsEvents,
|
|
||||||
},
|
},
|
||||||
settings,
|
settings,
|
||||||
chatwoot: {
|
chatwoot: {
|
||||||
|
@ -2,10 +2,10 @@ import { InstanceDto } from '@api/dto/instance.dto';
|
|||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import {
|
import {
|
||||||
difyController,
|
difyController,
|
||||||
|
eventManager,
|
||||||
genericController,
|
genericController,
|
||||||
openaiController,
|
openaiController,
|
||||||
typebotController,
|
typebotController,
|
||||||
websocketController,
|
|
||||||
} from '@api/server.module';
|
} from '@api/server.module';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
@ -102,12 +102,13 @@ export class ChatbotController {
|
|||||||
await genericController.emit(emitData);
|
await genericController.emit(emitData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setInstance(instanceName: string, data: any): Promise<any> {
|
public async setInstance(instanceName: string, data: InstanceDto): Promise<any> {
|
||||||
// chatwoot
|
if (data.websocket.enabled)
|
||||||
if (data.websocketEnabled)
|
await eventManager.websocket.set(instanceName, {
|
||||||
await websocketController.set(instanceName, {
|
websocket: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
events: data.websocketEvents,
|
events: data.websocket.events,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +201,7 @@ export class ChatbotController {
|
|||||||
instance: InstanceDto,
|
instance: InstanceDto,
|
||||||
session?: IntegrationSession,
|
session?: IntegrationSession,
|
||||||
) {
|
) {
|
||||||
let findBot = null;
|
let findBot: null;
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
findBot = await findBotByTrigger(botRepository, settingsRepository, content, instance.instanceId);
|
findBot = await findBotByTrigger(botRepository, settingsRepository, content, instance.instanceId);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { rabbitmqController, sqsController, webhookController, websocketController } from '@api/server.module';
|
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { Server } from 'http';
|
import { wa } from '@api/types/wa.types';
|
||||||
|
|
||||||
export type EmitData = {
|
export type EmitData = {
|
||||||
instanceName: string;
|
instanceName: string;
|
||||||
@ -16,19 +16,27 @@ export type EmitData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface EventControllerInterface {
|
export interface EventControllerInterface {
|
||||||
integrationEnabled: boolean;
|
|
||||||
set(instanceName: string, data: any): Promise<any>;
|
set(instanceName: string, data: any): Promise<any>;
|
||||||
get(instanceName: string): Promise<any>;
|
get(instanceName: string): Promise<any>;
|
||||||
emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise<void>;
|
emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EventController {
|
export class EventController {
|
||||||
public prismaRepository: PrismaRepository;
|
private prismaRepository: PrismaRepository;
|
||||||
public waMonitor: WAMonitoringService;
|
private waMonitor: WAMonitoringService;
|
||||||
|
private integrationStatus: boolean;
|
||||||
|
private integrationName: string;
|
||||||
|
|
||||||
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
constructor(
|
||||||
|
prismaRepository: PrismaRepository,
|
||||||
|
waMonitor: WAMonitoringService,
|
||||||
|
integrationStatus: boolean,
|
||||||
|
integrationName: string,
|
||||||
|
) {
|
||||||
this.prisma = prismaRepository;
|
this.prisma = prismaRepository;
|
||||||
this.monitor = waMonitor;
|
this.monitor = waMonitor;
|
||||||
|
this.status = integrationStatus;
|
||||||
|
this.name = integrationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set prisma(prisma: PrismaRepository) {
|
public set prisma(prisma: PrismaRepository) {
|
||||||
@ -47,6 +55,72 @@ export class EventController {
|
|||||||
return this.waMonitor;
|
return this.waMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set name(name: string) {
|
||||||
|
this.integrationName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name() {
|
||||||
|
return this.integrationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set status(status: boolean) {
|
||||||
|
this.integrationStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get status() {
|
||||||
|
return this.integrationStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async set(instanceName: string, data: EventDto): Promise<wa.LocalEvent> {
|
||||||
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data[this.name].enabled) {
|
||||||
|
data[this.name].events = [];
|
||||||
|
} else {
|
||||||
|
if (0 === data[this.name].events.length) {
|
||||||
|
data[this.name].events = this.events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prisma[this.name].upsert({
|
||||||
|
where: {
|
||||||
|
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
enabled: data[this.name].enabled,
|
||||||
|
events: data[this.name].events,
|
||||||
|
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(instanceName: string): Promise<wa.LocalEvent> {
|
||||||
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (undefined === this.monitor.waInstances[instanceName]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.prisma[this.name].findUnique({
|
||||||
|
where: {
|
||||||
|
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
public readonly events = [
|
public readonly events = [
|
||||||
'APPLICATION_STARTUP',
|
'APPLICATION_STARTUP',
|
||||||
'QRCODE_UPDATED',
|
'QRCODE_UPDATED',
|
||||||
@ -76,93 +150,4 @@ export class EventController {
|
|||||||
'REMOVE_INSTANCE',
|
'REMOVE_INSTANCE',
|
||||||
'LOGOUT_INSTANCE',
|
'LOGOUT_INSTANCE',
|
||||||
];
|
];
|
||||||
|
|
||||||
public init(httpServer: Server): void {
|
|
||||||
// websocket
|
|
||||||
websocketController.init(httpServer);
|
|
||||||
|
|
||||||
// rabbitmq
|
|
||||||
rabbitmqController.init();
|
|
||||||
|
|
||||||
// sqs
|
|
||||||
sqsController.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async emit({
|
|
||||||
instanceName,
|
|
||||||
origin,
|
|
||||||
event,
|
|
||||||
data,
|
|
||||||
serverUrl,
|
|
||||||
dateTime,
|
|
||||||
sender,
|
|
||||||
apiKey,
|
|
||||||
local,
|
|
||||||
}: {
|
|
||||||
instanceName: string;
|
|
||||||
origin: string;
|
|
||||||
event: string;
|
|
||||||
data: Object;
|
|
||||||
serverUrl: string;
|
|
||||||
dateTime: string;
|
|
||||||
sender: string;
|
|
||||||
apiKey?: string;
|
|
||||||
local?: boolean;
|
|
||||||
}): Promise<void> {
|
|
||||||
const emitData = {
|
|
||||||
instanceName,
|
|
||||||
origin,
|
|
||||||
event,
|
|
||||||
data,
|
|
||||||
serverUrl,
|
|
||||||
dateTime,
|
|
||||||
sender,
|
|
||||||
apiKey,
|
|
||||||
local,
|
|
||||||
};
|
|
||||||
// websocket
|
|
||||||
await websocketController.emit(emitData);
|
|
||||||
|
|
||||||
// rabbitmq
|
|
||||||
await rabbitmqController.emit(emitData);
|
|
||||||
|
|
||||||
// sqs
|
|
||||||
await sqsController.emit(emitData);
|
|
||||||
|
|
||||||
// webhook
|
|
||||||
await webhookController.emit(emitData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async setInstance(instanceName: string, data: any): Promise<any> {
|
|
||||||
// websocket
|
|
||||||
if (data.websocketEnabled)
|
|
||||||
await websocketController.set(instanceName, {
|
|
||||||
enabled: true,
|
|
||||||
events: data.websocketEvents,
|
|
||||||
});
|
|
||||||
|
|
||||||
// rabbitmq
|
|
||||||
if (data.rabbitmqEnabled)
|
|
||||||
await rabbitmqController.set(instanceName, {
|
|
||||||
enabled: true,
|
|
||||||
events: data.rabbitmqEvents,
|
|
||||||
});
|
|
||||||
|
|
||||||
// sqs
|
|
||||||
if (data.sqsEnabled)
|
|
||||||
await sqsController.set(instanceName, {
|
|
||||||
enabled: true,
|
|
||||||
events: data.sqsEvents,
|
|
||||||
});
|
|
||||||
|
|
||||||
// webhook
|
|
||||||
if (data.webhookEnabled)
|
|
||||||
await webhookController.set(instanceName, {
|
|
||||||
enabled: true,
|
|
||||||
events: data.webhookEvents,
|
|
||||||
url: data.webhookUrl,
|
|
||||||
webhookBase64: data.webhookBase64,
|
|
||||||
webhookByEvents: data.webhookByEvents,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
53
src/api/integrations/event/event.dto.ts
Normal file
53
src/api/integrations/event/event.dto.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Constructor } from '@api/integrations/integration.dto';
|
||||||
|
|
||||||
|
export class EventDto {
|
||||||
|
webhook?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
url?: string;
|
||||||
|
byEvents?: boolean;
|
||||||
|
base64?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
websocket?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
sqs?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
rabbitmq?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventInstanceMixin<TBase extends Constructor>(Base: TBase) {
|
||||||
|
return class extends Base {
|
||||||
|
webhook?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
url?: string;
|
||||||
|
byEvents?: boolean;
|
||||||
|
base64?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
websocket?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
sqs?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
rabbitmq?: {
|
||||||
|
enabled: boolean;
|
||||||
|
events?: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
130
src/api/integrations/event/event.manager.ts
Normal file
130
src/api/integrations/event/event.manager.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { RabbitmqController } from '@api/integrations/event/rabbitmq/rabbitmq.controller';
|
||||||
|
import { SqsController } from '@api/integrations/event/sqs/sqs.controller';
|
||||||
|
import { WebhookController } from '@api/integrations/event/webhook/webhook.controller';
|
||||||
|
import { WebsocketController } from '@api/integrations/event/websocket/websocket.controller';
|
||||||
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
|
import { Server } from 'http';
|
||||||
|
|
||||||
|
export class EventManager {
|
||||||
|
private prismaRepository: PrismaRepository;
|
||||||
|
private waMonitor: WAMonitoringService;
|
||||||
|
private websocketController: WebsocketController;
|
||||||
|
private webhookController: WebhookController;
|
||||||
|
private rabbitmqController: RabbitmqController;
|
||||||
|
private sqsController: SqsController;
|
||||||
|
|
||||||
|
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
||||||
|
this.prisma = prismaRepository;
|
||||||
|
this.monitor = waMonitor;
|
||||||
|
|
||||||
|
this.websocket = new WebsocketController(prismaRepository, waMonitor);
|
||||||
|
this.webhook = new WebhookController(prismaRepository, waMonitor);
|
||||||
|
this.rabbitmq = new RabbitmqController(prismaRepository, waMonitor);
|
||||||
|
this.sqs = new SqsController(prismaRepository, waMonitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set prisma(prisma: PrismaRepository) {
|
||||||
|
this.prismaRepository = prisma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get prisma() {
|
||||||
|
return this.prismaRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set monitor(waMonitor: WAMonitoringService) {
|
||||||
|
this.waMonitor = waMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get monitor() {
|
||||||
|
return this.waMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set websocket(websocket: WebsocketController) {
|
||||||
|
this.websocketController = websocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get websocket() {
|
||||||
|
return this.websocketController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set webhook(webhook: WebhookController) {
|
||||||
|
this.webhookController = webhook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get webhook() {
|
||||||
|
return this.webhookController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set rabbitmq(rabbitmq: RabbitmqController) {
|
||||||
|
this.rabbitmqController = rabbitmq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get rabbitmq() {
|
||||||
|
return this.rabbitmqController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set sqs(sqs: SqsController) {
|
||||||
|
this.sqsController = sqs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get sqs() {
|
||||||
|
return this.sqsController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(httpServer: Server): void {
|
||||||
|
this.websocket.init(httpServer);
|
||||||
|
this.rabbitmq.init();
|
||||||
|
this.sqs.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async emit(eventData: {
|
||||||
|
instanceName: string;
|
||||||
|
origin: string;
|
||||||
|
event: string;
|
||||||
|
data: Object;
|
||||||
|
serverUrl: string;
|
||||||
|
dateTime: string;
|
||||||
|
sender: string;
|
||||||
|
apiKey?: string;
|
||||||
|
local?: boolean;
|
||||||
|
}): Promise<void> {
|
||||||
|
await this.websocket.emit(eventData);
|
||||||
|
await this.rabbitmq.emit(eventData);
|
||||||
|
await this.sqs.emit(eventData);
|
||||||
|
await this.webhook.emit(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setInstance(instanceName: string, data: any): Promise<any> {
|
||||||
|
await this.websocket.set(instanceName, {
|
||||||
|
websocket: {
|
||||||
|
enabled: data.websocket?.enabled,
|
||||||
|
events: data.websocket?.events,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.rabbitmq.set(instanceName, {
|
||||||
|
rabbitmq: {
|
||||||
|
enabled: data.rabbitmq?.enabled,
|
||||||
|
events: data.rabbitmq?.events,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.sqs.set(instanceName, {
|
||||||
|
sqs: {
|
||||||
|
enabled: data.sqs?.enabled,
|
||||||
|
events: data.sqs?.events,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.webhook.set(instanceName, {
|
||||||
|
webhook: {
|
||||||
|
enabled: data.webhook?.enabled,
|
||||||
|
events: data.webhook?.events,
|
||||||
|
url: data.webhook.url,
|
||||||
|
base64: data.webhook.base64,
|
||||||
|
byEvents: data.webhook.byEvents,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { RabbitmqRouter } from '@api/integrations/event/rabbitmq/routes/rabbitmq.router';
|
import { RabbitmqRouter } from '@api/integrations/event/rabbitmq/rabbitmq.router';
|
||||||
import { SqsRouter } from '@api/integrations/event/sqs/routes/sqs.router';
|
import { SqsRouter } from '@api/integrations/event/sqs/sqs.router';
|
||||||
import { WebhookRouter } from '@api/integrations/event/webhook/routes/webhook.router';
|
import { WebhookRouter } from '@api/integrations/event/webhook/webhook.router';
|
||||||
import { WebsocketRouter } from '@api/integrations/event/websocket/routes/websocket.router';
|
import { WebsocketRouter } from '@api/integrations/event/websocket/websocket.router';
|
||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
|
||||||
export class EventRouter {
|
export class EventRouter {
|
||||||
|
@ -1,4 +1,67 @@
|
|||||||
export * from '@api/integrations/event/rabbitmq/validate/rabbitmq.schema';
|
import { JSONSchema7 } from 'json-schema';
|
||||||
export * from '@api/integrations/event/sqs/validate/sqs.schema';
|
import { v4 } from 'uuid';
|
||||||
export * from '@api/integrations/event/webhook/validate/webhook.schema';
|
|
||||||
export * from '@api/integrations/event/websocket/validate/websocket.schema';
|
export * from '@api/integrations/event/webhook/webhook.schema';
|
||||||
|
|
||||||
|
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
||||||
|
const properties = {};
|
||||||
|
propertyNames.forEach(
|
||||||
|
(property) =>
|
||||||
|
(properties[property] = {
|
||||||
|
minLength: 1,
|
||||||
|
description: `The "${property}" cannot be empty`,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
if: {
|
||||||
|
propertyNames: {
|
||||||
|
enum: [...propertyNames],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
then: { properties },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const eventSchema: JSONSchema7 = {
|
||||||
|
$id: v4(),
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
enabled: { type: 'boolean', enum: [true, false] },
|
||||||
|
events: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 0,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
enum: [
|
||||||
|
'APPLICATION_STARTUP',
|
||||||
|
'QRCODE_UPDATED',
|
||||||
|
'MESSAGES_SET',
|
||||||
|
'MESSAGES_UPSERT',
|
||||||
|
'MESSAGES_EDITED',
|
||||||
|
'MESSAGES_UPDATE',
|
||||||
|
'MESSAGES_DELETE',
|
||||||
|
'SEND_MESSAGE',
|
||||||
|
'CONTACTS_SET',
|
||||||
|
'CONTACTS_UPSERT',
|
||||||
|
'CONTACTS_UPDATE',
|
||||||
|
'PRESENCE_UPDATE',
|
||||||
|
'CHATS_SET',
|
||||||
|
'CHATS_UPSERT',
|
||||||
|
'CHATS_UPDATE',
|
||||||
|
'CHATS_DELETE',
|
||||||
|
'GROUPS_UPSERT',
|
||||||
|
'GROUP_UPDATE',
|
||||||
|
'GROUP_PARTICIPANTS_UPDATE',
|
||||||
|
'CONNECTION_UPDATE',
|
||||||
|
'LABELS_EDIT',
|
||||||
|
'LABELS_ASSOCIATION',
|
||||||
|
'CALL',
|
||||||
|
'TYPEBOT_START',
|
||||||
|
'TYPEBOT_CHANGE_STATUS',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['enabled'],
|
||||||
|
...isNotEmpty('enabled'),
|
||||||
|
};
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import { Constructor } from '@api/integrations/integration.dto';
|
|
||||||
|
|
||||||
export class RabbitmqDto {
|
|
||||||
enabled: boolean;
|
|
||||||
events?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RabbitMQInstanceMixin<TBase extends Constructor>(Base: TBase) {
|
|
||||||
return class extends Base {
|
|
||||||
rabbitmqEnabled?: boolean;
|
|
||||||
rabbitmqEvents?: string[];
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,37 +1,38 @@
|
|||||||
import { RabbitmqDto } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto';
|
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { wa } from '@api/types/wa.types';
|
|
||||||
import { configService, Log, Rabbitmq } from '@config/env.config';
|
import { configService, Log, Rabbitmq } from '@config/env.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
import { NotFoundException } from '@exceptions';
|
|
||||||
import * as amqp from 'amqplib/callback_api';
|
import * as amqp from 'amqplib/callback_api';
|
||||||
|
|
||||||
import { EmitData, EventController, EventControllerInterface } from '../../event.controller';
|
import { EmitData, EventController, EventControllerInterface } from '../event.controller';
|
||||||
|
|
||||||
export class RabbitmqController extends EventController implements EventControllerInterface {
|
export class RabbitmqController extends EventController implements EventControllerInterface {
|
||||||
public amqpChannel: amqp.Channel | null = null;
|
public amqpChannel: amqp.Channel | null = null;
|
||||||
private readonly logger = new Logger(RabbitmqController.name);
|
private readonly logger = new Logger(RabbitmqController.name);
|
||||||
integrationEnabled = configService.get<Rabbitmq>('RABBITMQ')?.ENABLED;
|
|
||||||
|
|
||||||
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
||||||
super(prismaRepository, waMonitor);
|
super(prismaRepository, waMonitor, configService.get<Rabbitmq>('RABBITMQ')?.ENABLED, 'rabbitmq');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async init(): Promise<void> {
|
public async init(): Promise<void> {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
|
const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
|
||||||
|
|
||||||
amqp.connect(uri, (error, connection) => {
|
amqp.connect(uri, (error, connection) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.createChannel((channelError, channel) => {
|
connection.createChannel((channelError, channel) => {
|
||||||
if (channelError) {
|
if (channelError) {
|
||||||
reject(channelError);
|
reject(channelError);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
this.amqpChannel = channel;
|
this.amqpChannel = channel;
|
||||||
|
|
||||||
this.logger.info('AMQP initialized');
|
this.logger.info('AMQP initialized');
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -61,57 +63,6 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
return this.amqpChannel;
|
return this.amqpChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async set(instanceName: string, data: RabbitmqDto): Promise<wa.LocalRabbitmq> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (!data.enabled) {
|
|
||||||
data.events = [];
|
|
||||||
} else {
|
|
||||||
if (0 === data.events.length) {
|
|
||||||
data.events = this.events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.get(instanceName);
|
|
||||||
|
|
||||||
return this.prisma.rabbitmq.update({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
return this.prisma.rabbitmq.create({
|
|
||||||
data: {
|
|
||||||
enabled: data.enabled,
|
|
||||||
events: data.events,
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async get(instanceName: string): Promise<wa.LocalWebsocket> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (undefined === this.monitor.waInstances[instanceName]) {
|
|
||||||
throw new NotFoundException('Instance not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.prisma.rabbitmq.findUnique({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
throw new NotFoundException('Instance rabbitmq not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async emit({
|
public async emit({
|
||||||
instanceName,
|
instanceName,
|
||||||
origin,
|
origin,
|
||||||
@ -122,7 +73,9 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const instanceRabbitmq = await this.get(instanceName);
|
const instanceRabbitmq = await this.get(instanceName);
|
||||||
const rabbitmqLocal = instanceRabbitmq?.events;
|
const rabbitmqLocal = instanceRabbitmq?.events;
|
||||||
@ -178,6 +131,7 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
|
|
||||||
this.logger.log(logData);
|
this.logger.log(logData);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
retry++;
|
retry++;
|
||||||
@ -231,10 +185,12 @@ export class RabbitmqController extends EventController implements EventControll
|
|||||||
|
|
||||||
private async initGlobalQueues(): Promise<void> {
|
private async initGlobalQueues(): Promise<void> {
|
||||||
this.logger.info('Initializing global queues');
|
this.logger.info('Initializing global queues');
|
||||||
|
|
||||||
const events = configService.get<Rabbitmq>('RABBITMQ').EVENTS;
|
const events = configService.get<Rabbitmq>('RABBITMQ').EVENTS;
|
||||||
|
|
||||||
if (!events) {
|
if (!events) {
|
||||||
this.logger.warn('No events to initialize on AMQP');
|
this.logger.warn('No events to initialize on AMQP');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
|||||||
import { RouterBroker } from '@api/abstract/abstract.router';
|
import { RouterBroker } from '@api/abstract/abstract.router';
|
||||||
import { InstanceDto } from '@api/dto/instance.dto';
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
import { RabbitmqDto } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto';
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { rabbitmqController } from '@api/server.module';
|
|
||||||
import { HttpStatus } from '@api/routes/index.router';
|
import { HttpStatus } from '@api/routes/index.router';
|
||||||
import { instanceSchema, rabbitmqSchema } from '@validate/validate.schema';
|
import { eventManager } from '@api/server.module';
|
||||||
|
import { eventSchema, instanceSchema } from '@validate/validate.schema';
|
||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
export class RabbitmqRouter extends RouterBroker {
|
export class RabbitmqRouter extends RouterBroker {
|
||||||
@ -11,11 +11,11 @@ export class RabbitmqRouter extends RouterBroker {
|
|||||||
super();
|
super();
|
||||||
this.router
|
this.router
|
||||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
const response = await this.dataValidate<RabbitmqDto>({
|
const response = await this.dataValidate<EventDto>({
|
||||||
request: req,
|
request: req,
|
||||||
schema: rabbitmqSchema,
|
schema: eventSchema,
|
||||||
ClassRef: RabbitmqDto,
|
ClassRef: EventDto,
|
||||||
execute: (instance, data) => rabbitmqController.set(instance.instanceName, data),
|
execute: (instance, data) => eventManager.rabbitmq.set(instance.instanceName, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
@ -25,7 +25,7 @@ export class RabbitmqRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: instanceSchema,
|
schema: instanceSchema,
|
||||||
ClassRef: InstanceDto,
|
ClassRef: InstanceDto,
|
||||||
execute: (instance) => rabbitmqController.get(instance.instanceName),
|
execute: (instance) => eventManager.rabbitmq.get(instance.instanceName),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.OK).json(response);
|
res.status(HttpStatus.OK).json(response);
|
@ -1,65 +0,0 @@
|
|||||||
import { JSONSchema7 } from 'json-schema';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
|
||||||
const properties = {};
|
|
||||||
propertyNames.forEach(
|
|
||||||
(property) =>
|
|
||||||
(properties[property] = {
|
|
||||||
minLength: 1,
|
|
||||||
description: `The "${property}" cannot be empty`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
if: {
|
|
||||||
propertyNames: {
|
|
||||||
enum: [...propertyNames],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
then: { properties },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const rabbitmqSchema: JSONSchema7 = {
|
|
||||||
$id: v4(),
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
enabled: { type: 'boolean', enum: [true, false] },
|
|
||||||
events: {
|
|
||||||
type: 'array',
|
|
||||||
minItems: 0,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
enum: [
|
|
||||||
'APPLICATION_STARTUP',
|
|
||||||
'QRCODE_UPDATED',
|
|
||||||
'MESSAGES_SET',
|
|
||||||
'MESSAGES_UPSERT',
|
|
||||||
'MESSAGES_EDITED',
|
|
||||||
'MESSAGES_UPDATE',
|
|
||||||
'MESSAGES_DELETE',
|
|
||||||
'SEND_MESSAGE',
|
|
||||||
'CONTACTS_SET',
|
|
||||||
'CONTACTS_UPSERT',
|
|
||||||
'CONTACTS_UPDATE',
|
|
||||||
'PRESENCE_UPDATE',
|
|
||||||
'CHATS_SET',
|
|
||||||
'CHATS_UPSERT',
|
|
||||||
'CHATS_UPDATE',
|
|
||||||
'CHATS_DELETE',
|
|
||||||
'GROUPS_UPSERT',
|
|
||||||
'GROUP_UPDATE',
|
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
|
||||||
'CONNECTION_UPDATE',
|
|
||||||
'LABELS_EDIT',
|
|
||||||
'LABELS_ASSOCIATION',
|
|
||||||
'CALL',
|
|
||||||
'TYPEBOT_START',
|
|
||||||
'TYPEBOT_CHANGE_STATUS',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ['enabled'],
|
|
||||||
...isNotEmpty('enabled'),
|
|
||||||
};
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Constructor } from '@api/integrations/integration.dto';
|
|
||||||
|
|
||||||
export class SqsDto {
|
|
||||||
enabled: boolean;
|
|
||||||
events?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SQSInstanceMixin<TBase extends Constructor>(Base: TBase) {
|
|
||||||
return class extends Base {
|
|
||||||
sqsEnabled?: boolean;
|
|
||||||
sqsEvents?: string[];
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,29 +1,27 @@
|
|||||||
import { SqsDto } from '@api/integrations/event/sqs/dto/sqs.dto';
|
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { wa } from '@api/types/wa.types';
|
|
||||||
import { SQS } from '@aws-sdk/client-sqs';
|
import { SQS } from '@aws-sdk/client-sqs';
|
||||||
import { configService, Log, Sqs } from '@config/env.config';
|
import { configService, Log, Sqs } from '@config/env.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
import { NotFoundException } from '@exceptions';
|
|
||||||
|
|
||||||
import { EmitData, EventController, EventControllerInterface } from '../../event.controller';
|
import { EmitData, EventController, EventControllerInterface } from '../event.controller';
|
||||||
|
|
||||||
export class SqsController extends EventController implements EventControllerInterface {
|
export class SqsController extends EventController implements EventControllerInterface {
|
||||||
private sqs: SQS;
|
private sqs: SQS;
|
||||||
private readonly logger = new Logger(SqsController.name);
|
private readonly logger = new Logger(SqsController.name);
|
||||||
integrationEnabled = configService.get<Sqs>('SQS')?.ENABLED;
|
|
||||||
|
|
||||||
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
||||||
super(prismaRepository, waMonitor);
|
super(prismaRepository, waMonitor, configService.get<Sqs>('SQS')?.ENABLED, 'sqs');
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(): void {
|
public init(): void {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
new Promise<void>((resolve) => {
|
||||||
new Promise<void>((resolve, reject) => {
|
|
||||||
const awsConfig = configService.get<Sqs>('SQS');
|
const awsConfig = configService.get<Sqs>('SQS');
|
||||||
|
|
||||||
this.sqs = new SQS({
|
this.sqs = new SQS({
|
||||||
credentials: {
|
credentials: {
|
||||||
accessKeyId: awsConfig.ACCESS_KEY_ID,
|
accessKeyId: awsConfig.ACCESS_KEY_ID,
|
||||||
@ -34,6 +32,7 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.logger.info('SQS initialized');
|
this.logger.info('SQS initialized');
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -46,57 +45,6 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
return this.sqs;
|
return this.sqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async set(instanceName: string, data: SqsDto): Promise<wa.LocalSqs> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (!data.enabled) {
|
|
||||||
data.events = [];
|
|
||||||
} else {
|
|
||||||
if (0 === data.events.length) {
|
|
||||||
data.events = this.events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.get(instanceName);
|
|
||||||
|
|
||||||
return this.prisma.sqs.update({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
return this.prisma.sqs.create({
|
|
||||||
data: {
|
|
||||||
enabled: data.enabled,
|
|
||||||
events: data.events,
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async get(instanceName: string): Promise<wa.LocalSqs> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (undefined === this.monitor.waInstances[instanceName]) {
|
|
||||||
throw new NotFoundException('Instance not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.prisma.sqs.findUnique({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
throw new NotFoundException('Instance SQS not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async emit({
|
public async emit({
|
||||||
instanceName,
|
instanceName,
|
||||||
origin,
|
origin,
|
||||||
@ -107,7 +55,9 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const instanceSqs = await this.get(instanceName);
|
const instanceSqs = await this.get(instanceName);
|
||||||
const sqsLocal = instanceSqs?.events;
|
const sqsLocal = instanceSqs?.events;
|
||||||
@ -117,11 +67,8 @@ export class SqsController extends EventController implements EventControllerInt
|
|||||||
if (this.sqs) {
|
if (this.sqs) {
|
||||||
if (Array.isArray(sqsLocal) && sqsLocal.includes(we)) {
|
if (Array.isArray(sqsLocal) && sqsLocal.includes(we)) {
|
||||||
const eventFormatted = `${event.replace('.', '_').toLowerCase()}`;
|
const eventFormatted = `${event.replace('.', '_').toLowerCase()}`;
|
||||||
|
|
||||||
const queueName = `${instanceName}_${eventFormatted}.fifo`;
|
const queueName = `${instanceName}_${eventFormatted}.fifo`;
|
||||||
|
|
||||||
const sqsConfig = configService.get<Sqs>('SQS');
|
const sqsConfig = configService.get<Sqs>('SQS');
|
||||||
|
|
||||||
const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`;
|
||||||
|
|
||||||
const message = {
|
const message = {
|
@ -1,9 +1,9 @@
|
|||||||
import { RouterBroker } from '@api/abstract/abstract.router';
|
import { RouterBroker } from '@api/abstract/abstract.router';
|
||||||
import { InstanceDto } from '@api/dto/instance.dto';
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
import { SqsDto } from '@api/integrations/event/sqs/dto/sqs.dto';
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { sqsController } from '@api/server.module';
|
|
||||||
import { HttpStatus } from '@api/routes/index.router';
|
import { HttpStatus } from '@api/routes/index.router';
|
||||||
import { instanceSchema, sqsSchema } from '@validate/validate.schema';
|
import { eventManager } from '@api/server.module';
|
||||||
|
import { eventSchema, instanceSchema } from '@validate/validate.schema';
|
||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
export class SqsRouter extends RouterBroker {
|
export class SqsRouter extends RouterBroker {
|
||||||
@ -11,11 +11,11 @@ export class SqsRouter extends RouterBroker {
|
|||||||
super();
|
super();
|
||||||
this.router
|
this.router
|
||||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
const response = await this.dataValidate<SqsDto>({
|
const response = await this.dataValidate<EventDto>({
|
||||||
request: req,
|
request: req,
|
||||||
schema: sqsSchema,
|
schema: eventSchema,
|
||||||
ClassRef: SqsDto,
|
ClassRef: EventDto,
|
||||||
execute: (instance, data) => sqsController.set(instance.instanceName, data),
|
execute: (instance, data) => eventManager.sqs.set(instance.instanceName, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
@ -25,7 +25,7 @@ export class SqsRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: instanceSchema,
|
schema: instanceSchema,
|
||||||
ClassRef: InstanceDto,
|
ClassRef: InstanceDto,
|
||||||
execute: (instance) => sqsController.get(instance.instanceName),
|
execute: (instance) => eventManager.sqs.get(instance.instanceName),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.OK).json(response);
|
res.status(HttpStatus.OK).json(response);
|
@ -1,65 +0,0 @@
|
|||||||
import { JSONSchema7 } from 'json-schema';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
|
||||||
const properties = {};
|
|
||||||
propertyNames.forEach(
|
|
||||||
(property) =>
|
|
||||||
(properties[property] = {
|
|
||||||
minLength: 1,
|
|
||||||
description: `The "${property}" cannot be empty`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
if: {
|
|
||||||
propertyNames: {
|
|
||||||
enum: [...propertyNames],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
then: { properties },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sqsSchema: JSONSchema7 = {
|
|
||||||
$id: v4(),
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
enabled: { type: 'boolean', enum: [true, false] },
|
|
||||||
events: {
|
|
||||||
type: 'array',
|
|
||||||
minItems: 0,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
enum: [
|
|
||||||
'APPLICATION_STARTUP',
|
|
||||||
'QRCODE_UPDATED',
|
|
||||||
'MESSAGES_SET',
|
|
||||||
'MESSAGES_UPSERT',
|
|
||||||
'MESSAGES_EDITED',
|
|
||||||
'MESSAGES_UPDATE',
|
|
||||||
'MESSAGES_DELETE',
|
|
||||||
'SEND_MESSAGE',
|
|
||||||
'CONTACTS_SET',
|
|
||||||
'CONTACTS_UPSERT',
|
|
||||||
'CONTACTS_UPDATE',
|
|
||||||
'PRESENCE_UPDATE',
|
|
||||||
'CHATS_SET',
|
|
||||||
'CHATS_UPSERT',
|
|
||||||
'CHATS_UPDATE',
|
|
||||||
'CHATS_DELETE',
|
|
||||||
'GROUPS_UPSERT',
|
|
||||||
'GROUP_UPDATE',
|
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
|
||||||
'CONNECTION_UPDATE',
|
|
||||||
'LABELS_EDIT',
|
|
||||||
'LABELS_ASSOCIATION',
|
|
||||||
'CALL',
|
|
||||||
'TYPEBOT_START',
|
|
||||||
'TYPEBOT_CHANGE_STATUS',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ['enabled'],
|
|
||||||
...isNotEmpty('enabled'),
|
|
||||||
};
|
|
@ -1,18 +0,0 @@
|
|||||||
import { Constructor } from '@api/integrations/integration.dto';
|
|
||||||
|
|
||||||
export class WebhookDto {
|
|
||||||
enabled?: boolean;
|
|
||||||
url?: string;
|
|
||||||
events?: string[];
|
|
||||||
webhookByEvents?: boolean;
|
|
||||||
webhookBase64?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WebhookInstanceMixin<TBase extends Constructor>(Base: TBase) {
|
|
||||||
return class extends Base {
|
|
||||||
webhookUrl?: string;
|
|
||||||
webhookByEvents?: boolean;
|
|
||||||
webhookBase64?: boolean;
|
|
||||||
webhookEvents?: string[];
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,74 +1,53 @@
|
|||||||
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { wa } from '@api/types/wa.types';
|
import { wa } from '@api/types/wa.types';
|
||||||
import { configService, Log, Webhook } from '@config/env.config';
|
import { configService, Log, Webhook } from '@config/env.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
import { BadRequestException, NotFoundException } from '@exceptions';
|
import { BadRequestException } from '@exceptions';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { isURL } from 'class-validator';
|
import { isURL } from 'class-validator';
|
||||||
|
|
||||||
import { EmitData, EventController, EventControllerInterface } from '../../event.controller';
|
import { EmitData, EventController, EventControllerInterface } from '../event.controller';
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
|
||||||
|
|
||||||
export class WebhookController extends EventController implements EventControllerInterface {
|
export class WebhookController extends EventController implements EventControllerInterface {
|
||||||
private readonly logger = new Logger(WebhookController.name);
|
private readonly logger = new Logger(WebhookController.name);
|
||||||
|
|
||||||
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
||||||
super(prismaRepository, waMonitor);
|
super(prismaRepository, waMonitor, true, 'webhook');
|
||||||
}
|
}
|
||||||
integrationEnabled: boolean;
|
|
||||||
|
|
||||||
public async set(instanceName: string, data: WebhookDto): Promise<wa.LocalWebHook> {
|
override async set(instanceName: string, data: EventDto): Promise<wa.LocalWebHook> {
|
||||||
if (!isURL(data.url, { require_tld: false })) {
|
if (!isURL(data.webhook.url, { require_tld: false })) {
|
||||||
throw new BadRequestException('Invalid "url" property');
|
throw new BadRequestException('Invalid "url" property');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.enabled) {
|
if (!data.webhook.enabled) {
|
||||||
data.events = [];
|
data.webhook.events = [];
|
||||||
} else {
|
} else {
|
||||||
if (0 === data.events.length) {
|
if (0 === data.webhook.events.length) {
|
||||||
data.events = this.events;
|
data.webhook.events = this.events;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.get(instanceName);
|
|
||||||
|
|
||||||
return this.prisma.webhook.upsert({
|
return this.prisma.webhook.upsert({
|
||||||
where: {
|
where: {
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
...data,
|
...data.webhook,
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
enabled: data.enabled,
|
enabled: data.webhook.enabled,
|
||||||
events: data.events,
|
events: data.webhook.events,
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
||||||
url: data.url,
|
url: data.webhook.url,
|
||||||
webhookBase64: data.webhookBase64,
|
webhookBase64: data.webhook.base64,
|
||||||
webhookByEvents: data.webhookByEvents,
|
webhookByEvents: data.webhook.byEvents,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get(instanceName: string): Promise<wa.LocalWebHook> {
|
|
||||||
if (undefined === this.monitor.waInstances[instanceName]) {
|
|
||||||
throw new NotFoundException('Instance not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.prisma.webhook.findUnique({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
throw new NotFoundException('Instance webhook not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async emit({
|
public async emit({
|
||||||
instanceName,
|
instanceName,
|
||||||
origin,
|
origin,
|
||||||
@ -80,13 +59,14 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
apiKey,
|
apiKey,
|
||||||
local,
|
local,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
const instanceWebhook = await this.get(instanceName);
|
const instance = (await this.get(instanceName)) as EventDto;
|
||||||
if (!instanceWebhook || !instanceWebhook.enabled) {
|
|
||||||
|
if (!instance || !instance.webhook.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhookConfig = configService.get<Webhook>('WEBHOOK');
|
const webhookConfig = configService.get<Webhook>('WEBHOOK');
|
||||||
const webhookLocal = instanceWebhook?.events;
|
const webhookLocal = instance.webhook?.events;
|
||||||
const we = event.replace(/[.-]/gm, '_').toUpperCase();
|
const we = event.replace(/[.-]/gm, '_').toUpperCase();
|
||||||
const transformedWe = we.replace(/_/gm, '-').toLowerCase();
|
const transformedWe = we.replace(/_/gm, '-').toLowerCase();
|
||||||
const enabledLog = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
const enabledLog = configService.get<Log>('LOG').LEVEL.includes('WEBHOOKS');
|
||||||
@ -95,7 +75,7 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
event,
|
event,
|
||||||
instance: instanceName,
|
instance: instanceName,
|
||||||
data,
|
data,
|
||||||
destination: instanceWebhook?.url,
|
destination: instance.webhook?.url,
|
||||||
date_time: dateTime,
|
date_time: dateTime,
|
||||||
sender,
|
sender,
|
||||||
server_url: serverUrl,
|
server_url: serverUrl,
|
||||||
@ -106,10 +86,10 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) {
|
if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) {
|
||||||
let baseURL: string;
|
let baseURL: string;
|
||||||
|
|
||||||
if (instanceWebhook?.webhookByEvents) {
|
if (instance.webhook?.byEvents) {
|
||||||
baseURL = `${instanceWebhook?.url}/${transformedWe}`;
|
baseURL = `${instance.webhook?.url}/${transformedWe}`;
|
||||||
} else {
|
} else {
|
||||||
baseURL = instanceWebhook?.url;
|
baseURL = instance.webhook?.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabledLog) {
|
if (enabledLog) {
|
||||||
@ -123,7 +103,7 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (instanceWebhook?.enabled && isURL(instanceWebhook.url, { require_tld: false })) {
|
if (instance.webhook?.enabled && isURL(instance.webhook.url, { require_tld: false })) {
|
||||||
const httpService = axios.create({ baseURL });
|
const httpService = axios.create({ baseURL });
|
||||||
|
|
||||||
await httpService.post('', webhookData);
|
await httpService.post('', webhookData);
|
||||||
@ -190,12 +170,13 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
public async receiveWebhook(data: any) {
|
public async receiveWebhook(data: any) {
|
||||||
if (data.object === 'whatsapp_business_account') {
|
if (data.object === 'whatsapp_business_account') {
|
||||||
if (data.entry[0]?.changes[0]?.field === 'message_template_status_update') {
|
if (data.entry[0]?.changes[0]?.field === 'message_template_status_update') {
|
||||||
const template = await this.prismaRepository.template.findFirst({
|
const template = await this.prisma.template.findFirst({
|
||||||
where: { templateId: `${data.entry[0].changes[0].value.message_template_id}` },
|
where: { templateId: `${data.entry[0].changes[0].value.message_template_id}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!template) {
|
if (!template) {
|
||||||
console.log('template not found');
|
console.log('template not found');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,29 +190,27 @@ export class WebhookController extends EventController implements EventControlle
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.entry?.forEach(async (entry: any) => {
|
for (const entry of data.entry) {
|
||||||
const numberId = entry.changes[0].value.metadata.phone_number_id;
|
const numberId = entry.changes[0].value.metadata.phone_number_id;
|
||||||
|
|
||||||
if (!numberId) {
|
if (!numberId) {
|
||||||
this.logger.error('WebhookService -> receiveWebhook -> numberId not found');
|
this.logger.error('WebhookService -> receiveWebhook -> numberId not found');
|
||||||
return;
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = await this.prismaRepository.instance.findFirst({
|
const instance = await this.prisma.instance.findFirst({
|
||||||
where: { number: numberId },
|
where: { number: numberId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
this.logger.error('WebhookService -> receiveWebhook -> instance not found');
|
this.logger.error('WebhookService -> receiveWebhook -> instance not found');
|
||||||
return;
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.waMonitor.waInstances[instance.name].connectToWhatsapp(data);
|
await this.monitor.waInstances[instance.name].connectToWhatsapp(data);
|
||||||
|
}
|
||||||
return;
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,23 +1,22 @@
|
|||||||
import { RouterBroker } from '@api/abstract/abstract.router';
|
import { RouterBroker } from '@api/abstract/abstract.router';
|
||||||
import { InstanceDto } from '@api/dto/instance.dto';
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { HttpStatus } from '@api/routes/index.router';
|
import { HttpStatus } from '@api/routes/index.router';
|
||||||
import { webhookController } from '@api/server.module';
|
import { eventManager } from '@api/server.module';
|
||||||
import { ConfigService, WaBusiness } from '@config/env.config';
|
import { ConfigService, WaBusiness } from '@config/env.config';
|
||||||
import { instanceSchema, webhookSchema } from '@validate/validate.schema';
|
import { instanceSchema, webhookSchema } from '@validate/validate.schema';
|
||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
|
||||||
|
|
||||||
export class WebhookRouter extends RouterBroker {
|
export class WebhookRouter extends RouterBroker {
|
||||||
constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) {
|
constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) {
|
||||||
super();
|
super();
|
||||||
this.router
|
this.router
|
||||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
const response = await this.dataValidate<WebhookDto>({
|
const response = await this.dataValidate<EventDto>({
|
||||||
request: req,
|
request: req,
|
||||||
schema: webhookSchema,
|
schema: webhookSchema,
|
||||||
ClassRef: WebhookDto,
|
ClassRef: EventDto,
|
||||||
execute: (instance, data) => webhookController.set(instance.instanceName, data),
|
execute: (instance, data) => eventManager.webhook.set(instance.instanceName, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
@ -27,7 +26,7 @@ export class WebhookRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: instanceSchema,
|
schema: instanceSchema,
|
||||||
ClassRef: InstanceDto,
|
ClassRef: InstanceDto,
|
||||||
execute: (instance) => webhookController.get(instance.instanceName),
|
execute: (instance) => eventManager.webhook.get(instance.instanceName),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.OK).json(response);
|
res.status(HttpStatus.OK).json(response);
|
||||||
@ -39,7 +38,7 @@ export class WebhookRouter extends RouterBroker {
|
|||||||
})
|
})
|
||||||
.post('meta', async (req, res) => {
|
.post('meta', async (req, res) => {
|
||||||
const { body } = req;
|
const { body } = req;
|
||||||
const response = await webhookController.receiveWebhook(body);
|
const response = await eventManager.webhook.receiveWebhook(body);
|
||||||
|
|
||||||
return res.status(200).json(response);
|
return res.status(200).json(response);
|
||||||
});
|
});
|
@ -1,13 +0,0 @@
|
|||||||
import { Constructor } from '@api/integrations/integration.dto';
|
|
||||||
|
|
||||||
export class WebsocketDto {
|
|
||||||
enabled: boolean;
|
|
||||||
events?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WebsocketInstanceMixin<TBase extends Constructor>(Base: TBase) {
|
|
||||||
return class extends Base {
|
|
||||||
websocketEnabled?: boolean;
|
|
||||||
websocketEvents?: string[];
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import { JSONSchema7 } from 'json-schema';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
|
||||||
const properties = {};
|
|
||||||
propertyNames.forEach(
|
|
||||||
(property) =>
|
|
||||||
(properties[property] = {
|
|
||||||
minLength: 1,
|
|
||||||
description: `The "${property}" cannot be empty`,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
if: {
|
|
||||||
propertyNames: {
|
|
||||||
enum: [...propertyNames],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
then: { properties },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const websocketSchema: JSONSchema7 = {
|
|
||||||
$id: v4(),
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
enabled: { type: 'boolean', enum: [true, false] },
|
|
||||||
events: {
|
|
||||||
type: 'array',
|
|
||||||
minItems: 0,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
enum: [
|
|
||||||
'APPLICATION_STARTUP',
|
|
||||||
'QRCODE_UPDATED',
|
|
||||||
'MESSAGES_SET',
|
|
||||||
'MESSAGES_UPSERT',
|
|
||||||
'MESSAGES_EDITED',
|
|
||||||
'MESSAGES_UPDATE',
|
|
||||||
'MESSAGES_DELETE',
|
|
||||||
'SEND_MESSAGE',
|
|
||||||
'CONTACTS_SET',
|
|
||||||
'CONTACTS_UPSERT',
|
|
||||||
'CONTACTS_UPDATE',
|
|
||||||
'PRESENCE_UPDATE',
|
|
||||||
'CHATS_SET',
|
|
||||||
'CHATS_UPSERT',
|
|
||||||
'CHATS_UPDATE',
|
|
||||||
'CHATS_DELETE',
|
|
||||||
'GROUPS_UPSERT',
|
|
||||||
'GROUP_UPDATE',
|
|
||||||
'GROUP_PARTICIPANTS_UPDATE',
|
|
||||||
'CONNECTION_UPDATE',
|
|
||||||
'LABELS_EDIT',
|
|
||||||
'LABELS_ASSOCIATION',
|
|
||||||
'CALL',
|
|
||||||
'TYPEBOT_START',
|
|
||||||
'TYPEBOT_CHANGE_STATUS',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ['enabled'],
|
|
||||||
...isNotEmpty('enabled'),
|
|
||||||
};
|
|
@ -1,28 +1,28 @@
|
|||||||
import { WebsocketDto } from '@api/integrations/event/websocket/dto/websocket.dto';
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { WAMonitoringService } from '@api/services/monitor.service';
|
import { WAMonitoringService } from '@api/services/monitor.service';
|
||||||
import { wa } from '@api/types/wa.types';
|
|
||||||
import { configService, Cors, Log, Websocket } from '@config/env.config';
|
import { configService, Cors, Log, Websocket } from '@config/env.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
import { NotFoundException } from '@exceptions';
|
|
||||||
import { Server } from 'http';
|
import { Server } from 'http';
|
||||||
import { Server as SocketIO } from 'socket.io';
|
import { Server as SocketIO } from 'socket.io';
|
||||||
|
|
||||||
import { EmitData, EventController, EventControllerInterface } from '../../event.controller';
|
import { EmitData, EventController, EventControllerInterface } from '../event.controller';
|
||||||
|
|
||||||
export class WebsocketController extends EventController implements EventControllerInterface {
|
export class WebsocketController extends EventController implements EventControllerInterface {
|
||||||
private io: SocketIO;
|
private io: SocketIO;
|
||||||
private corsConfig: Array<any>;
|
private corsConfig: Array<any>;
|
||||||
private readonly logger = new Logger(WebsocketController.name);
|
private readonly logger = new Logger(WebsocketController.name);
|
||||||
integrationEnabled = configService.get<Websocket>('WEBSOCKET')?.ENABLED;
|
|
||||||
|
|
||||||
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) {
|
||||||
super(prismaRepository, waMonitor);
|
super(prismaRepository, waMonitor, configService.get<Websocket>('WEBSOCKET')?.ENABLED, 'websocket');
|
||||||
|
|
||||||
this.cors = configService.get<Cors>('CORS').ORIGIN;
|
this.cors = configService.get<Cors>('CORS').ORIGIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(httpServer: Server): void {
|
public init(httpServer: Server): void {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.socket = new SocketIO(httpServer, {
|
this.socket = new SocketIO(httpServer, {
|
||||||
cors: {
|
cors: {
|
||||||
@ -57,57 +57,6 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
return this.io;
|
return this.io;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async set(instanceName: string, data: WebsocketDto): Promise<wa.LocalWebsocket> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (!data.enabled) {
|
|
||||||
data.events = [];
|
|
||||||
} else {
|
|
||||||
if (0 === data.events.length) {
|
|
||||||
data.events = this.events;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.get(instanceName);
|
|
||||||
|
|
||||||
return this.prisma.websocket.update({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
return this.prisma.websocket.create({
|
|
||||||
data: {
|
|
||||||
enabled: data.enabled,
|
|
||||||
events: data.events,
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async get(instanceName: string): Promise<wa.LocalWebsocket> {
|
|
||||||
if (!this.integrationEnabled) return;
|
|
||||||
|
|
||||||
if (undefined === this.monitor.waInstances[instanceName]) {
|
|
||||||
throw new NotFoundException('Instance not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.prisma.websocket.findUnique({
|
|
||||||
where: {
|
|
||||||
instanceId: this.monitor.waInstances[instanceName].instanceId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
throw new NotFoundException('Instance websocket not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async emit({
|
public async emit({
|
||||||
instanceName,
|
instanceName,
|
||||||
origin,
|
origin,
|
||||||
@ -118,7 +67,9 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
sender,
|
sender,
|
||||||
apiKey,
|
apiKey,
|
||||||
}: EmitData): Promise<void> {
|
}: EmitData): Promise<void> {
|
||||||
if (!this.integrationEnabled) return;
|
if (!this.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const configEv = event.replace(/[.-]/gm, '_').toUpperCase();
|
const configEv = event.replace(/[.-]/gm, '_').toUpperCase();
|
||||||
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBSOCKET');
|
const logEnabled = configService.get<Log>('LOG').LEVEL.includes('WEBSOCKET');
|
||||||
@ -144,13 +95,13 @@ export class WebsocketController extends EventController implements EventControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const instanceSocket = await this.get(instanceName);
|
const instance = (await this.get(instanceName)) as EventDto;
|
||||||
|
|
||||||
if (!instanceSocket?.enabled) {
|
if (!instance?.websocket.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(instanceSocket?.events) && instanceSocket?.events.includes(configEv)) {
|
if (Array.isArray(instance?.websocket.events) && instance?.websocket.events.includes(configEv)) {
|
||||||
this.socket.of(`/${instanceName}`).emit(event, message);
|
this.socket.of(`/${instanceName}`).emit(event, message);
|
||||||
|
|
||||||
if (logEnabled) {
|
if (logEnabled) {
|
@ -1,9 +1,9 @@
|
|||||||
import { RouterBroker } from '@api/abstract/abstract.router';
|
import { RouterBroker } from '@api/abstract/abstract.router';
|
||||||
import { InstanceDto } from '@api/dto/instance.dto';
|
import { InstanceDto } from '@api/dto/instance.dto';
|
||||||
import { WebsocketDto } from '@api/integrations/event/websocket/dto/websocket.dto';
|
import { EventDto } from '@api/integrations/event/event.dto';
|
||||||
import { websocketController } from '@api/server.module';
|
|
||||||
import { HttpStatus } from '@api/routes/index.router';
|
import { HttpStatus } from '@api/routes/index.router';
|
||||||
import { instanceSchema, websocketSchema } from '@validate/validate.schema';
|
import { eventManager } from '@api/server.module';
|
||||||
|
import { eventSchema, instanceSchema } from '@validate/validate.schema';
|
||||||
import { RequestHandler, Router } from 'express';
|
import { RequestHandler, Router } from 'express';
|
||||||
|
|
||||||
export class WebsocketRouter extends RouterBroker {
|
export class WebsocketRouter extends RouterBroker {
|
||||||
@ -11,11 +11,11 @@ export class WebsocketRouter extends RouterBroker {
|
|||||||
super();
|
super();
|
||||||
this.router
|
this.router
|
||||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
const response = await this.dataValidate<WebsocketDto>({
|
const response = await this.dataValidate<EventDto>({
|
||||||
request: req,
|
request: req,
|
||||||
schema: websocketSchema,
|
schema: eventSchema,
|
||||||
ClassRef: WebsocketDto,
|
ClassRef: EventDto,
|
||||||
execute: (instance, data) => websocketController.set(instance.instanceName, data),
|
execute: (instance, data) => eventManager.websocket.set(instance.instanceName, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
@ -25,7 +25,7 @@ export class WebsocketRouter extends RouterBroker {
|
|||||||
request: req,
|
request: req,
|
||||||
schema: instanceSchema,
|
schema: instanceSchema,
|
||||||
ClassRef: InstanceDto,
|
ClassRef: InstanceDto,
|
||||||
execute: (instance) => websocketController.get(instance.instanceName),
|
execute: (instance) => eventManager.websocket.get(instance.instanceName),
|
||||||
});
|
});
|
||||||
|
|
||||||
res.status(HttpStatus.OK).json(response);
|
res.status(HttpStatus.OK).json(response);
|
@ -1,11 +1,6 @@
|
|||||||
import { ChatwootInstanceMixin } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto';
|
import { ChatwootInstanceMixin } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto';
|
||||||
import { RabbitMQInstanceMixin } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto';
|
import { EventInstanceMixin } from '@api/integrations/event/event.dto';
|
||||||
import { SQSInstanceMixin } from '@api/integrations/event/sqs/dto/sqs.dto';
|
|
||||||
import { WebhookInstanceMixin } from '@api/integrations/event/webhook/dto/webhook.dto';
|
|
||||||
import { WebsocketInstanceMixin } from '@api/integrations/event/websocket/dto/websocket.dto';
|
|
||||||
|
|
||||||
export type Constructor<T = {}> = new (...args: any[]) => T;
|
export type Constructor<T = {}> = new (...args: any[]) => T;
|
||||||
|
|
||||||
export class IntegrationDto extends WebhookInstanceMixin(
|
export class IntegrationDto extends EventInstanceMixin(ChatwootInstanceMixin(class {})) {}
|
||||||
WebsocketInstanceMixin(RabbitMQInstanceMixin(SQSInstanceMixin(ChatwootInstanceMixin(class {})))),
|
|
||||||
) {}
|
|
||||||
|
@ -23,11 +23,7 @@ import { OpenaiController } from './integrations/chatbot/openai/controllers/open
|
|||||||
import { OpenaiService } from './integrations/chatbot/openai/services/openai.service';
|
import { OpenaiService } from './integrations/chatbot/openai/services/openai.service';
|
||||||
import { TypebotController } from './integrations/chatbot/typebot/controllers/typebot.controller';
|
import { TypebotController } from './integrations/chatbot/typebot/controllers/typebot.controller';
|
||||||
import { TypebotService } from './integrations/chatbot/typebot/services/typebot.service';
|
import { TypebotService } from './integrations/chatbot/typebot/services/typebot.service';
|
||||||
import { EventController } from './integrations/event/event.controller';
|
import { EventManager } from './integrations/event/event.manager';
|
||||||
import { RabbitmqController } from './integrations/event/rabbitmq/controllers/rabbitmq.controller';
|
|
||||||
import { SqsController } from './integrations/event/sqs/controllers/sqs.controller';
|
|
||||||
import { WebhookController } from './integrations/event/webhook/controllers/webhook.controller';
|
|
||||||
import { WebsocketController } from './integrations/event/websocket/controllers/websocket.controller';
|
|
||||||
import { S3Controller } from './integrations/storage/s3/controllers/s3.controller';
|
import { S3Controller } from './integrations/storage/s3/controllers/s3.controller';
|
||||||
import { S3Service } from './integrations/storage/s3/services/s3.service';
|
import { S3Service } from './integrations/storage/s3/services/s3.service';
|
||||||
import { ProviderFiles } from './provider/sessions';
|
import { ProviderFiles } from './provider/sessions';
|
||||||
@ -98,16 +94,10 @@ export const chatController = new ChatController(waMonitor);
|
|||||||
export const groupController = new GroupController(waMonitor);
|
export const groupController = new GroupController(waMonitor);
|
||||||
export const labelController = new LabelController(waMonitor);
|
export const labelController = new LabelController(waMonitor);
|
||||||
|
|
||||||
export const eventController = new EventController(prismaRepository, waMonitor);
|
export const eventManager = new EventManager(prismaRepository, waMonitor);
|
||||||
export const chatbotController = new ChatbotController(prismaRepository, waMonitor);
|
export const chatbotController = new ChatbotController(prismaRepository, waMonitor);
|
||||||
export const channelController = new ChannelController();
|
export const channelController = new ChannelController();
|
||||||
|
|
||||||
// events
|
|
||||||
export const websocketController = new WebsocketController(prismaRepository, waMonitor);
|
|
||||||
export const rabbitmqController = new RabbitmqController(prismaRepository, waMonitor);
|
|
||||||
export const sqsController = new SqsController(prismaRepository, waMonitor);
|
|
||||||
export const webhookController = new WebhookController(prismaRepository, waMonitor);
|
|
||||||
|
|
||||||
// chatbots
|
// chatbots
|
||||||
const typebotService = new TypebotService(waMonitor, configService, prismaRepository);
|
const typebotService = new TypebotService(waMonitor, configService, prismaRepository);
|
||||||
export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor);
|
export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor);
|
||||||
|
@ -7,7 +7,7 @@ import { DifyService } from '@api/integrations/chatbot/dify/services/dify.servic
|
|||||||
import { OpenaiService } from '@api/integrations/chatbot/openai/services/openai.service';
|
import { OpenaiService } from '@api/integrations/chatbot/openai/services/openai.service';
|
||||||
import { TypebotService } from '@api/integrations/chatbot/typebot/services/typebot.service';
|
import { TypebotService } from '@api/integrations/chatbot/typebot/services/typebot.service';
|
||||||
import { PrismaRepository, Query } from '@api/repository/repository.service';
|
import { PrismaRepository, Query } from '@api/repository/repository.service';
|
||||||
import { eventController, waMonitor } from '@api/server.module';
|
import { eventManager, waMonitor } from '@api/server.module';
|
||||||
import { Events, wa } from '@api/types/wa.types';
|
import { Events, wa } from '@api/types/wa.types';
|
||||||
import { Auth, Chatwoot, ConfigService, HttpServer } from '@config/env.config';
|
import { Auth, Chatwoot, ConfigService, HttpServer } from '@config/env.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
@ -392,7 +392,7 @@ export class ChannelStartupService {
|
|||||||
|
|
||||||
const instanceApikey = this.token || 'Apikey not found';
|
const instanceApikey = this.token || 'Apikey not found';
|
||||||
|
|
||||||
await eventController.emit({
|
await eventManager.emit({
|
||||||
instanceName: this.instance.name,
|
instanceName: this.instance.name,
|
||||||
origin: ChannelStartupService.name,
|
origin: ChannelStartupService.name,
|
||||||
event,
|
event,
|
||||||
|
@ -60,14 +60,6 @@ export declare namespace wa {
|
|||||||
businessId?: string;
|
businessId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalWebHook = {
|
|
||||||
enabled?: boolean;
|
|
||||||
url?: string;
|
|
||||||
events?: JsonValue;
|
|
||||||
webhookByEvents?: boolean;
|
|
||||||
webhookBase64?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LocalChatwoot = {
|
export type LocalChatwoot = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
accountId?: string;
|
accountId?: string;
|
||||||
@ -95,19 +87,15 @@ export declare namespace wa {
|
|||||||
syncFullHistory?: boolean;
|
syncFullHistory?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalWebsocket = {
|
export type LocalEvent = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
events?: JsonValue;
|
events?: JsonValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalRabbitmq = {
|
export type LocalWebHook = LocalEvent & {
|
||||||
enabled?: boolean;
|
url?: string;
|
||||||
events?: JsonValue;
|
webhookByEvents?: boolean;
|
||||||
};
|
webhookBase64?: boolean;
|
||||||
|
|
||||||
export type LocalSqs = {
|
|
||||||
enabled?: boolean;
|
|
||||||
events?: JsonValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Session = {
|
type Session = {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ProviderFiles } from '@api/provider/sessions';
|
import { ProviderFiles } from '@api/provider/sessions';
|
||||||
import { PrismaRepository } from '@api/repository/repository.service';
|
import { PrismaRepository } from '@api/repository/repository.service';
|
||||||
import { HttpStatus, router } from '@api/routes/index.router';
|
import { HttpStatus, router } from '@api/routes/index.router';
|
||||||
import { eventController, waMonitor } from '@api/server.module';
|
import { eventManager, waMonitor } from '@api/server.module';
|
||||||
import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config';
|
import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config';
|
||||||
import { onUnexpectedError } from '@config/error.config';
|
import { onUnexpectedError } from '@config/error.config';
|
||||||
import { Logger } from '@config/logger.config';
|
import { Logger } from '@config/logger.config';
|
||||||
@ -139,7 +139,7 @@ async function bootstrap() {
|
|||||||
ServerUP.app = app;
|
ServerUP.app = app;
|
||||||
const server = ServerUP[httpServer.TYPE];
|
const server = ServerUP[httpServer.TYPE];
|
||||||
|
|
||||||
eventController.init(server);
|
eventManager.init(server);
|
||||||
|
|
||||||
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
|
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user