Repository navigation
Expand file tree
/
Copy pathapplication.py
More file actions
143 lines (115 loc) · 3.92 KB
/
Copy pathapplication.py
File metadata and controls
143 lines (115 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import eventlet
import os
import json
from collections import deque
import datetime
from flask import Flask, render_template, request, session, flash, redirect, url_for
from flask_session import Session
from flask_socketio import SocketIO, emit, join_room, leave_room
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
socketio = SocketIO(app, async_mode="eventlet")
# Configure session to use filesystem
# app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# each room will have a deque of messages
# each message will be a list of user, timestamp, and msg text
rooms = {}
rooms["#general"] = deque()
# users dict will contain sessionIDS with nicknames as values
users = {}
# last_room dict will pair users with their last visited room
last_room = {}
@app.route("/", methods=["GET", "POST"])
def login():
if request.method == "GET":
if session.get("user") == None:
return render_template("login.html")
else:
nickname = session.get("user")
# if user opens a second tab/window, direct them to the login page
if nickname in users.values():
return render_template("login.html")
current_room = last_room.get(nickname) or "#general"
return render_template(
"index.html",
nickname=nickname,
current_room=current_room,
)
else:
nickname = request.form.get("nickname").strip()
if nickname in users.values():
flash("username taken, please choose another.")
return redirect(url_for("login"))
if nickname == "":
flash("please choose a valid username")
return redirect(url_for("login"))
current_room = "#general"
session["user"] = nickname
return render_template(
"index.html",
nickname=nickname,
current_room=current_room,
)
@socketio.on("get channels")
def get_channels():
current_channels = list(rooms)
emit("receive channels", current_channels)
@socketio.on("submit msg")
def handle_message(message, nickname, current_room):
test_msg = message.strip()
if test_msg == "":
return
# get timestamp for msg
# + "Z" is to ensure UTC time in ISO format
timestamp = str(datetime.datetime.utcnow().isoformat()) + "Z"
new_message = {"message": message, "nickname": nickname, "timestamp": timestamp}
# store 100 most recent msg objects server side
if len(rooms[current_room]) >= 100:
rooms[current_room].popleft()
rooms[current_room].append(new_message)
emit(
"broadcast msg",
(message, nickname, timestamp),
broadcast=True,
room=current_room,
)
@socketio.on("user connected")
def connect(nickname):
if nickname in users.values():
# user opened another tab
return
else:
users[request.sid] = nickname
emit("on connection", nickname, broadcast=True, include_self=False)
@socketio.on("disconnect")
def test_disconnect():
if users.get(request.sid) is not None:
nickname = users.get(request.sid)
users.pop(request.sid)
emit("disconnected", nickname, broadcast=True)
@socketio.on("create channel")
def create_channel(name):
test_name = name.strip()
if test_name == "":
return
test_name = test_name.replace(" ", "-")
if ("#" + test_name) in rooms:
return
rooms["#" + test_name] = deque()
emit("broadcast channel", "#" + test_name, broadcast=True)
@socketio.on("join")
def on_join(room, nickname):
try:
join_room(room)
last_room[nickname] = room
messages = list(rooms.get(room))
emit("render room", messages)
except:
print("user needs browser reset")
@socketio.on("leave")
def on_leave(room):
leave_room(room)
if __name__ == "__main__":
socketio.run(app, host="0.0.0.0")