thruster-rs / thruster-socketio

A socket.io implementation over thruster
14 stars 2 forks source link

Why are there three rooms design? #20

Closed rts-gordon closed 3 years ago

rts-gordon commented 3 years ago

Hi @trezm I realized that there are three rooms design in thruster-socketio: 1, SocketIOSocket

pub struct SocketIOSocket {
    id: String,
    sender: Sender<InternalMessage>,
    rooms: Vec<String>,
}

2, SocketIOWrapper

pub struct SocketIOWrapper {
    sid: String,
    message_number: usize,
    socket: SplitSink<WebSocketStream<hyper::upgrade::Upgraded>, Message>,
    rooms: Vec<String>,
    event_handlers: HashMap<String, Vec<SocketIOHandler>>,
    sender: Sender<InternalMessage>,
    receiver: Receiver<InternalMessage>,
}

3, static ROOMS

lazy_static! {
    static ref ROOMS: CHashMap<String, Vec<ChannelPair>> = CHashMap::new();
}

My question is: 1, How to ensure consistency between the three rooms data? For example, when a client socket leave a room, SocketIOWrapper rooms.remove successful, but remove_socket_from_room failed.

                        SocketIOMessage::Leave(room_id) => {
                            let mut i = 0;
                            for room in &self.rooms {
                                if room == &room_id {
                                    self.rooms.remove(i);
                                    debug!("SocketIOMessage socketid {} leaved room {}. Rooms = {:?}, rooms len = {}", self.sid, room_id, self.rooms, self.rooms.len());                            

                                    //Call rooms::remove_socket_from_room
                                    remove_socket_from_room(&room_id, &self.sid);
                                    break;
                                }

                                i = i + 1;
                            }
                        }

2, If I want to get how many rooms in my process, which rooms data shall be correct? SocketIOSocket.rooms, SocketIOWrapper.rooms, or static ROOMS?

Thanks for your reply.

trezm commented 3 years ago

Sorry for the late response, let me see if I can answer these questions:

SocketIOWrapper wraps individual sockets and holds the rooms that a particular socket is connected to. SocketIOSocket, although poorly named, is created on a per-handler basis. That is, when a particular piece of socket.io middleware is triggered, the SocketIOWrapper creates a new SocketIOSocket and uses its copy of rooms so that the developer can query what rooms this socket is in. SocketIOSocket's copy of rooms should be readonly from a developer perspective.

ROOMS is a different pattern altogether. Whereas SocketIOWrapper::rooms represents a socket -> Vec<Room>, ROOMS can be thought of as the inverse direction -- Room -> Vec<Socket>.

So for your questions specifically,

  1. ROOMS and SocketIOWrapper::rooms are kept in sync because they join/leave functionality updates both sequentially.
  2. If you want to get the correct room count in the process, count the keys in ROOMS and you should get an accurate count.

Does this help?

P.S. I'll put out an update for https://github.com/thruster-rs/thruster-socketio/issues/19 shortly.

rts-gordon commented 3 years ago

Thanks for your explain, it is much clear.