创建 app

python3 manage.py startapp chat

注册

# mysite/settings.py
INSTALLED_APPS = [
    'chat',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

将用户的头像图片的 base64 发送过来后,在生成对话的时候直接将 base64 放上就行了

时间线来展示用户注册系统到现在的时间

时间线展示

如何实现展示

如何在聊天框中展示发出消息的用户头像和昵称,传送用户头像的 base64 和昵称到 websocket,之后再将这个 base64 进行转发,

上面的昵称先暂时是用户名

如果私有房间选择密码输入进行进入,那么在展示房间的时候,就要增加一栏显示是公有的还是私有的,

因为无论私有房间还是公有房间都可以加入,下面建立的房间名到对象的映射是所有的房间名到对象的映射。

如果要展示一个房间中的用户列表,那么存储的时候,原本是房间名到用户连接对象列表的映射,现在这个连接对象就要变成一个字典,存储连接对象,对象的用户名和对象的头像的 base64。

为防止在同一个研讨室内的人数过多,这里选择限制最多人数。

因为是创建 dom 元素添加上去,所以要完全使用原生的 html 元素。

当进入或离开自习室的时候,在聊天框的中间进行提醒

聊天框设计参考:

https://blog.csdn.net/weixin_49296016/article/details/116084583

气泡中的日期可以在前端生成

在连接的时候,发送房间名,头像、用户名和用户 id 给后端,后端建立房间名到这些信息的映射

那么用户的全局信息就包括这些东西了

在房间的 websocket 中要包括

在创建房间的时候前端发送给后端的信息包括

id: 0, 操作 id
user_id: 用户 id
name: 用户名
avatar_base64: 用户头像
room_name: 房间名称,
theme: 房间主题,
permission: 房间权限,
password: 房间密码,当房间是私有的时候有值,房间是公有时为空字符串

在加入房间时前端发送给后端的信息

id: 1, 操作 id
user_id: 用户 id
name: 用户名
avatar_base64: 用户头像
room_name: row.room_name,
password: 房间密码,当房间是私有的时候有值,房间是公有时为空字符串

在发送消息时前端发送给后端的消息
id: 2, 操作 id
user_id: 用户 id
name: 用户名
avatar_base64: 用户头像
sentence: 消息内容
room_name: 房间名称,

前端收到后端的消息格式为

user_id:
name: 用户名
avatar_base64:
sentence:

当同一个用户登录到两个网页的时候,

后端发送来的信息包括 user_id,前端将此 user_id 和此时网站登录的 user_id 进行比对,如果相同的话说明是同一个人可能在不同的网页发送的信息,将信息显示在左边;如果 user_id 不同,则将信息显示在右边。

后端保存的信息:

  • room_info

房间名 -> {
user_id_set: {user_id, user_id, ...}, 采用集合
socket_list: [...], 连接对象,据此转发消息
theme: str,
permission: 'public'/'private',
password:
}

从上面的 user_id_list,通过 len (user_id_list) 得到房间的人数

  • user_info

user_id -> {
socket_dict: { room_name: [socket 连接对象,...]}, 连接对象
avatar_base64:,
name: , 用户名
}

也许上面没有必要存储头像和用户名,因为在转发消息的时候可以实时发送

因为用户在房间中发送信息的时候,他是不知道房间中的其他用户信息的,所以要事先存储其他用户的头像和用户名的信息。

上面的想法还有一个问题,在 room_info 中保存的是 user_id,但是用户在不同的网页中是可以进入不同的房间的

  • socket_into

连接对象 -> {
user_id: ,
room_name:
}

用户在一个房间中的一个连接断掉了,可能房间的总人数不会减少,因为他还可能在另一个网页中存在着和房间的连接。

所以要从即将断掉的连接对象拿到 user_id 和此连接对象所在的房间名。之后要判断该 user_id 在该房间的连接对象是否为 0 了,如果为 0 了,再在 room_info 的 user_id_set 中移除该 user_id,房间人数发生变化。

(针对上面的想法,是否可以设置一个按钮,一次性退出用户在某个房间中的所有连接)

由于用户名和头像用户都是可以中途更改的,因此用户每次发送信息或者连接的时候都将用户名和头像发送过来,

在获取到房间中的用户名和头像列表后,中途用户可能修改了头像和用户名的。
不理他,他退出重新加入系统就自动更新了。

房间连接对象中,后端会向前端发送两种消息

  1. 转发消息
  2. 当前房间中的用户列表

用一个 msg_id 字段标识,转向不同的处理