数据库改版
数据库设计
- 会话表
- 聊天详情表
- 群组表
- 群组信息表
- 群成员
- 联系人表
会话表
Id:自增长主键 Uid:该条消息所属消息,比如我登陆了,我发送/接收到消息入库的时候写入自己的uid,他的作用是多用户登陆的时候区分回话表 chatId:服务器生产回话 id当前的回话id,它作用是标识一个回话,比如我跟你聊天or 你跟我聊天,我们的回话id应该是一致的,对于群聊也是,在群中发送消息,每个人的回话id是一致的 c_id:他是标记一台设备上某个用户的唯一回话,用于更新避免插入多条数据的,可以用到sqlite的update or replace,他的值可以是hash(uid+chatid)或者其他,该字段可以只是客户端具有,客户端生成并且自己维护。 From:发送人id(自己发送就是自己的uid,不然就是别人的uid) to:接收人id(uid/group_id) last_msg:最后的一条消息内容 last_user_name:最后的发送者名称 last_time:最后消息发送时间 chat_type:回话类型(群组消息/个人聊天/系统消息) msg_type:消息类型(文字/图片/文件/音乐等) unread_count:改回话未读数目
聊天详情表
id:自增长主键 msg_id:消息唯一id,一般服务器生成,或者客户端本地使用UUID生成 uid:所属者uid from:发送者uid from_avatar:发送者头像 from_nam:发送者名称 to:接受者(uid/group_id) chat_type:会话类型 msg_type:消息类型 msg:消息内容 file_info:文件信息json格式 send_time:发送时间 send_status:发送状态 发送中,发送完成,发送失败 extra:把人插入 一般可以为null,预留的额外字段,使用JOSN字符串存储
群组表
Id:自增长主键 group_id:群组唯一id group_name:群组名称 group_name:群组头像 group_type:群组类型 group_num:群组数量 group_create_uid:群组创建者uid
群组信息表
Id:自增长主键 group_id:群组唯一id group_name:群组名称 group_name:群组头像 group_type:群组类型 group_num:群组数量 group_create_uid:群组创建者uid group_intrduce:群组简介 nick_name:个人的群昵称字段。 group_role:群组角色字段,比如你是管理员/群主/普通成员等(该字段的作用是可以用来做一个权限控制,比如在一些群里面,需要特定的人才可以拉人,需要群主才可以删除成员等,该字段是server下发的,根据不同的uid请求返回不同的role) group_members:部分群成员的List的JSON数据,该字段看UI设计,可能有的UI在群信息页面默认显示几个群成员,然后点击进入通过另外的接口查看全部群成员。如果是这种情况下,可以在群信息接口下发该群的一些必要显示成员既可。当然,这个字段也可以不用,用一个或者群成员接口替换,查看群信息的时候也同时请求群信息和群成员接口也可以
群成员表
Id:自增长主键 group_id:群组唯一id user_nam:用户名 user_avatar:varchar 头像 group_role:角色
联系人列表
Id:自增长主键 uid:所属者uid sex:性别信息 birthday:生日信息 user_name:用户名 user_avatar:varchar 头像 Relation:关系(比如好友/陌生人)
数据库升级
- 顺序型策略:不能跨版本升级。一个从版本1到3,需要先升级到2再到3
- 阶梯型策略:能跨版本升级。设计嵌套数据库迁移功能,进行1-2-3自动检测,通过中间层进行升级
IM v3.5 重构
开发要求
- 通用性
- 可用性
- 降级策略
设计原理
- IM 服务抽取成独立的模块,对外提供统一的集成和调用方式
- 监控管理提高线上质量
- IMSocketConfig: 是 SDK 的配置入口,主要完成服务器配置及相关参数设置的入口。
- IMSocketManager: 管理登录、退出、连接管理等功能。
- IMAPIManager: 负责消息的收发,完成会话管理、好友的添加删除,黑名单的管理。
- IMResponseHandle: 负责接收多种类型消息回调及 delegate 事件分发等功能。
问题:消息丢失和重复
FAQ:解决消息丢失和重复问题?
- 长连接轮询方式:带上客户端已读消息的 ID,由服务端计算出差值消息然后返回
- WebSocket 方式:服务端会在推送给客户端消息后,等待客户端的 ACK,如果客户端没有 ACK,服务端会尝试多次推送
前端 UIKit 实现
1)基于 UICollectionView 预加载和缓存气泡的大小计算 2)自动增长输入视图 3)多种包含的气泡类型
- 文本
- 大型表情符号
- 图像
- 视频
4)内置 SFSafariViewController 访问 Web 页面 5)内置一套基本的 iMessenges 风格示例主体 6)自定义主题系统,用于显示 UICollectionViewCells 的页眉,页脚和输入等视图
Protocol Buffer 数据结构
- 利用 varint 原理压缩数据以后,二进制数据非常紧凑
- 没有数据描述 .proto 文件是无法理解二进制数据流,加密性更好
- 向后兼容,更新数据结构以后,老版本依旧可以兼容
IM v4.0 阶段
可插拔跨平台架构
- Native 层:负责业务请求封装和数据解析,与原生进行交互
- Chat 层:负责提供底层通信使用的 c 接口,包含连接、读写和关闭
- WebSocket 层:实现 WebSocket 协议及维护心跳
- TLS 层:基于 mbedTLS 实现 TLS 协议及数据加解密
- TCP 层:基于 libuv 实现 TCP 连接和数据的读写
层级解耦,提高组件的灵活性,实现可插拔
C 语言调用方式
- Android 采用 JNI 的方式
- iOS 采用 runtime 的方式
插件化改造
- 将插件行为抽象出一个结构体,利用双向链表将前后插件绑定在一起,使用函数指针调用具体插件的函数或回调
- 通过修改插件的注册提高了灵活性,使得组件具有可插拔性(冷插拔)
存储库的数据建立多元索引:公开群的检索,需要对群 ID、消息发送人、消息类型、消息内容、以及时间建立索引,其中消息内容需要使用分词字符串类型,从而提供模糊查询的能力。做消息的权限管理需要扩展接收人 ID 数组。