Вопрос или проблема
Я разрабатываю веб-приложение для чата в реальном времени, и пользователи могут отправлять приватные сообщения другим зарегистрированным пользователям. Я хочу обновить статус сообщения в форме “отправлено”, когда клиент неактивен в своем аккаунте, “перенаправлено”, когда он входит в свой аккаунт, и “прочитано”, когда он заходит в чат.
from flask import Flask, render_template, request, session, redirect, url_for
from flask_socketio import join_room, leave_room, send, SocketIO
from datetime import datetime
import uuid
app = Flask(__name__)
app.config["SECRET_KEY"] = "hjhjsdahhds"
socketio = SocketIO(app)
users = {}
rooms = {}
active_users = {}
@app.route("/", methods=["GET", "POST"])
def home():
if request.method == "POST":
if "register" in request.form:
username = request.form.get("username")
if username in (user["username"] for user in users.values()):
return render_template("home.html", error="Это имя пользователя уже существует.")
user_id = str(uuid.uuid4())
users[user_id] = {"username": username}
return render_template("home.html", success="Регистрация успешна! Теперь вы можете войти.")
elif "login" in request.form:
username = request.form.get("username")
user = next((uid for uid, u in users.items() if u["username"] == username), None)
if not user:
return render_template("home.html", error="Пользователь не найден.")
session["user_id"] = user
session["username"] = username
return redirect(url_for("user_list"))
return render_template("home.html")
@app.route("/user_list")
def user_list():
if "username" not in session:
return redirect(url_for("home"))
other_users = {uid: u["username"] for uid, u in users.items() if uid != session["user_id"]}
return render_template("user_list.html", users=other_users, username=session["username"], active_users=active_users)
@app.route("/private_chat/<target_user_id>")
def private_chat(target_user_id):
if "username" not in session:
return redirect(url_for("home"))
if target_user_id not in users:
return redirect(url_for("user_list"))
room_id = f"{min(session['user_id'], target_user_id)}-{max(session['user_id'], target_user_id)}"
if room_id not in rooms:
rooms[room_id] = []
session["room_id"] = room_id
target_username = users[target_user_id]["username"]
messages = rooms[room_id]
return render_template("private_chat.html", room_id=room_id, messages=messages, target_user=target_username)
@socketio.on("connect")
def handle_connect():
user_id = session.get("user_id")
username = session.get("username")
if user_id and username:
active_users[user_id] = username
socketio.emit("active_users", active_users)
@socketio.on("disconnect")
def handle_disconnect():
user_id = session.get("user_id")
if user_id in active_users:
active_users.pop(user_id)
socketio.emit("active_users", active_users)
@socketio.on("message")
def handle_message(data):
room_id = session.get("room_id")
if not room_id:
return
message_data = {
"name": session["username"],
"message": data["message"],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
rooms[room_id].append(message_data)
send(message_data, to=room_id)
@socketio.on("join")
def on_join():
room_id = session.get("room_id")
if not room_id:
return
join_room(room_id)
send({"name": session["username"], "message": "присоединился к чату"}, to=room_id)
@socketio.on("broadcast_message")
def handle_broadcast_message(data):
message_data = {
"name": "Система",
"message": data["message"],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
for user_id in active_users:
room_id = f"{min(session['user_id'], user_id)}-{max(session['user_id'], user_id)}"
rooms.setdefault(room_id, []).append(message_data)
socketio.emit("message", message_data, room=room_id)
if __name__ == "__main__":
socketio.run(app, debug=True)
Прежде всего, только отправитель должен видеть статус сообщения, по умолчанию статус сообщения – отправлено, но если получатель был подключен к сокету в момент отправки сообщения или после его отправки, то есть если он вошел в список активных пользователей, статус всех сообщений, отправленных ему, пока он был неактивен, должен быть обновлен на “перенаправлено”, если пользователь подключился к чату, то есть если он вошел в комнату, статус сообщений, которые были “перенаправлены” ранее, должен быть обновлен на “прочитано”. Вот как я пытался задать вопрос chatgpt.
Ответ или решение
Для того чтобы включить статус сообщений в ваше приложение для чат-общения, необходимо рассмотреть несколько ключевых аспектов, включая структуру данных, логику обновления статуса и интерфейс для отображения статуса сообщений. В процессе разработки вам нужно будет учесть различные статусы сообщений, такие как "отправлено", "перенаправлено" и "прочитано".
1. Определение структуры данных
Первым шагом является изменение структуры данных для хранения статусов сообщений. Ваш текущий формат сообщений уже содержит основную информацию, но вам нужно добавить поле для статуса сообщения. Например, вы можете обновить ваш message_data
следующим образом:
message_data = {
"name": session["username"],
"message": data["message"],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"status": "sent" # Добавлено поле статуса
}
2. Логика обновления статусов сообщений
Теперь вам нужно реализовать логику, которая будет обновлять статусы сообщений в зависимости от действий пользователей.
- Статус "отправлено": По умолчанию все сообщения имеют статус "отправлено".
- Статус "перенаправлено": Если пользователь, которому было отправлено сообщение, подключается к сокету после того, как сообщение было отправлено, его статус должен обновляться до "перенаправлено". Это можно реализовать в функции
handle_message
следующим образом:
@socketio.on("message")
def handle_message(data):
room_id = session.get("room_id")
if not room_id:
return
message_data = {
"name": session["username"],
"message": data["message"],
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"status": "sent"
}
rooms[room_id].append(message_data)
send(message_data, to=room_id)
# Проверка на наличие клиента в активных пользователях
recipient_id = target_user_id # Получите ID получателя
if recipient_id in active_users:
message_data["status"] = "forwarded"
# Отправка сообщения с обновленным статусом получателю
send(message_data, to=room_id)
- Статус "прочитано": При входе пользователя в частный чат, вам нужно обновить статус всех сообщений, которые были недавно отправлены, с "перенаправлено" на "прочитано". Это можно сделать в функции
private_chat
:
@socketio.on("join")
def on_join():
room_id = session.get("room_id")
if not room_id:
return
join_room(room_id)
# Обновление статусов сообщений
for message in rooms[room_id]:
if message['status'] == "forwarded":
message['status'] = "seen"
send({"name": session["username"], "message": "сообщение прочитано"}, to=room_id)
send(rooms[room_id], to=room_id) # Отправка всех сообщений с новыми статусами
3. Обновление интерфейса
Наконец, чтобы пользователи могли видеть статус своих сообщений, необходимо обновить фронтенд. Убедитесь, что вы правильно отображаете статус сообщений в вашем HTML:
<div>
{% for message in messages %}
<div>
<strong>{{ message.name }}</strong>: {{ message.message }}
<span>({{ message.status }})</span>
</div>
{% endfor %}
</div>
Заключение
Таким образом, вы сможете реализовать отображение статусов сообщений для пользователей вашего чата. Не забудьте протестировать каждый уровень, чтобы убедиться, что статусы обновляются корректно при каждом взаимодействии с приложением. Использование такого подхода не только улучшит пользовательский опыт, но и сделает вашу систему более интуитивной и удобной для использования.
Если у вас возникнут дополнительные вопросы о реализации, не стесняйтесь задавать их!