1- import * as amqp from 'amqplib/callback_api' ;
1+ import { Channel , connect } from 'amqplib/callback_api' ;
22
3- import { configService , Rabbitmq } from '../config/env.config' ;
3+ import { configService , HttpServer , Rabbitmq } from '../config/env.config' ;
44import { Logger } from '../config/logger.config' ;
5+ import { Events } from '../whatsapp/types/wa.types' ;
56
67const logger = new Logger ( 'AMQP' ) ;
78
8- let amqpChannel : amqp . Channel | null = null ;
9+ const parseEvtName = ( evt : string ) => evt . replace ( / _ / g, '.' ) . toLowerCase ( ) ;
10+
11+ const globalQueues : { [ key : string ] : Events [ ] } = {
12+ contacts : [ Events . CONTACTS_SET , Events . CONTACTS_UPDATE , Events . CONTACTS_UPSERT ] ,
13+ messages : [
14+ Events . MESSAGES_DELETE ,
15+ Events . MESSAGES_SET ,
16+ Events . MESSAGES_UPDATE ,
17+ Events . MESSAGES_UPSERT ,
18+ Events . MESSAGING_HISTORY_SET ,
19+ Events . SEND_MESSAGE ,
20+ ] ,
21+ chats : [ Events . CHATS_DELETE , Events . CHATS_SET , Events . CHATS_UPDATE , Events . CHATS_UPSERT ] ,
22+ groups : [ Events . GROUPS_UPDATE , Events . GROUPS_UPSERT , Events . GROUP_PARTICIPANTS_UPDATE ] ,
23+ others : [ ] , // All other events not included in the above categories
24+ } ;
25+
26+ let amqpChannel : Channel | null = null ;
927
1028export const initAMQP = ( ) => {
1129 return new Promise < void > ( ( resolve , reject ) => {
12- const uri = configService . get < Rabbitmq > ( 'RABBITMQ' ) . URI ;
13- amqp . connect ( uri , ( error , connection ) => {
30+ const rabbitConfig = configService . get < Rabbitmq > ( 'RABBITMQ' ) ;
31+ connect ( rabbitConfig . URI , ( error , connection ) => {
1432 if ( error ) {
1533 reject ( error ) ;
1634 return ;
@@ -22,12 +40,9 @@ export const initAMQP = () => {
2240 return ;
2341 }
2442
25- const exchangeName = 'evolution_exchange' ;
26-
27- channel . assertExchange ( exchangeName , 'topic' , {
43+ channel . assertExchange ( rabbitConfig . EXCHANGE_NAME , 'topic' , {
2844 durable : true ,
2945 autoDelete : false ,
30- assert : true ,
3146 } ) ;
3247
3348 amqpChannel = channel ;
@@ -39,65 +54,190 @@ export const initAMQP = () => {
3954 } ) ;
4055} ;
4156
42- export const getAMQP = ( ) : amqp . Channel | null => {
57+ export const getAMQP = ( ) : Channel | null => {
4358 return amqpChannel ;
4459} ;
4560
4661export const initQueues = ( instanceName : string , events : string [ ] ) => {
4762 if ( ! instanceName || ! events || ! events . length ) return ;
63+ const rabbitConfig = configService . get < Rabbitmq > ( 'RABBITMQ' ) ;
64+ const TWO_DAYS_IN_MS = 2 * 24 * 60 * 60 * 1000 ;
65+ const amqp = getAMQP ( ) ;
4866
49- const queues = events . map ( ( event ) => {
50- return `${ event . replace ( / _ / g, '.' ) . toLowerCase ( ) } ` ;
51- } ) ;
67+ let exchangeName = rabbitConfig . EXCHANGE_NAME ;
68+
69+ const receivedEvents = events . map ( parseEvtName ) ;
70+ if ( rabbitConfig . MODE === 'isolated' ) {
71+ exchangeName = instanceName ;
5272
53- queues . forEach ( ( event ) => {
54- const amqp = getAMQP ( ) ;
55- const exchangeName = instanceName ?? 'evolution_exchange' ;
73+ receivedEvents . forEach ( ( event ) => {
74+ amqp . assertExchange ( exchangeName , 'topic' , {
75+ durable : true ,
76+ autoDelete : false ,
77+ } ) ;
78+
79+ const queueName = `${ instanceName } .${ event } ` ;
80+ amqp . assertQueue ( queueName , {
81+ durable : true ,
82+ autoDelete : false ,
83+ messageTtl : TWO_DAYS_IN_MS ,
84+ arguments : {
85+ 'x-queue-type' : 'quorum' ,
86+ } ,
87+ } ) ;
5688
89+ amqp . bindQueue ( queueName , exchangeName , event ) ;
90+ } ) ;
91+ } else if ( rabbitConfig . MODE === 'single' ) {
5792 amqp . assertExchange ( exchangeName , 'topic' , {
5893 durable : true ,
5994 autoDelete : false ,
60- assert : true ,
6195 } ) ;
6296
63- const queueName = `${ instanceName } .${ event } ` ;
64-
97+ const queueName = 'evolution' ;
6598 amqp . assertQueue ( queueName , {
6699 durable : true ,
67100 autoDelete : false ,
101+ messageTtl : TWO_DAYS_IN_MS ,
68102 arguments : {
69103 'x-queue-type' : 'quorum' ,
70104 } ,
71105 } ) ;
72106
73- amqp . bindQueue ( queueName , exchangeName , event ) ;
74- } ) ;
107+ receivedEvents . forEach ( ( event ) => {
108+ amqp . bindQueue ( queueName , exchangeName , event ) ;
109+ } ) ;
110+ } else if ( rabbitConfig . MODE === 'global' ) {
111+ const queues = Object . keys ( globalQueues ) ;
112+
113+ const addQueues = queues . filter ( ( evt ) => {
114+ if ( evt === 'others' ) {
115+ return receivedEvents . some (
116+ ( e ) =>
117+ ! Object . values ( globalQueues )
118+ . flat ( )
119+ . includes ( e as Events ) ,
120+ ) ;
121+ }
122+ return globalQueues [ evt ] . some ( ( e ) => receivedEvents . includes ( e ) ) ;
123+ } ) ;
124+
125+ addQueues . forEach ( ( event ) => {
126+ amqp . assertExchange ( exchangeName , 'topic' , {
127+ durable : true ,
128+ autoDelete : false ,
129+ } ) ;
130+
131+ const queueName = event ;
132+ amqp . assertQueue ( queueName , {
133+ durable : true ,
134+ autoDelete : false ,
135+ messageTtl : TWO_DAYS_IN_MS ,
136+ arguments : {
137+ 'x-queue-type' : 'quorum' ,
138+ } ,
139+ } ) ;
140+
141+ if ( globalQueues [ event ] . length === 0 ) {
142+ // Other events
143+ const otherEvents = Object . values ( globalQueues ) . flat ( ) ;
144+ for ( const subEvent in Events ) {
145+ const eventCode = Events [ subEvent ] ;
146+ if ( otherEvents . includes ( eventCode ) ) continue ;
147+ if ( ! receivedEvents . includes ( eventCode ) ) continue ;
148+ amqp . bindQueue ( queueName , exchangeName , eventCode ) ;
149+ }
150+ } else {
151+ globalQueues [ event ] . forEach ( ( subEvent ) => {
152+ amqp . bindQueue ( queueName , exchangeName , subEvent ) ;
153+ } ) ;
154+ }
155+ } ) ;
156+ } else {
157+ throw new Error ( 'Invalid RabbitMQ mode' ) ;
158+ }
75159} ;
76160
77161export const removeQueues = ( instanceName : string , events : string [ ] ) => {
78162 if ( ! events || ! events . length ) return ;
163+ const rabbitConfig = configService . get < Rabbitmq > ( 'RABBITMQ' ) ;
164+ let exchangeName = rabbitConfig . EXCHANGE_NAME ;
165+ const amqp = getAMQP ( ) ;
166+
167+ const receivedEvents = events . map ( parseEvtName ) ;
168+ if ( rabbitConfig . MODE === 'isolated' ) {
169+ exchangeName = instanceName ;
170+ receivedEvents . forEach ( ( event ) => {
171+ amqp . assertExchange ( exchangeName , 'topic' , {
172+ durable : true ,
173+ autoDelete : false ,
174+ } ) ;
79175
80- const channel = getAMQP ( ) ;
176+ const queueName = `${ instanceName } .${ event } ` ;
177+ amqp . deleteQueue ( queueName ) ;
178+ } ) ;
179+ amqp . deleteExchange ( instanceName ) ;
180+ }
181+ } ;
81182
82- const queues = events . map ( ( event ) => {
83- return `${ event . replace ( / _ / g, '.' ) . toLowerCase ( ) } ` ;
183+ interface SendEventData {
184+ instanceName : string ;
185+ wuid : string ;
186+ event : string ;
187+ apiKey ?: string ;
188+ data : any ;
189+ }
190+
191+ export const sendEventData = ( { data, event, wuid, apiKey, instanceName } : SendEventData ) => {
192+ const rabbitConfig = configService . get < Rabbitmq > ( 'RABBITMQ' ) ;
193+ let exchangeName = rabbitConfig . EXCHANGE_NAME ;
194+ if ( rabbitConfig . MODE === 'isolated' ) exchangeName = instanceName ;
195+
196+ amqpChannel . assertExchange ( exchangeName , 'topic' , {
197+ durable : true ,
198+ autoDelete : false ,
84199 } ) ;
85-
86- const exchangeName = instanceName ?? 'evolution_exchange' ;
87-
88- queues . forEach ( ( event ) => {
89- const amqp = getAMQP ( ) ;
90-
91- amqp . assertExchange ( exchangeName , 'topic' , {
92- durable : true ,
93- autoDelete : false ,
94- assert : true ,
200+ let queueName = event ;
201+ if ( rabbitConfig . MODE === 'single' ) {
202+ queueName = 'evolution' ;
203+ } else if ( rabbitConfig . MODE === 'global' ) {
204+ let eventName = '' ;
205+ Object . keys ( globalQueues ) . forEach ( ( key ) => {
206+ if ( globalQueues [ key ] . includes ( event as Events ) ) {
207+ eventName = key ;
208+ }
209+ if ( eventName === '' && key === 'others' ) {
210+ eventName = key ;
211+ }
95212 } ) ;
96-
97- const queueName = `${ instanceName } .${ event } ` ;
98-
99- amqp . deleteQueue ( queueName ) ;
213+ queueName = eventName ;
214+ }
215+ amqpChannel . assertQueue ( queueName , {
216+ durable : true ,
217+ autoDelete : false ,
218+ arguments : { 'x-queue-type' : 'quorum' } ,
100219 } ) ;
101-
102- channel . deleteExchange ( exchangeName ) ;
220+ amqpChannel . bindQueue ( queueName , exchangeName , event ) ;
221+
222+ const serverUrl = configService . get < HttpServer > ( 'SERVER' ) . URL ;
223+ const tzoffset = new Date ( ) . getTimezoneOffset ( ) * 60000 ; //offset in milliseconds
224+ const localISOTime = new Date ( Date . now ( ) - tzoffset ) . toISOString ( ) ;
225+ const now = localISOTime ;
226+ const message = {
227+ event,
228+ instance : instanceName ,
229+ data,
230+ server_url : serverUrl ,
231+ date_time : now ,
232+ sender : wuid ,
233+ } ;
234+ if ( apiKey ) {
235+ message [ 'apikey' ] = apiKey ;
236+ }
237+ logger . log ( {
238+ queueName,
239+ exchangeName,
240+ event,
241+ } ) ;
242+ amqpChannel . publish ( exchangeName , event , Buffer . from ( JSON . stringify ( message ) ) ) ;
103243} ;
0 commit comments