2015-07-09 14 views
12

Czy możliwe jest rozgłoszenie socket.io dla wszystkich użytkowników przestrzeni nazw znajdujących się w pokoju A i pokoju B, ale nie w pomieszczeniu A lub pokój B?. socket.io nadaje się tylko dla użytkowników znajdujących się w pokoju A i B

Jeśli nie, w jaki sposób sam będę realizować to zadanie? Czy istnieje sposób na odzyskanie wszystkich użytkowników w przestrzeni nazw znajdujących się w danym pokoju?

Pracuję z socket.io 1,0 w węźle

Edit: Jeśli nie ma natywny sposób, jak pójdę zamiar stworzyć własną składnię, takich jak: socket.broadcast.in('room1').in('room2').emit(...)?

+0

zobaczyć to: http://stackoverflow.com/a/24145381/3842050 To może pomóc . – Blubberguy22

+0

możesz to zrobić po stronie klienta, wysyłając do obu i tylko reagując na drugie przybycie na tego samego klienta ... – dandavis

Odpowiedz

5

Można wyszukać wszystkich użytkowników pomieszczenia stosując (ref How to update socket object for all clients in room? (socket.io))

var clients = io.sockets.adapter.room["Room Name"] 

Więc podane dwie tablice do listy zaplanowany swoich 2 pokoje, można obliczyć punkt przecięcia przy użyciu coś jak tutaj odpowiedzi (ref: Simplest code for array intersection in javascript)

i wreszcie można przyjąć, że lista użytkowników w obu pokojach i emitują zdarzenia użyciu (Ref: How to update socket object for all clients in room? (socket.io))

//this is the socket of each client in the room. 
var clientSocket = io.sockets.connected[clientId]; 

//you can do whatever you need with this 
clientSocket.emit('new event', "Updates"); 

Alternatywą jest posiadanie ukrytych pomieszczeń, w których utrzymuje się kombinacja wszystkich pomieszczeń i dodawanie użytkowników do pomieszczeń za kulisami, a następnie możesz po prostu emitować te ukryte pomieszczenia. Ale to cierpi na wykładniczy problem wzrostu.

+0

Dziękuję! To bardzo cenna informacja. Czy wiesz, jak mogę wdrożyć tego rodzaju zachowanie w prototypie socket.io? To jest coś, czego zamierzam używać w całym moim kodzie, więc byłoby to naprawdę proste, gdybym mógł po prostu zadzwonić, powiedzmy, 'socket.broadcast.toAll ([...]) .ali (...)' i mieć Funkcja 'toAll()' chwyta połączenie wszystkich pomieszczeń i emituje tylko te. –

0
io.sockets.adapter.room["Room A"].forEach(function(user_a){ 
    io.sockets.adapter.room["Room B"].forEach(function(user_b){ 
    if(user_a.id == user_b.id){ 
     user_a.emit('your event', { your: 'data' }); 
    } 
    }); 
}); 
1

Nie ma wbudowanego sposobu, aby to zrobić. Więc najpierw przyjrzyjmy się, jak broadcast działa:

https://github.com/Automattic/socket.io/blob/master/lib/namespace.js 206 ... 221-224 ... 230

this.adapter.broadcast(packet, { 
    rooms: this.rooms, 
    flags: this.flags 
}); 

Teraz wiemy, każda transmisja tworzy kilka obiektów temp wyszukiwań IndexOf argumenty plastry ... A następnie wywołuje metodę rozgłaszania adaptera. Pozwala spojrzeć na tym jednym:

https://github.com/Automattic/socket.io-adapter/blob/master/index.js 111-151

Teraz tworzymy nawet więcej obiektów tymczasowych i pętli przez wszystkich klientów w pokojach lub wszystkich klientów, jeśli nie został wybrany pokój. Pętla dzieje się w oddzwanianiu kodowania. Ten sposób można znaleźć tutaj:

https://github.com/socketio/socket.io-parser/blob/master/index.js

Ale co, jeśli nie wysyłamy nasze pakiety poprzez broadcast ale do każdego klienta oddzielnie po pętli po pokojach i znalezienie klientów, które istnieją zarówno w pokoju A i pokojowej B?

socket.emit zdefiniowano poniżej: https://github.com/Automattic/socket.io/blob/master/lib/socket.js

Co prowadzi do sposobu client.jspacket: https://github.com/Automattic/socket.io/blob/master/lib/client.js

Każdy bezpośrednio emitowane pakiet zostanie oddzielnie kodowane, co znowu jest kosztowne. Ponieważ wysyłamy dokładnie ten sam pakiet do wszystkich użytkowników.

Aby odpowiedzieć na to pytanie:

albo zmienić klasę adaptera socket.io i zmiany sposobu nadawania, dodać swoje własne metody do prototypu lub przewróceniu własne zasilacza przez dziedziczenie z klasy adaptera). (var io = require('socket.io')(server, { adapter: yourCustomAdapter });)

Można również zastąpić metody join i leave z zakresu socket.js. Co jest dość wygodne, biorąc pod uwagę, że metody te nie są nazywane bardzo często i nie masz kłopotów z edycją przez wiele plików.

Socket.prototype.join = (function() { 
    // the original join method 
    var oldJoin = Socket.prototype.join; 

    return function(room, fn) { 

     // join the room as usual 
     oldJoin.call(this, room, fn); 

     // if we join A and are alreadymember of B, we can join C 
     if(room === "A" && ~this.rooms.indexOf("B")) { 
      this.join("C"); 
     } else if(room === "B" && ~this.rooms.indexOf("A")) { 
      this.join("C"); 
     } 
    }; 
})(); 

Socket.prototype.leave = (function() { 
    // the original leave method 
    var oldLeave = Socket.prototype.leave; 

    return function(room, fn) { 

     // leave the room as usual 
     oldLeave.call(this, room, fn); 

     if(room === "A" || room === "B") { 
      this.leave("C"); 
     } 
    }; 
})(); 

A następnie transmitowane do C jeśli chcesz nadawać do wszystkich użytkowników w A i B. To jest tylko przykładowy kod, można go dodatkowo poprawić, nie kodując w sposób trudny nazw pomieszczeń, ale używając tablicy lub obiektu, aby zapętlić możliwe kombinacje pokoi.

as Adapter do socket.broadcast.in("A").in("B").emit() pracy:

var Adapter = require('socket.io-adapter'); 

module.exports = CustomAdapter; 

function CustomAdapter(nsp) { 
    Adapter.call(this, nsp); 
}; 

CustomAdapter.prototype = Object.create(Adapter.prototype); 
CustomAdapter.prototype.constructor = CustomAdapter; 

CustomAdapter.prototype.broadcast = function(packet, opts){ 
    var rooms = opts.rooms || []; 
    var except = opts.except || []; 
    var flags = opts.flags || {}; 
    var packetOpts = { 
    preEncoded: true, 
    volatile: flags.volatile, 
    compress: flags.compress 
    }; 
    var ids = {}; 
    var self = this; 
    var socket; 

    packet.nsp = this.nsp.name; 
    this.encoder.encode(packet, function(encodedPackets) { 
    if (rooms.length) { 
     for (var i = 0; i < rooms.length; i++) { 
     var room = self.rooms[rooms[i]]; 
     if (!room) continue; 
     for (var id in room) { 
      if (room.hasOwnProperty(id)) { 
      if (~except.indexOf(id)) continue; 
      socket = self.nsp.connected[id]; 
      if (socket) { 
       ids[id] = ids[id] || 0; 
       if(++ids[id] === rooms.length){ 
       socket.packet(encodedPackets, packetOpts); 
       } 
      } 
      } 
     } 
     } 
    } else { 
     for (var id in self.sids) { 
     if (self.sids.hasOwnProperty(id)) { 
      if (~except.indexOf(id)) continue; 
      socket = self.nsp.connected[id]; 
      if (socket) socket.packet(encodedPackets, packetOpts); 
     } 
     } 
    } 
    }); 
}; 

A w pliku app:

var io = require('socket.io')(server, { 
    adapter: require('./CustomAdapter') 
}); 
+0

Jest to zdecydowanie najbardziej obiecujące podejście. Nie miałem czasu go przetestować, ale dam ci nagrodę, zanim wygaśnie za twoją pracę i wysiłek. –

+0

Dzięki! :) Istnieją również inne podejścia, które można wypróbować. Na przykład. iterowanie wszystkich użytkowników w 'A', sprawdzanie, czy są również w' B' (za pomocą indexOf na ich własności 'room'), a następnie kodowanie wiadomości i wysyłanie jej przez' socket.packet' zamiast 'socket. emitować'. Nie wypróbowałem też kodu, więc daj mi znać, jeśli coś nie działa zgodnie z oczekiwaniami. –

+0

Zrobię! Będę miał trochę wolnego czasu pod koniec tego tygodnia. Moim głównym problemem było dodanie moich funkcji do prototypu socket.io –