@@ -23,20 +23,20 @@ function matchUsers(channel, msg, userId, language, difficulty) {
23
23
waitingUsers [ criteriaKey ] = [ ] ;
24
24
}
25
25
26
- waitingUsers [ criteriaKey ] . push ( { userId, msg } ) ; // Store both userId and the message
26
+ // Store both the userId, message, and the channel in waitingUsers
27
+ waitingUsers [ criteriaKey ] . push ( { userId, msg, channel } ) ;
27
28
console . log ( `User ${ userId } added to ${ criteriaKey } . Waiting list: ${ waitingUsers [ criteriaKey ] . length } ` ) ;
28
29
29
30
// Check if there are 2 or more users waiting for this criteria
30
31
if ( waitingUsers [ criteriaKey ] . length >= 2 ) {
31
32
const matchedUsers = waitingUsers [ criteriaKey ] . splice ( 0 , 2 ) ; // Match the first two users
32
33
console . log ( `Matched users: ${ matchedUsers . map ( user => user . userId ) } ` ) ;
33
34
34
- // Send match success (this could trigger WebSocket communication)
35
- // notifyUsers(matchedUsers.map(user => user.userId));
35
+ // Notify users of the match
36
36
notifyUsers ( matchedUsers . map ( user => user . userId ) , 'Match found!' , 'match' ) ;
37
37
38
38
// Acknowledge the messages for both matched users
39
- matchedUsers . forEach ( ( { msg } ) => {
39
+ matchedUsers . forEach ( ( { msg, channel } ) => {
40
40
acknowledgeMessage ( channel , msg ) ;
41
41
} ) ;
42
42
@@ -46,6 +46,7 @@ function matchUsers(channel, msg, userId, language, difficulty) {
46
46
return false ;
47
47
}
48
48
49
+
49
50
async function acknowledgeMessage ( channel , msg ) {
50
51
return new Promise ( ( resolve , reject ) => {
51
52
try {
@@ -64,19 +65,46 @@ async function acknowledgeMessage(channel, msg) {
64
65
async function rejectMessage ( channel , msg , userId ) {
65
66
return new Promise ( ( resolve , reject ) => {
66
67
try {
68
+ // Get user data from the message to find the correct key in waitingUsers
69
+ const userData = JSON . parse ( msg . content . toString ( ) ) ;
70
+ const { language, difficulty } = userData ;
71
+
72
+ // Correctly creating the criteriaKey using template literals
73
+ const criteriaKey = `${ difficulty } .${ language } ` ;
74
+
75
+
76
+ // Find the user in the waitingUsers list and remove them
77
+ if ( waitingUsers [ criteriaKey ] ) {
78
+ // Find the index of the user in the waiting list
79
+ const userIndex = waitingUsers [ criteriaKey ] . findIndex ( user => user . userId === userId ) ;
80
+
81
+ if ( userIndex !== - 1 ) {
82
+ // Remove the user from the waiting list
83
+ waitingUsers [ criteriaKey ] . splice ( userIndex , 1 ) ;
84
+ console . log ( `Removed user ${ userId } from waiting list for ${ criteriaKey } ` ) ;
85
+ }
86
+ }
87
+
88
+ // Reject the message without requeuing
67
89
channel . reject ( msg , false ) ; // Reject without requeuing
68
90
console . log ( `Rejected message for user: ${ userId } ` ) ;
91
+
92
+ // Clean up the timeoutMap
93
+ if ( timeoutMap [ userId ] ) {
94
+ clearTimeout ( timeoutMap [ userId ] ) ;
95
+ delete timeoutMap [ userId ] ;
96
+ }
97
+
69
98
resolve ( ) ;
70
99
} catch ( error ) {
71
- console . error ( `Failed to reject message for user ${ userId } :` , error ) ;
100
+ console . error ( `Failed to reject message for user ${ userId } :, error` ) ;
72
101
reject ( error ) ;
73
102
}
74
103
} ) ;
75
104
}
76
105
77
106
async function consumeQueue ( ) {
78
107
try {
79
- // Connect
80
108
const connection = await amqp . connect ( process . env . RABBITMQ_URL ) ;
81
109
const channel = await connection . createChannel ( ) ;
82
110
@@ -95,23 +123,23 @@ async function consumeQueue() {
95
123
// Call matchUsers with channel, message, and user details
96
124
const matched = matchUsers ( channel , msg , userId , language , difficulty ) ;
97
125
98
- // If not matched, set a timeout for rejection
99
126
if ( ! matched ) {
100
127
console . log ( `No match for ${ userId } , waiting for rejection timeout.` ) ;
101
128
102
- // Set a timeout for rejection after 10 seconds
103
129
const timeoutId = setTimeout ( async ( ) => {
104
130
await rejectMessage ( channel , msg , userId ) ;
105
131
} , 10000 ) ; // 10 seconds delay
106
132
107
- // Store the timeout ID
108
133
timeoutMap [ userId ] = timeoutId ;
109
134
}
110
135
}
111
- } ) ;
136
+ } , { noAck : false } ) ; // Ensure manual acknowledgment
112
137
}
113
138
114
139
console . log ( "Listening to matchmaking queues" ) ;
140
+
141
+ await consumeCancelQueue ( ) ;
142
+ console . log ( "Listening to Cancel Queue" ) ;
115
143
} catch ( error ) {
116
144
console . error ( 'Error consuming RabbitMQ queue:' , error ) ;
117
145
}
@@ -144,4 +172,71 @@ async function consumeDLQ() {
144
172
}
145
173
}
146
174
175
+ async function consumeCancelQueue ( ) {
176
+ try {
177
+ const connection = await amqp . connect ( process . env . RABBITMQ_URL ) ;
178
+ const channel = await connection . createChannel ( ) ;
179
+
180
+ // Subscribe to the cancel queue
181
+ await channel . consume ( 'cancel_queue' , async ( msg ) => {
182
+ if ( msg !== null ) {
183
+ const { userId } = JSON . parse ( msg . content . toString ( ) ) ;
184
+ console . log ( `Received cancel request for user: ${ userId } ` ) ;
185
+
186
+ // Process the cancel request
187
+ await cancelMatching ( channel , msg , userId ) ;
188
+ }
189
+ } , { noAck : false } ) ; // Ensure manual acknowledgment
190
+
191
+ console . log ( "Listening for cancel requests" ) ;
192
+ } catch ( error ) {
193
+ console . error ( 'Error consuming cancel queue:' , error ) ;
194
+ }
195
+ }
196
+
197
+ async function cancelMatching ( cancelChannel , cancelMsg , userId ) {
198
+ try {
199
+ let foundOriginalMsg = false ;
200
+
201
+ // Loop through waitingUsers to find the original message for the user
202
+ Object . keys ( waitingUsers ) . forEach ( criteriaKey => {
203
+ const userIndex = waitingUsers [ criteriaKey ] . findIndex ( user => user . userId === userId ) ;
204
+
205
+ if ( userIndex !== - 1 ) {
206
+ const { msg, channel } = waitingUsers [ criteriaKey ] [ userIndex ] ; // Get original msg and its channel
207
+
208
+ // Acknowledge the original matchmaking message from the queue (e.g., easy.python)
209
+ if ( msg && channel ) {
210
+ console . log ( `Acknowledging original message for user ${ userId } in queue ${ criteriaKey } ` ) ;
211
+ channel . ack ( msg ) ; // Use the same channel that consumed the message to acknowledge it
212
+ foundOriginalMsg = true ;
213
+ }
214
+
215
+ // Remove the user from the waiting list
216
+ waitingUsers [ criteriaKey ] . splice ( userIndex , 1 ) ;
217
+ console . log ( `User ${ userId } removed from waiting list for ${ criteriaKey } ` ) ;
218
+ }
219
+ } ) ;
220
+
221
+ // If original message not found, log a warning
222
+ if ( ! foundOriginalMsg ) {
223
+ console . warn ( `Original message for user ${ userId } not found in matchmaking queues.` ) ;
224
+ }
225
+
226
+ // Clear any timeouts for the user
227
+ if ( timeoutMap [ userId ] ) {
228
+ clearTimeout ( timeoutMap [ userId ] ) ;
229
+ delete timeoutMap [ userId ] ;
230
+ }
231
+
232
+ // Acknowledge the cancel message from the cancel queue
233
+ cancelChannel . ack ( cancelMsg ) ;
234
+ console . log ( `Cancel processed for user ${ userId } ` ) ;
235
+
236
+ } catch ( error ) {
237
+ console . error ( `Failed to process cancel for user ${ userId } :` , error ) ;
238
+ }
239
+ }
240
+
241
+
147
242
module . exports = { consumeQueue, consumeDLQ } ;
0 commit comments