0

I am building a simple chat app and I have been trying to emit messages to rooms with Flask-SocketIO.

The "mesage_event" event from the client reaches the server well, but then, I cannot see anything on the client side. I don't know whether the server emits something to the room but on the client side, I cannot see anything in the console. I can only successfully send to all clients with broadcasting.

Here is my code on the server side:

@socketio.on("send msg")
def sendsocket(data):
    print("send msg start:", data["msg"])
    msg = data["msg"]
    room = data["room"]
    emit("message_event", msg, room = room)

And the client side:

1- for sending the message:

socket.emit('send msg', {'msg': msg, 'room': room})

2- for triggering the event handler:

socket.on('message_event', data => {
    console.log("message received:", data);
});
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
mizar
  • 259
  • 1
  • 3
  • 10
  • Did you call the `join_room()` function at any point? If you emit to a room, only those clients that joined the room will receive the event. – Miguel Grinberg Feb 23 '20 at 12:14
  • Yes as below mentioned. But it seems that I get two sid's from the client. one after joining the room and one after sending a message. Reason is maybe that I have two js files for two html files as below described below. I think I need to use the socket variable in the second js file without trying to connect to a new socket right? but how? – mizar Feb 23 '20 at 12:23
  • 1
    Are you changing the html page? If the page changes, then the client will delete all connections and create new ones. If you join a room that's going to go away when you switch to another page. Build a single-page app instead, then the connections will be preserved. – Miguel Grinberg Feb 23 '20 at 23:27

2 Answers2

3

You are missing 2 things.

1st, you need to send a "join" event to the server.

<script>
function joinRoom() {
    console.log("ask server to join room");
    socket.emit("join", { "user": Date.now(), "room": "Notifications" });
}
</script>

<body>
    <button onclick="joinRoom()">Join</button>
</body>

For example, here I attached the trigger to a button. And to make it easier to initially test adding users to rooms, I use Date.now() as the username. You can open different tabs to serve as different users.

2nd, you need to have a handler for that join event.
There is an example in the Rooms and Namespaces section of the Flask-SocketIO docs.

@socketio.on("join")
def on_join(data):
    user = data["user"]
    room = data["room"]
    print(f"client {user} wants to join: {room}")
    join_room(room)
    emit("room_message", f"Welcome to {room}, {user}", room=room)

In the handler, you need to call the join_room method to add the user to a room under the current namespace. Note that part about the namespace. By default all connections are under the root (/) namespace. If you have custom namespaces, then each namespace will have their own rooms.

There is also a corresponding leave_room method.

Here is the complete server-side code:

@socketio.on("connect")
def connect():
    print("client wants to connect")
    emit("status", { "data": "Connected. Hello!" })

@socketio.on("join")
def on_join(data):
    user = data["user"]
    room = data["room"]
    print(f"client {user} wants to join: {room}")
    join_room(room)
    emit("room_message", f"Welcome to {room}, {user}", room=room)

Here is the complete client-side code:

<script type="text/javascript" charset="utf-8">
    const socket = io();
    socket.on("connect", () => {
        console.log("connect");
    });
    socket.on("status", (status) => {
        console.log("received status: " + status.data);
    });
    socket.on("room_message", (msg) => {
        console.log("message from room: " + msg);
    });
    function joinRoom() {
        console.log("ask server to join room");
        socket.emit("join", { "user": Date.now(), "room": "Notifications" });
    }
</script>

<body>
    <button onclick="joinRoom()">Join</button>
</body>

Now, you can now open multiple tabs and connect each one to the server. The server-side should show the following messages:

client wants to connect
client wants to connect
client wants to connect
client 1582428076724 wants to join: Notifications
client 1582428080023 wants to join: Notifications
client 1582428082916 wants to join: Notifications

And on the 1st user to join the room (1582428076724), you should be able to see the logs as other users are joining the room.

connect 
received status: Connected. Hello!
ask server to join room 
message from room: Welcome to Notifications, 1582428076724 
message from room: Welcome to Notifications, 1582428080023 
message from room: Welcome to Notifications, 1582428082916
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
  • I have implemented the two steps but no success. I have 2 html pages, one for "room list" and one for the "room page itself". Both of them have own js file and both try to connect to a socket. I am sending the "join room" event to the server from the first page the "room list". Then the server will render the "room page itself". In this case, a new socket connect is generated. I saw that there is a new sid value. Maybe this is the problem? How can I use the original socket in the second js file of the "room page itself" after rendering to a new page, the room page? – mizar Feb 23 '20 at 11:28
2

Don't know why send and emit function from flask_socketio does not work. If I use socketio (socket instance), it will send the message successfully.

socketio.emit('EVENT_NAME', data, to='YOUR_ROOM')
tiennguyen
  • 164
  • 1
  • 8