@@ -16,6 +16,15 @@ var async = require('async');
16
16
17
17
module . exports = adapter ;
18
18
19
+ /**
20
+ * Request types, for messages between nodes
21
+ */
22
+
23
+ var requestTypes = {
24
+ clients : 0 ,
25
+ clientRooms : 1 ,
26
+ } ;
27
+
19
28
/**
20
29
* Returns a redis Adapter class.
21
30
*
@@ -39,7 +48,7 @@ function adapter(uri, opts){
39
48
40
49
var prefix = opts . key || 'socket.io' ;
41
50
var subEvent = opts . subEvent || 'message' ;
42
- var clientsTimeout = opts . clientsTimeout || 1000 ;
51
+ var requestsTimeout = opts . requestsTimeout || 1000 ;
43
52
44
53
// init clients if needed
45
54
function createClient ( redis_opts ) {
@@ -50,11 +59,9 @@ function adapter(uri, opts){
50
59
return redis ( opts . port , opts . host , redis_opts ) ;
51
60
}
52
61
}
53
-
62
+
54
63
if ( ! pub ) pub = createClient ( ) ;
55
64
if ( ! sub ) sub = createClient ( { return_buffers : true } ) ;
56
-
57
- var subJson = sub . duplicate ( { return_buffers : false } ) ;
58
65
59
66
// this server's key
60
67
var uid = uid2 ( 6 ) ;
@@ -71,10 +78,12 @@ function adapter(uri, opts){
71
78
72
79
this . uid = uid ;
73
80
this . prefix = prefix ;
74
- this . clientsTimeout = clientsTimeout ;
81
+ this . requestsTimeout = requestsTimeout ;
75
82
76
83
this . channel = prefix + '#' + nsp . name + '#' ;
77
- this . syncChannel = prefix + '-sync#request#' + this . nsp . name + '#' ;
84
+ this . requestChannel = prefix + '-request#' + this . nsp . name + '#' ;
85
+ this . responseChannel = prefix + '-response#' + this . nsp . name + '#' ;
86
+ this . requests = { } ;
78
87
79
88
if ( String . prototype . startsWith ) {
80
89
this . channelMatches = function ( messageChannel , subscribedChannel ) {
@@ -90,16 +99,11 @@ function adapter(uri, opts){
90
99
91
100
var self = this ;
92
101
93
- sub . subscribe ( this . channel , function ( err ) {
94
- if ( err ) self . emit ( 'error' , err ) ;
95
- } ) ;
96
-
97
- subJson . subscribe ( this . syncChannel , function ( err ) {
102
+ sub . subscribe ( [ this . channel , this . requestChannel , this . responseChannel ] , function ( err ) {
98
103
if ( err ) self . emit ( 'error' , err ) ;
99
104
} ) ;
100
105
101
106
sub . on ( subEvent , this . onmessage . bind ( this ) ) ;
102
- subJson . on ( subEvent , this . onclients . bind ( this ) ) ;
103
107
}
104
108
105
109
/**
@@ -115,9 +119,16 @@ function adapter(uri, opts){
115
119
*/
116
120
117
121
Redis . prototype . onmessage = function ( channel , msg ) {
118
- if ( ! this . channelMatches ( channel . toString ( ) , this . channel ) ) {
122
+ channel = channel . toString ( ) ;
123
+
124
+ if ( this . channelMatches ( channel , this . requestChannel ) ) {
125
+ return this . onrequest ( channel , msg ) ;
126
+ } else if ( this . channelMatches ( channel , this . responseChannel ) ) {
127
+ return this . onresponse ( channel , msg ) ;
128
+ } else if ( ! this . channelMatches ( channel , this . channel ) ) {
119
129
return debug ( 'ignore different channel' ) ;
120
130
}
131
+
121
132
var args = msgpack . decode ( msg ) ;
122
133
var packet ;
123
134
@@ -139,40 +150,119 @@ function adapter(uri, opts){
139
150
} ;
140
151
141
152
/**
142
- * Called with a subscription message on sync
153
+ * Called on request from another node
143
154
*
144
155
* @api private
145
156
*/
146
157
147
- Redis . prototype . onclients = function ( channel , msg ) {
148
-
158
+ Redis . prototype . onrequest = function ( channel , msg ) {
149
159
var self = this ;
160
+ var request ;
150
161
151
- if ( ! self . channelMatches ( channel . toString ( ) , self . syncChannel ) ) {
152
- return debug ( 'ignore different channel' ) ;
162
+ try {
163
+ request = JSON . parse ( msg ) ;
164
+ } catch ( err ) {
165
+ self . emit ( 'error' , err ) ;
166
+ return ;
153
167
}
154
168
169
+ debug ( 'received request %j' , request ) ;
170
+
171
+ switch ( request . type ) {
172
+
173
+ case requestTypes . clients :
174
+ Adapter . prototype . clients . call ( self , request . rooms , function ( err , clients ) {
175
+ if ( err ) {
176
+ self . emit ( 'error' , err ) ;
177
+ return ;
178
+ }
179
+
180
+ var response = JSON . stringify ( {
181
+ requestid : request . requestid ,
182
+ clients : clients
183
+ } ) ;
184
+
185
+ pub . publish ( self . responseChannel , response ) ;
186
+ } ) ;
187
+ break ;
188
+
189
+ case requestTypes . clientRooms :
190
+ Adapter . prototype . clientRooms . call ( self , request . sid , function ( err , rooms ) {
191
+ if ( err ) {
192
+ self . emit ( 'error' , err ) ;
193
+ return ;
194
+ }
195
+
196
+ if ( ! rooms ) { return ; }
197
+
198
+ var response = JSON . stringify ( {
199
+ requestid : request . requestid ,
200
+ rooms : rooms
201
+ } ) ;
202
+
203
+ pub . publish ( self . responseChannel , response ) ;
204
+ } ) ;
205
+ break ;
206
+
207
+ default :
208
+ debug ( 'ignoring unknown request type: %s' , request . type ) ;
209
+ }
210
+ } ;
211
+
212
+ /**
213
+ * Called on response from another node
214
+ *
215
+ * @api private
216
+ */
217
+
218
+ Redis . prototype . onresponse = function ( channel , msg ) {
219
+ var self = this ;
220
+ var response ;
221
+
155
222
try {
156
- var decoded = JSON . parse ( msg ) ;
223
+ response = JSON . parse ( msg ) ;
157
224
} catch ( err ) {
158
225
self . emit ( 'error' , err ) ;
159
226
return ;
160
227
}
161
228
162
- Adapter . prototype . clients . call ( self , decoded . rooms , function ( err , clients ) {
163
- if ( err ) {
164
- self . emit ( 'error' , err ) ;
165
- return ;
166
- }
229
+ if ( ! response . requestid || ! self . requests [ response . requestid ] ) {
230
+ debug ( 'ignoring unknown request' ) ;
231
+ return ;
232
+ }
167
233
168
- var responseChn = prefix + '-sync#response#' + decoded . transaction ;
169
- var response = JSON . stringify ( {
170
- clients : clients
171
- } ) ;
234
+ debug ( 'received response %j' , response ) ;
172
235
173
- pub . publish ( responseChn , response ) ;
174
- } ) ;
175
-
236
+ var request = self . requests [ response . requestid ] ;
237
+
238
+ switch ( request . type ) {
239
+
240
+ case requestTypes . clients :
241
+ request . msgCount ++ ;
242
+
243
+ // ignore if response does not contain 'clients' key
244
+ if ( ! response . clients || ! Array . isArray ( response . clients ) ) return ;
245
+
246
+ for ( var i = 0 ; i < response . clients . length ; i ++ ) {
247
+ request . clients [ response . clients [ i ] ] = true ;
248
+ }
249
+
250
+ if ( request . msgCount === request . numsub ) {
251
+ clearTimeout ( request . timeout ) ;
252
+ if ( request . callback ) process . nextTick ( request . callback . bind ( null , null , Object . keys ( request . clients ) ) ) ;
253
+ delete self . requests [ request . requestid ] ;
254
+ }
255
+ break ;
256
+
257
+ case requestTypes . clientRooms :
258
+ clearTimeout ( request . timeout ) ;
259
+ if ( request . callback ) process . nextTick ( request . callback . bind ( null , null , response . rooms ) ) ;
260
+ delete self . requests [ request . requestid ] ;
261
+ break ;
262
+
263
+ default :
264
+ debug ( 'ignoring unknown request type: %s' , request . type ) ;
265
+ }
176
266
} ;
177
267
178
268
/**
@@ -292,6 +382,7 @@ function adapter(uri, opts){
292
382
* Gets a list of clients by sid.
293
383
*
294
384
* @param {Array } explicit set of rooms to check.
385
+ * @param {Function } callback
295
386
* @api public
296
387
*/
297
388
@@ -304,11 +395,9 @@ function adapter(uri, opts){
304
395
rooms = rooms || [ ] ;
305
396
306
397
var self = this ;
398
+ var requestid = uid2 ( 6 ) ;
307
399
308
- var transaction = uid2 ( 6 ) ;
309
- var responseChn = prefix + '-sync#response#' + transaction ;
310
-
311
- pub . send_command ( 'pubsub' , [ 'numsub' , self . syncChannel ] , function ( err , numsub ) {
400
+ pub . send_command ( 'pubsub' , [ 'numsub' , self . requestChannel ] , function ( err , numsub ) {
312
401
if ( err ) {
313
402
self . emit ( 'error' , err ) ;
314
403
if ( fn ) fn ( err ) ;
@@ -317,64 +406,78 @@ function adapter(uri, opts){
317
406
318
407
numsub = numsub [ 1 ] ;
319
408
320
- var msg_count = 0 ;
321
- var clients = { } ;
322
-
323
- subJson . subscribe ( responseChn , function ( err ) {
324
- if ( err ) {
325
- self . emit ( 'error' , err ) ;
326
- if ( fn ) fn ( err ) ;
327
- return ;
328
- }
329
-
330
- var request = JSON . stringify ( {
331
- transaction : transaction ,
332
- rooms : rooms
333
- } ) ;
334
-
335
- /*If there is no response for 1 second, return result;*/
336
- var timeout = setTimeout ( function ( ) {
337
- if ( fn ) process . nextTick ( fn . bind ( null , null , Object . keys ( clients ) ) ) ;
338
- } , self . clientsTimeout ) ;
409
+ var request = JSON . stringify ( {
410
+ requestid : requestid ,
411
+ type : requestTypes . clients ,
412
+ rooms : rooms
413
+ } ) ;
339
414
340
- subJson . on ( subEvent , function onEvent ( channel , msg ) {
415
+ // if there is no response for x second, return result
416
+ var timeout = setTimeout ( function ( ) {
417
+ var request = self . requests [ requestid ] ;
418
+ if ( fn ) process . nextTick ( fn . bind ( null , new Error ( 'timeout reached while waiting for clients response' ) , Object . keys ( request . clients ) ) ) ;
419
+ delete self . requests [ requestid ] ;
420
+ } , self . requestsTimeout ) ;
421
+
422
+ self . requests [ requestid ] = {
423
+ type : requestTypes . clients ,
424
+ numsub : numsub ,
425
+ msgCount : 0 ,
426
+ clients : { } ,
427
+ callback : fn ,
428
+ timeout : timeout
429
+ } ;
430
+
431
+ pub . publish ( self . requestChannel , request ) ;
432
+ } ) ;
433
+ } ;
341
434
342
- if ( ! self . channelMatches ( channel . toString ( ) , responseChn ) ) {
343
- return debug ( 'ignore different channel' ) ;
344
- }
435
+ /**
436
+ * Gets the list of rooms a given client has joined.
437
+ *
438
+ * @param {String } client id
439
+ * @param {Function } callback
440
+ * @api public
441
+ */
345
442
346
- var response = JSON . parse ( msg ) ;
443
+ Redis . prototype . clientRooms = function ( id , fn ) {
347
444
348
- //Ignore if response does not contain 'clients' key
349
- if ( ! response . clients || ! Array . isArray ( response . clients ) ) return ;
350
-
351
- for ( var i = 0 ; i < response . clients . length ; i ++ ) {
352
- clients [ response . clients [ i ] ] = true ;
353
- }
445
+ var self = this ;
446
+ var requestid = uid2 ( 6 ) ;
354
447
355
- msg_count ++ ;
356
- if ( msg_count == numsub ) {
357
- clearTimeout ( timeout ) ;
358
- subJson . unsubscribe ( responseChn ) ;
359
- subJson . removeListener ( subEvent , onEvent ) ;
448
+ var rooms = this . sids [ id ] ;
360
449
361
- if ( fn ) process . nextTick ( fn . bind ( null , null , Object . keys ( clients ) ) ) ;
362
- }
363
- } ) ;
450
+ if ( rooms ) {
451
+ if ( fn ) process . nextTick ( fn . bind ( null , null , Object . keys ( rooms ) ) ) ;
452
+ return ;
453
+ }
364
454
365
- pub . publish ( self . syncChannel , request ) ;
455
+ var request = JSON . stringify ( {
456
+ requestid : requestid ,
457
+ type : requestTypes . clientRooms ,
458
+ sid : id
459
+ } ) ;
366
460
367
- } ) ;
461
+ // if there is no response for x second, return result
462
+ var timeout = setTimeout ( function ( ) {
463
+ if ( fn ) process . nextTick ( fn . bind ( null , new Error ( 'timeout reached while waiting for rooms response' ) ) ) ;
464
+ delete self . requests [ requestid ] ;
465
+ } , self . requestsTimeout ) ;
368
466
369
- } ) ;
467
+ self . requests [ requestid ] = {
468
+ type : requestTypes . clientRooms ,
469
+ callback : fn ,
470
+ timeout : timeout
471
+ } ;
370
472
473
+ pub . publish ( self . requestChannel , request ) ;
371
474
} ;
372
475
373
476
Redis . uid = uid ;
374
477
Redis . pubClient = pub ;
375
478
Redis . subClient = sub ;
376
479
Redis . prefix = prefix ;
377
- Redis . clientsTimeout = clientsTimeout ;
480
+ Redis . requestsTimeout = requestsTimeout ;
378
481
379
482
return Redis ;
380
483
0 commit comments