第13章IM服务——13.6 会话管理与命令消息

第13章IM服务——13.6 会话管理与命令消息
John Yaml13.6 会话管理与命令消息
目前我们只讨论了用户消息的收发问题,一条用户消息必然属于一个会话,会话本身也需要IM服务管理。
13.6.1 创建单聊会话
我们先从发送者的视角介绍创建会话的流程。例如,用户A首次与用户B聊天时,用户A先打开与用户B的聊天框,此时对于用户A来说两者的会话就已经建立了,只不过服务端和用户B对此并不知情。当用户A发出第一条消息时,客户端才请求服务端创建会话,此时客户端将消息内容、接收者和值为0的会话ID传递给服务端,服务端发现请求的会话ID为0,于是需要依次创建如下数据。
- 生成唯一的会话ID,在会话表中创建新会话。
- 在用户会话链中建立会话与用户A、用户B的关联关系。
- 将消息存储到消息表中。
服务端将会话ID响应给客户端,表示会话创建成功、消息发送成功,但是此流程缺点明显,在如下场景中容易出现重复创建会话的情况。
- 服务端在存储消息时遇到网络错误,于是客户端被告知消息发送失败,然后用户A选择重发消息;当服务端再次处理此消息时,会创建新会话,以及会话与用户的关联关系,从而导致出现用户A与用户B之间存在两个单聊会话的情况。
- 当用户A打开聊天框准备与B首次聊天时,恰好用户B也打开了与用户A的聊天框发送消息,这样就会使得服务端接收到两个创建用户A与用户B之间会话的请求,最终也导致出现用户A与用户B之间存在两个单聊会话的情况。
在创建单聊会话时,之所以会有重复的会话产生,是因为服务端没有简单的办法来判断两个用户之间是否已存在单聊会话。其实可以在服务端生成的会话ID上反映单聊关系,对于任何单聊会话都使用{用户ID1}-{用户ID2}
作为会话ID,其中用户ID1是两个用户中用户ID较小的那个,用户ID2则是另一个用户ID。假设用户A的ID为222,用户B的ID为111,那么两者的单聊会话ID固定使用“111-222”来表示。这样一来,无论是用户A重发消息,还是用户B同时发送消息,IM服务都会在会话表中发现两者的单聊会话已经存在了。
现在再从接收者的视角来讲讲会话的创建。接收者的客户端在接收到一条消息后,根据消息中携带的会话ID在本地查询是否已存在此会话;如果没有找到此会话(或者被用户手动删除了,或者用户换了聊天设备),则说明可能是新会话,此时客户端再根据会话ID从IM服务中拉取会话信息。
13.6.2 创建群聊会话
创建群聊会话,发起者必须显式地请求服务端,所以创建群聊会话的流程比创建单聊会话要简单得多。比如用户A选择向用户B、用户C、用户D发起群聊,则会直接向服务端发起创建群聊会话的请求,IM服务只需要创建会话、设置会话与每个成员的关联关系即可。由于群聊不要求两个用户之间只能有一个群聊会话,所以不需要考虑用户B同时向用户A、用户C、用户D发起群聊导致两个群聊会话重复的问题,谁发起了群聊就新建一个群聊会话。从接收者的视角来说,会话的创建与单聊类似,这里不再赘述。
13.6.3 命令消息
我们在使用微信或者其他即时通信软件时,经常会看到如下事件。
- 好友给你发了一条消息,过了一会儿,你发现消息被撤回了。
- 群聊中提示:A邀请B加入了群聊、B被A移出群聊、A将B禁言。
- 群聊中提示:B退出了群聊。
其实这些事件都是依靠IM服务实现通知到客户端的,这些事件也被当作IM服务的消息来处理,只不过不同于用户发送的消息,这些事件被定义为命令消息,用于控制消息的展示、群聊成员的管理等。
为了区分用户消息和命令消息,在消息表中应该至少增加两个字段。
- msg_type:使用枚举类型,指示消息的具体类型,比如用户消息,有撤回消息、邀请加群、移出群、退群、禁言等。
- extra:使用字符串类型,命令消息所需要的额外参数被统一存储到这里,比如撤回消息事件需要指定被撤回的消息ID,邀请加群事件需要指定谁邀请谁,禁言事件需要指定谁禁言谁。
邀请加群、移出群、禁言这3种命令消息都需要指定事件发起者from_user和事件作用者to_user,即消息表中的extra字段需要存储如下参数:
1 | { |
当客户端收到这些命令消息时,其按照消息的具体类型,在对应的群聊中展示如下内容:
- 邀请加群:from_user邀请to_user加入群聊。
- 移出群:from_user将to_user移出群聊。
- 禁言:from_user将to_user禁言。
用户选择退群,IM 服务应该产生的相关命令消息需要指定退群者是谁,即消息表中的extra字段如下:
1 | { |
当客户端收到退群的命令消息时,其在对应的群聊会话中展示user退出了群聊。
用户选择撤回某条已发送的消息时,除修改消息表中的消息状态为“撤回”之外,IM服务还应该产生一条指定消息ID的撤回命令,用于让消息在触达的客户端也实现撤回的效果。消息表中的extra字段如下:
1 | { |
在客户端无论是通过推送还是拉取接收到这条消息后,IM服务都会将客户端已展示的对应的消息内容删除并改写为“消息被撤回”。