I'm building a simple chat application with Flask and SocketIO. The user enters a username and a room key to join a room and start chatting.
In the beginning, I could make the sockets work to send and receive messages. However, at that moment I was not using any blueprint. Just templates and all the events and routes were in the same python file.
Later, I decided to split the application into folders and use blueprints. Mainly due to the incorporation of registration and authentication of users (No incorporated yet). However, the sockets stopped working but everything else is working as expected.
The directory tree looks as follows:
Chat_Rooms/
|
--- flask_chat_app/
| |
| --- static/css/
| --- templates/
|
| --- __init__.py
| --- auth.py
| --- events.py
| --- models.py
| --- views.py
|
--- app.py
My python and HTML files look as follows:
_init_.py
from flask import Flask
from flask_socketio import SocketIO
# create socket object
socket:SocketIO = SocketIO()
def create_app(debug=False):
"""Create application"""
app:Flask = Flask(__name__)
app.debug = debug
app.config['SECRET_KEY'] = 'mysecret!'
"""import and add blueprints to app"""
from .auth import auth
from .views import views
app.register_blueprint(views, url_prefix="/")
app.register_blueprint(auth, url_prefix="/")
"""Initialize socket"""
socket.init_app(app)
"""Return built app"""
return app
views.py
from flask import Blueprint
from flask import render_template, request
import random
# init blueprint object
views:Blueprint = Blueprint('views', __name__)
# Routes
"""
index
First page the user will see when enter to site
"""
@views.route("/")
def index():
return render_template("index.html")
"""
home:
Display options to generate key and join room
"""
@views.route("/home")
def home():
return render_template("home.html")
"""
generateKey:
Generate 2 random number between 100 - 1000. Put them together
to create a random key shown in the frontend.
Key is saved into a session as room-key
Increase room counter
"""
@views.route("/generate_key")
def generateKey():
# generate a random key
key1:int = random.randint(100,1000)
key2:int = random.randint(100,1000)
key:str = str(key1) + ' - ' + str(key2)
# render template with key
return render_template("generate_key.html", key=key)
"""
join_room_credentials:
Get username and room key. If it exist, enter room chat
"""
@views.route("/join_room", methods=['GET', 'POST'])
def join_room_credentials():
# get user information and enter chat room
if request.method == 'POST':
if request.form["username"] and request.form["roomKey"]:
# redirect to chat room page
return render_template("chat_room.html", username=request.form["username"], room=request.form["roomKey"])
# render html file to get credentials
else:
return render_template("join_room.html")
events.py
from .__init__ import socket
from flask_socketio import join_room
# socket routes
"""
handle_join_room:
event that will get the users in the same room and will notify to all clients
when a new user joins a room
"""
@socket.on("user_join_room")
def handle_join_room(data):
# print user and room in terminal
print("\n")
print(f"{data['username']} joined to room{data['room']}")
print("\n")
# add user to group
join_room(data["room"])
# send notification to clients
socket.emit('user_join_room', f"{data['username']} joined the room", to=data["room"])
"""
handle_message:
event to send a client message to all other clients
"""
@socket.on("user_message")
def handle_message(message):
socket.emit("user_message", f". {message['username']}: {message['message']} .", to=message["room"])
chat_room.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chat Room</title>
<link rel="stylesheet" href="{{url_for("static", filename="CSS/chat_room.css")}}">
<!-- connect to server -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
<script>
// create socket to connect with server
const socket = io.connect("http://127.0.0.1:5000/")
/* --------- client to server ----------- */
// send message to server with user credentials
socket.on("connect", function() {
socket.emit('user_join_room', {
username: "{{username}}",
room: "{{room}}"
})
// get message text
let msgElem = document.getElementById("msg_input");
let msgForm = document.getElementById("mgs-form");
msgForm.onsubmit = function (event) {
event.preventDefault();
let msg = msgElem.value.trim();
if (msg.length) {
socket.emit("user_message", {
username: "{{username}}",
room: "{{room}}",
message: msg
})
}
msgElem.value = " ";
msgElem.focus();
}
});
/* ---------- server to client ------------ */
// add message when someone joins the room
socket.on("user_join_room", function(data) {
// create new paragraph
let newP = document.createElement("p");
let newNode = document.createTextNode(data);
newP.appendChild(newNode);
// get message div element
const msgDiv = document.getElementById("message");
msgDiv.appendChild(newP);
})
socket.on("user_message", function (data) {
let newP = document.createElement("p");
let newNode = document.createTextNode(" " + data + " ");
newP.appendChild(newNode);
// get message div element
const msgDiv = document.getElementById("message");
msgDiv.appendChild(newP);
})
</script>
</head>
<body>
<div id="chat-wrap">
<div id="header-wrap">
<h1>Room: {{room}}</h1>
</div>
<div id="chat-space">
<p id="message"></p>
</div>
<div id="msg-wrap">
<form id="mgs-form">
<input id="msg_input" placeholder="Enter message"></input>
<button type="submit">Send</button>
</form>
</div>
</div>
</body>
</html>
join_room.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Join Room</title>
<link rel="stylesheet" href="{{url_for("static", filename="CSS/join_room.css")}}">
</head>
<body>
<!-- Get username and room key -->
<div id="credential-wrap">
<form method="POST">
<div id="username_wrapper">
<label>Username: </label>
<input name="username" placeholder="frazzledcoal"></input>
</div>
<div id="key_wrapper">
<label>Room Key: </label>
<input name="roomKey" placeholder="xxx - xxx"></input>
</div>
<div id="button-wrap">
<a href="{{url_for("views.home")}}"><button type="button">Back</button></a>
<button type="submit" id="submit-btn">Enter</button>
</div>
</form>
</div>
</body>
</html>
app.py
from flask_chat_app import create_app, socket
"""build application"""
chat_app = create_app(True)
if __name__ == "__main__":
socket.run(chat_app)
I tried to find a solution by looking at the Flask and SocketIO documentation but I still don't know why the sockets stopped communicating with each other.
I really would appreciate it if you guys can help me to solve this problem. This is my first stack overflow post, so I do apologize if any information is missing.