Concise example of how to join and leave rooms using Flask and Socket.io?
Solution 1
Think of a room as an array of users that stays on the server. When you send your message in "send message", you set broadcast=True
, so it sends it as a global message to all users, as long as they are connected. If you only want to send to users in specific rooms, you will need to specify which room you want to send the message to from the client, each time you send a message, like this:
// client.js
socket.emit('join', { 'channel': channel, ... });
socket.emit('send message', {'message': message, 'channel': channel});
// server.py
@socketio.on("send message")
def message(data):
room = data['channel']
emit('broadcast message', data['message'], room=room)
Solution 2
I believe the first answer is correct. Just as a note, avoid using 'innerhtml' where possible especially in this case. By setting the innerhtml, anything a user writes in a message will be treated as html at the other end. This includes script tags which means someone could remotely run javascript on someone else's machine by sending a malicious message.
I would suggest using innerText or textContent. This will treat the message as plain text not html. They are slightly different so it may be worth looking into which one you need.
I would have done this as a comment but my rep isn't high enough.
tl:dr Use textContent or innerText instead of innerhtml.
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on June 17, 2022Comments
-
Admin about 2 years
I'm trying to use socket.io with a Flask server connecting to JS.. I'm struggling with basically everything, but my first step is to make it so that users can connect to different channels. My broadcast message function is working, but when I click on a different channel, the messages do not get sent to a different channel.. What am I doing wrong?
JS:
document.addEventListener('DOMContentLoaded', ()=>{ // Send user back to login page if they didn't sign in const username = localStorage.getItem('username'); if (username == null){ window.location = "/"; } // Switch button active class when clicked $('.list-group .list-group-item.list-group-item-action').click(function(e) { $('.list-group .list-group-item.list-group-item-action.active').removeClass('active'); var $this = $(this); if (!$this.hasClass('active')) { $this.addClass('active'); } e.preventDefault(); }); // Connect to socket.io var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port); socket.on('connect', () => { // Automatically connect to general channel socket.emit('join',{"channel": "general", "username":username}); // When a channel is clicked, connect to that channel document.querySelectorAll('.list-group-item').forEach(function(channel){ channel.onclick = () =>{ socket.emit('join',{"channel":channel.innerHTML, "username":username}); return false; } }); // When a message is sent, call 'send message' function from server document.querySelector('#send-message').onsubmit = () => { const message = document.querySelector('#m').value socket.emit('send message', {'message': message}); // Clear message form document.querySelector('#m').value = ""; return false; }; }); // Callback from server for sending messages socket.on('broadcast message', data =>{ console.log(data); // Append message to list of messages const li = document.createElement('li'); li.innerHTML = `${data.message}`; document.querySelector('#messages').append(li); }); });
Python Flask:
import os from flask import Flask, render_template, url_for from flask_socketio import SocketIO, emit, join_room, leave_room from collections import defaultdict app = Flask(__name__) app.config["SECRET_KEY"] = os.getenv("SECRET_KEY") socketio = SocketIO(app) messages = defaultdict(list) channels = ["Programming"] @app.route("/") def index(): return render_template("login.html") @app.route("/chatroom/") def chatroom(): return render_template("chatroom.html", channels=channels, messages=messages) @socketio.on("send message") def message(data): print(data) emit("broadcast message", {"message": message}, broadcast=True) @socketio.on('join') def on_join(data): username = data['username'] channel = data['channel'] join_room(channel) #send(username + ' has entered the room.', channel=channel) if __name__ == '__main__': socketio.run(app)
-
Kakashi Hatake about 3 yearsI am a beginner, Can you please tell me what the third parameter
room=room
in theemit
does, and how do we use it on the client side. I am just clueless about the whole room thing and how doessend
andemit
handle it. -
Jacob Sussan almost 3 years@KakashiHatake
room
is an optional parameter that emit has. When included it will only emit the message to that specific room, and only clients that have joined that room will get said message. A room is an arbitrary channel that sockets can join and leave. It can be used to broadcast events to a subset of clients. Rooms are a server-only concept (i.e. the client does not have access to the list of rooms it has joined). Hope this helps.