2016-02-10 33 views
5

Pytanie na podstawie tej odpowiedzi: https://stackoverflow.com/a/18650183/4478897socket.io + Redis + expressjs klaster - pobranie obiektu gniazda w expressjs zażądać

Starałem się znaleźć takie rozwiązanie, ale nic nie wydaje się działać w taki sposób, że muszę.

Klastry expressjs i socket.io możemy dzielić sesje za pomocą Redis i wysłać io wiadomości wewnątrz io świata (io.sockets.on('connection', ...). Problem polega na tym, że chcemy wysłać wiadomość (lub użyć zwykłego socket.join/leave) wewnątrz świata (route.get/post).

Jeśli nie używamy klastrów możemy atach obiektu klient socket do wyraźnej request obiektu (lub po prostu export przedmiotem io), a następnie używać go w dowolnym momencie na dowolnej trasie GET/POST.

Z drugiej strony, jeśli mamy do grupowania i wykorzystywać wspomnianą metodę, aby uzyskać obiekt wewnątrz świata expressjssocket, czasami przedmiotem socket jest nieokreślona, ​​ponieważ socket obiektu dla tego klienta jest inicjowany w drugiej worker.

Niektóre przykład przepływ:

  • klient łączy się http://localhost i worker 1 obsługuje tę prośbę. Po pobraniu strony klient łączy się z . Worker 2 obsługuje to połączenie.
  • Klient wykonuje test POST i ponownie obsługuje go: worker 1 lub .

W tym przypadku, gdy klient wykonuje POST, tylko worker 2 zna obiekt socket dla tego klienta. W ten sposób otrzymamy niezdefiniowany obiekt socket.

Więc pytanie:

Jak możemy dostać klient socket obiektu z dowolnego worker aby używać go na expressjs request obiektu.

Być może mój kod jest błędny, ale jest prawie jak link do odpowiedzi wspomnianej powyżej.


zauważa

  • Nie chcę użyć jakiegoś pełnomocnika.
  • Nie chcą migrować do innych bibliotek (expressio, sockjs ...)
  • Przepraszam za mój angielski :)

Korzystanie ostatnich nodejs, socket.io, expressjs, socket.io- redis, redis ... wersje

Nie wahaj się o coś zapytać!


UPDATE 1

Możliwe rozwiązanie, ale nadal trzeba go przetestować. Nie wiem, czy to naprawdę dobre rozwiązanie.

  • UPDATE 3: Kod Praca na własnym odpowiedź

UPDATE 2

Jak Update 1, ale przy użyciu https://nodejs.org/dist/latest-v5.x/docs/api/cluster.html#cluster_event_message

Odpowiedz

-1

No wreszcie spróbował kod i działa (z pewnymi modyfikacjami i innymi rzeczami), ale jestem pewien, że gdzieś musi być lepszy kod. Więc jestem otwarty na więcej odpowiedzi!

Kod ten jest częścią mojego modułu socket.io gdy zezwalają gniazdo klienta i kilka innych rzeczy ...

var redis = require("redis"); 
    var redisPub = redis.createClient(); 
    var redisSub = redis.createClient(); 
    var PubSubChannel = "clusterChannel"; 

    // Function that checks if this worker knows the socket object of this socketId. 
    // If not, publish the message to all the other sockets (workers) 
    io.socketDo = function (type, socketId, roomName) { 
    if (typeof io.sockets.connected[socketId] != "undefined") { 
     if (type === "join") { 
     return io.sockets.connected[socketId].join(roomName); 
     } 
     if (type === "leave") { 
     return io.sockets.connected[socketId].leave(roomName); 
     } 
    } else { 
     redisPub.publish(
     PubSubChannel, 
     JSON.stringify({ 
      type: type, 
      socketId: '' + socketId, 
      roomName: roomName 
     }) 
    ); 
    } 
    }; 

    // Subscribe to some channel 
    redisSub.subscribe(PubSubChannel); 

    // When this worker receive a message from channel "PubSubChannel" checks 
    // if it have the socket object for this socketId and do the operation 
    redisSub.on("message", function (channel, data) { 
    data = JSON.parse(data); 
    var type = data.type; 
    var socketId = data.socketId; 
    var roomName = data.roomName; 
    if ((type === "join" || type === "leave") && channel == PubSubChannel){ 
     if (typeof io.sockets.connected[socketId] != "undefined") { 
     if (type === "join") { 
      return io.sockets.connected[socketId].join(roomName); 
     } 
     if (type === "leave") { 
      return io.sockets.connected[socketId].leave(roomName); 
     } 
     } 
    } 
    }); 

Wtedy po prostu wyeksportować moduł i dołączyć go do swoich expressjs request => req.io = io

// req.session.socketId value is fetched on "io.sockets.on('connection', function(socket) {" 
// by express to socket.io using redis shared sessions 
app.get('/', function (req, res) { 
    req.io.socketDo('join', req.session.socketId, 'someRoomToJoin'); 

    // IT WORKS! 
    req.io.sockets.in('someRoomToJoin').emit('text'); 

    req.io.socketDo('leave', req.session.socketId, 'someRoomToLeave'); 
    res.send('Hello World!'); 
}); 
1

remoteJoin i remoteLeave metody dodano socket.io-REDiS 3.0.0:

io.adapter.remoteJoin('<my-id>', 'room1', function (err) { 
    if (err) { /* unknown id */ } 
    // success 
}); 

io.adapter.remoteLeave('<my-id>', 'room1', function (err) { 
    if (err) { /* unknown id */ } 
    // success 
}); 

Uwaga: Implementacja wygląda dużo (mam nadzieję?), Podobnie jak odpowiedź: above.

+0

Widziałem scalenie. Dziękujemy i tak: D – nada