群聊系统架构与业务设计
📋 概述
本文档全面解析OpenIM群聊系统的完整架构设计,涵盖存储架构、业务逻辑、权限控制和管理流程等核心模块:
🏗️ 系统架构层次
- 存储架构:客户端SQLite + 服务端MongoDB + Redis缓存的三层存储体系
- 业务架构:群组管理、成员管理、权限控制、申请审核等完整业务流程
- 权限架构:基于角色的分级权限控制体系,支持精细化权限管理
- 通知架构:实时通知机制,确保群组状态变更的及时同步
通过本文档,您将全面了解OpenIM群聊系统从底层存储到上层业务的完整设计架构。
第一部分:客户端存储层(SQLite)
🗄️ 核心表结构概览
OpenIM SDK 使用四个核心表实现完整的群聊数据存储:
| 表名 | 作用 | 数据特点 | 查询频率 |
|---|---|---|---|
| LocalGroup | 群组基础信息 | 相对稳定,变更较少 | 高频查询 |
| LocalGroupMember | 群成员信息 | 动态变化,成员进出频繁 | 超高频查询 |
| LocalGroupRequest | 群申请记录 | 临时数据,定期清理 | 中频查询 |
| LocalChatLog | 群聊消息记录 | 数据量大,增长快速 | 超高频查询 |
📋 1. LocalGroup - 本地群组信息表
表名: local_groups
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| GroupID | string(64) [主键] | PRIMARY KEY | 群组唯一标识 • 全局唯一的群组ID • 与服务端保持一致 • 作为主键,关联群成员和消息表 |
| GroupName | string(255) | 无 | 群组名称 • 群聊显示名称 • 支持实时更新 • 影响会话列表显示 |
| Notification | string(255) | 无 | 群公告内容 • 群主/管理员发布的公告 • 支持富文本格式 • 客户端弹窗提醒 |
| Introduction | string(255) | 无 | 群组介绍 • 群组详细描述 • 加群时展示给申请者 • 群信息页面显示 |
| FaceURL | string(255) | 无 | 群头像URL • 群组头像地址 • 支持本地缓存 • 会话列表头像显示 |
| CreateTime | int64 | 无 | 创建时间戳 • 群组创建时间 • 毫秒级时间戳 • 用于群组排序 |
| Status | int32 | 无 | 群组状态枚举 • 0 = 正常状态 (GroupOk)• 1 = 群禁言状态 (GroupBanChat)• 2 = 群解散状态 (GroupStatusDismissed)• 3 = 群静音状态 (GroupStatusMuted) |
| CreatorUserID | string(64) | 无 | 创建者用户ID • 群组创建者标识 • 与用户表关联 • 用于权限判断 |
| GroupType | int32 | 无 | 群组类型枚举 • 0 = 普通群 (NormalGroup)• 1 = 超级群 (SuperGroup)• 2 = 工作群 (WorkingGroup) |
| OwnerUserID | string(64) | 无 | 群主用户ID • 当前群主标识 • 支持转让变更 • 最高权限拥有者 |
| MemberCount | int32 | 无 | 群成员数量 • 实时成员统计 • 避免实时count查询 • 上限根据群类型确定 |
| Ex | string(1024) | 无 | 扩展字段 • 自定义数据存储 • JSON格式 • 业务扩展使用 |
| AttachedInfo | string(1024) | 无 | 附加信息 • 额外业务数据 • 可选的元数据信息 • 客户端自定义使用 |
| NeedVerification | int32 | 无 | 入群验证设置枚举 • 0 = 申请需要验证, 邀请直接进群 (ApplyNeedVerificationInviteDirectly)• 1 = 所有人需要验证,除了群主管理员邀请 (AllNeedVerification)• 2 = 直接进群 (Directly) |
| LookMemberInfo | int32 | 无 | 查看成员信息权限枚举 • 0 = 所有人可查看 (ALL)• 1 = 仅群成员可查看 (MEMBER_ONLY)• 2 = 仅管理员可查看 (ADMIN_ONLY)• 3 = 禁止查看 (FORBIDDEN) |
| ApplyMemberFriend | int32 | 无 | 添加成员为好友权限枚举 • 0 = 允许添加 (ALLOW)• 1 = 需要验证 (NEED_VERIFICATION)• 2 = 禁止添加 (FORBIDDEN)• 3 = 仅管理员可添加 (ADMIN_ONLY) |
| NotificationUpdateTime | int64 | 无 | 群公告更新时间戳 • 公告最后更新时间 • 用于公告变更提醒 • 毫秒级时间戳 |
| NotificationUserID | string(64) | 无 | 群公告更新者ID • 最后修改公告的用户 • 公告来源追踪 • 权限验证使用 |
👥 2. LocalGroupMember - 本地群成员信息表
表名: local_group_members
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| GroupID | string(64) [联合主键] | PRIMARY KEY | 群组标识 • 关联群组表 • 成员归属群组 • 联合主键组成部分 |
| UserID | string(64) [联合主键] | PRIMARY KEY | 成员用户ID • 用户唯一标识 • 联合主键组成部分 • 一个用户在一个群中唯一 |
| Nickname | string(255) | 无 | 群内昵称 • 成员在群内显示名称 • 可与真实昵称不同 • 群主/管理员可修改 |
| FaceURL | string(255) | 无 | 成员头像URL • 用户头像快照 • 群内头像显示 • 支持本地缓存 |
| RoleLevel | int32 | INDEX | 角色等级枚举 • 20 = 普通成员 (GroupOrdinaryUsers)• 60 = 管理员 (GroupAdmin)• 100 = 群主 (GroupOwner)• 权限递增,索引优化查询 |
| JoinTime | int64 | INDEX | 加入时间戳 • 成员入群时间 • 毫秒级时间戳 • 成员列表排序依据 |
| JoinSource | int32 | 无 | 加入来源枚举 • 1 = 管理员邀请 (JoinByAdmin)• 2 = 邀请加入 (JoinByInvitation)• 3 = 搜索加入 (JoinBySearch)• 4 = 扫码加入 (JoinByQRCode) |
| InviterUserID | string(64) | 无 | 邀请者用户ID • 邀请该成员的用户 • 追踪邀请关系 • 入群来源管理 |
| MuteEndTime | int64 | 无 | 禁言结束时间戳 • 0表示未被禁言 • 大于当前时间表示禁言中 • 毫秒级时间戳 |
| OperatorUserID | string(64) | 无 | 操作者用户ID • 最后操作该成员的用户 • 用于操作日志记录 • 权限变更追踪 |
| Ex | string(1024) | 无 | 扩展字段 • 成员自定义数据 • JSON格式存储 • 业务扩展使用 |
| AttachedInfo | string(1024) | 无 | 附加信息 • 成员相关元数据 • 可选的业务信息 • 灵活扩展支持 |
📨 3. LocalGroupRequest - 本地群申请记录表
表名: local_group_request
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| GroupID | string(64) [联合主键] | PRIMARY KEY | 目标群组ID • 申请加入的群组 • 联合主键组成部分 |
| UserID | string(64) [联合主键] | PRIMARY KEY | 申请者用户ID • 发起申请的用户 • 联合主键组成部分 |
| GroupName | string(255) | 无 | 群组名称快照 • 申请时的群名 • 避免群名变更后显示异常 • 申请列表展示使用 |
| Notification | string(255) | 无 | 群公告快照 • 申请时的群公告 • 申请页面展示 • 用户了解群组信息 |
| Introduction | string(255) | 无 | 群介绍快照 • 申请时的群介绍 • 帮助用户了解群组 • 申请决策参考 |
| GroupFaceURL | string(255) | 无 | 群头像快照 • 申请时的群头像 • 申请列表头像展示 • 保持视觉一致性 |
| CreateTime | int64 | 无 | 群组创建时间 • 群组创建时间快照 • 群组基本信息 |
| CreatorUserID | string(64) | 无 | 群创建者ID • 群组创建者快照 • 群组历史信息 |
| GroupType | int32 | 无 | 群组类型快照 • 申请时的群类型 • 类型变更后的历史记录 |
| OwnerUserID | string(64) | 无 | 群主ID快照 • 申请时的群主 • 群主变更后的历史记录 |
| MemberCount | int32 | 无 | 成员数量快照 • 申请时的成员数 • 群规模参考信息 |
| Nickname | string(255) | 无 | 申请者昵称 • 申请者当时昵称 • 审核时显示使用 • 历史昵称记录 |
| UserFaceURL | string(255) | 无 | 申请者头像 • 申请者当时头像 • 审核页面头像展示 • 快照保持一致性 |
| HandleResult | int32 | 无 | 处理结果枚举 • 0 = 待处理 (默认状态)• 1 = 同意 (GroupResponseAgree)• -1 = 拒绝 (GroupResponseRefuse) |
| ReqMsg | string(255) | 无 | 申请消息 • 申请者填写的入群理由 • 帮助管理员决策 • 最大255字符 |
| HandledMsg | string(255) | 无 | 处理消息 • 管理员处理时填写的消息 • 同意/拒绝的具体原因 • 反馈给申请者 |
| ReqTime | int64 | 无 | 申请时间戳 • 申请发起时间 • 毫秒级时间戳 • 申请列表排序依据 |
| HandleUserID | string(64) | 无 | 处理者用户ID • 处理申请的管理员/群主 • 权限追踪 • 操作日志记录 |
| HandledTime | int64 | 无 | 处理时间戳 • 申请处理时间 • 0表示未处理 • 处理效率统计 |
| Ex | string(1024) | 无 | 扩展字段 • 申请相关自定义数据 • JSON格式存储 |
| AttachedInfo | string(1024) | 无 | 附加信息 • 申请相关元数据 • 业务扩展支持 |
| JoinSource | int32 | 无 | 申请来源 • 与成员表JoinSource对应 • 申请渠道统计 |
| InviterUserID | string(64) | 无 | 邀请者ID • 如通过邀请申请 • 邀请关系追踪 |
第二部分:服务端存储层
🏗️ 架构概览
服务端采用三层存储架构:
- MongoDB:持久化存储,保证数据安全和事务一致性
- Redis:高速缓存,提升查询性能,支持大群场景
🗄️ MongoDB 数据库存储层
1. Group - 群组核心表
集合名: group
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| _id | ObjectId | PRIMARY KEY | MongoDB主键 • 自动生成的唯一标识 |
| GroupID | string | UNIQUE INDEX | 群组唯一标识 • 业务层面的唯一ID • 与客户端保持一致 • 关键查询索引字段 |
| GroupName | string | 无 | 群组名称 • 群聊显示名称 • 支持修改更新 • 搜索功能使用 |
| Notification | string | 无 | 群公告内容 • 富文本群公告 • 支持链接和格式 • 群管理功能核心 |
| Introduction | string | 无 | 群组介绍 • 群组详细描述 • 搜索和推荐使用 • 入群申请展示 |
| FaceURL | string | 无 | 群头像URL • 群组头像存储链接 • CDN分发优化 • 多端同步显示 |
| CreateTime | time.Time | INDEX | 创建时间 • MongoDB时间类型 • 自动索引优化 • 统计分析使用 |
| Ex | string | 无 | 扩展字段 • 业务自定义数据 • JSON格式存储 • 灵活扩展支持 |
| Status | int32 | 无 | 群组状态 • 0 = 正常 (GroupOk)• 1 = 群禁言状态 (GroupBanChat)• 2 = 群解散状态 (GroupStatusDismissed)• 3 = 群静音状态 (GroupStatusMuted) |
| CreatorUserID | string | 无 | 创建者用户ID • 群组创建者标识 • 历史记录保存 • 权限判断依据 |
| GroupType | int32 | 无 | 群组类型 • 0 = 普通群 (NormalGroup)• 1 = 超级群 (SuperGroup)• 2 = 工作群 (WorkingGroup)• 不同类型不同规则 |
| NeedVerification | int32 | 无 | 入群验证设置 • 控制入群门槛 • 群管理策略 • 自动化审核规则 |
| LookMemberInfo | int32 | 无 | 查看成员权限 • 隐私保护设置 • 成员信息可见性 • 安全策略配置 |
| ApplyMemberFriend | int32 | 无 | 加好友权限 • 群内社交控制 • 防骚扰机制 • 隐私保护策略 |
| NotificationUpdateTime | time.Time | 无 | 公告更新时间 • 公告版本控制 • 变更通知依据 • 时间戳精确记录 |
| NotificationUserID | string | 无 | 公告更新者 • 操作者追踪 • 管理审计日志 • 权限验证使用 |
2. GroupMember - 群成员表
集合名: group_member
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| _id | ObjectId | PRIMARY KEY | MongoDB主键 |
| GroupID | string | INDEX | 群组ID • 复合索引:group_id + user_id • 成员归属群组 • 高频查询优化 |
| UserID | string | INDEX | 用户ID • 复合索引组成部分 • 用户群组反向查询 • 权限验证使用 |
| Nickname | string | 无 | 群内昵称 • 群内显示名称 • 可与全局昵称不同 • 群主管理员可修改 |
| FaceURL | string | 无 | 头像URL • 用户头像链接 • 群内头像显示 • 同步全局头像变更 |
| RoleLevel | int32 | INDEX | 角色等级 • 20 = 普通成员 (GroupOrdinaryUsers)• 60 = 管理员 (GroupAdmin)• 100 = 群主 (GroupOwner)• 权限控制核心字段 |
| JoinTime | time.Time | INDEX | 加入时间 • 成员入群时间记录 • 排序和统计使用 • 成员资历判断 |
| JoinSource | int32 | 无 | 加入来源 • 入群渠道统计 • 推广效果分析 • 成员质量评估 |
| InviterUserID | string | 无 | 邀请者ID • 邀请关系链 • 社交网络分析 • 成员来源追踪 |
| OperatorUserID | string | 无 | 操作者ID • 最后操作记录 • 管理操作审计 • 权限变更追踪 |
| MuteEndTime | time.Time | 无 | 禁言结束时间 • 禁言功能支持 • 自动解禁机制 • 群管理工具 |
| Ex | string | 无 | 扩展字段 • 成员自定义属性 • 业务数据扩展 • JSON格式存储 |
3. GroupRequest - 群申请表
集合名: group_request
完整字段结构
| 字段名 | 字段类型 | 索引 | 详细描述 |
|---|---|---|---|
| _id | ObjectId | PRIMARY KEY | MongoDB主键 |
| UserID | string | INDEX | 申请者用户ID • 复合索引:user_id + group_id • 申请者标识 • 申请历史查询 |
| GroupID | string | INDEX | 目标群组ID • 复合索引组成部分 • 群组申请管理 • 批量处理支持 |
| HandleResult | int32 | INDEX | 处理结果 • 0 = 待处理 (默认状态)• 1 = 同意 (GroupResponseAgree)• -1 = 拒绝 (GroupResponseRefuse)• 申请状态过滤索引 |
| ReqMsg | string | 无 | 申请消息 • 申请者入群理由 • 管理员审核参考 • 申请质量评估 |
| HandledMsg | string | 无 | 处理消息 • 管理员处理说明 • 拒绝/同意原因 • 申请者反馈信息 |
| ReqTime | time.Time | INDEX | 申请时间 • 申请发起时间 • 申请列表排序 • 处理时效统计 |
| HandleUserID | string | 无 | 处理者ID • 处理申请的管理员 • 管理操作追踪 • 权限验证使用 |
| HandledTime | time.Time | 无 | 处理时间 • 申请处理时间 • 处理效率统计 • 时效性分析 |
| JoinSource | int32 | 无 | 申请来源 • 申请渠道统计 • 与成员加入来源对应 • 转化率分析 |
| InviterUserID | string | 无 | 邀请者ID • 邀请类申请的邀请者 • 邀请关系维护 • 社交网络构建 |
| Ex | string | 无 | 扩展字段 • 申请相关扩展数据 • 自定义申请属性 • 业务数据支持 |
🚀 Redis 缓存层
OpenIM Redis缓存采用分层过期策略和智能预加载,特别针对群聊场景优化:
1. 群组信息相关缓存
| 缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
|---|---|---|---|---|
GROUP_INFO:{groupID} | Hash | 24小时 | 完整群组信息 | 群组详情快速查询 |
GROUP_MEMBER_IDS:{groupID} | Set | 12小时 | 群成员用户ID集合 | 群消息推送,权限验证 |
GROUP_MEMBER_INFO:{groupID}:{userID} | Hash | 12小时 | 单个成员详细信息 | 成员信息快速查询 |
GROUP_MEMBER_NUM_CACHE:{groupID} | String | 6小时 | 群成员数量 | 成员统计,群容量检查 |
GROUP_OWNER:{groupID} | Hash | 24小时 | 群主信息 | 权限验证,管理操作 |
2. 群成员角色相关缓存
| 缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
|---|---|---|---|---|
GROUP_ADMINS:{groupID} | Set | 12小时 | 管理员用户ID集合 | 管理权限快速验证 |
GROUP_MEMBERS_ALL:{groupID} | List | 6小时 | 全部成员信息列表 | 成员列表展示 |
GROUP_ROLE_LEVEL_{roleLevel}:{groupID} | Set | 12小时 | 指定角色级别成员ID | 按角色查询成员 |
USER_JOINED_GROUPS:{userID} | Set | 12小时 | 用户加入的群组ID集合 | 用户群组列表 |
USER_MANAGED_GROUPS:{userID} | Set | 12小时 | 用户管理的群组ID集合 | 管理员权限快速检查 |
3. 群成员哈希缓存
| 缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
|---|---|---|---|---|
GROUP_MEMBER_HASH:{groupID} | String | 24小时 | 群成员列表哈希值 | 成员变更检测 |
GROUP_MEMBER_VERSION:{groupID} | Hash | 永久 | 群成员版本信息 | 增量同步控制 |
USER_JOIN_GROUP_VERSION:{userID} | Hash | 永久 | 用户加群版本信息 | 用户群组同步 |
4. 群申请管理缓存
| 缓存Key格式 | 数据类型 | TTL时间 | 缓存内容 | 使用场景 |
|---|---|---|---|---|
GROUP_REQUEST_COUNT:{groupID} | String | 30分钟 | 待处理申请数量 | 申请数量统计 |
USER_GROUP_REQUESTS:{userID} | List | 2小时 | 用户发起的群申请 | 申请历史查询 |
GROUP_PENDING_REQUESTS:{groupID} | List | 1小时 | 群组待处理申请 | 申请管理页面 |
第三部分:群组管理操作权限矩阵
🔐 群组操作权限控制表
OpenIM群组系统采用严格的分级权限控制机制,根据用户角色不同,拥有不同的操作权限。以下表格详细列出了所有群组管理操作及其对应的角色权限:
| 操作名称 | 功能描述 | 系统管理员 | 群主 | 管理员 | 普通成员 | 特殊说明 |
|---|---|---|---|---|---|---|
| CreateGroup | 创建群组 | ✅ | ✅ | ✅ | ✅ | 需要通过CheckAccessV3验证权限 |
| InviteUserToGroup | 邀请用户加入群组 | ✅ | ✅ | ✅ | ⚠️ | 普通成员在需验证群组中只能发起申请 |
| KickGroupMember | 踢出群组成员 | ✅ | ✅ | ⚠️ | ❌ | 管理员不能踢出群主和其他管理员 |
| QuitGroup | 退出群组 | ✅ | ❌ | ✅ | ✅ | 群主不能退出群组,需先转让群主 |
| SetGroupInfo | 设置群组信息 | ✅ | ✅ | ✅ | ❌ | 修改群名称、头像、公告等信息 |
| SetGroupInfoEx | 扩展设置群组信息 | ✅ | ✅ | ✅ | ❌ | 扩展版本的群组信息设置 |
| TransferGroupOwner | 转让群主 | ✅ | ✅ | ❌ | ❌ | 只有群主可以转让群主身份 |
| DismissGroup | 解散群组 | ✅ | ✅ | ❌ | ❌ | 解散群组是不可逆操作 |
| MuteGroupMember | 禁言群组成员 | ✅ | ✅ | ⚠️ | ❌ | 管理员不能禁言群主和其他管理员 |
| CancelMuteGroupMember | 取消禁言群组成员 | ✅ | ✅ | ⚠️ | ❌ | 权限规则同禁言操作 |
| MuteGroup | 全群禁言 | ✅ | ✅ | ✅ | ❌ | 禁止所有成员发言 |
| CancelMuteGroup | 取消全群禁言 | ✅ | ✅ | ✅ | ❌ | 恢复群组正常发言 |
| SetGroupMemberInfo | 设置群成员信息 | ✅ | ✅ | ⚠️ | ⚠️ | 角色权限有复杂的层级控制 |
| GroupApplicationResponse | 处理群组申请 | ✅ | ✅ | ✅ | ❌ | 审核加群申请(同意/拒绝) |
| JoinGroup | 申请加入群组 | ✅ | ✅ | ✅ | ✅ | 所有用户都可以申请加群 |
| GetGroupMemberList | 获取群成员列表 | ✅ | ✅ | ✅ | ✅ | 需要是群组成员或系统管理员 |
| GetGroupAllMember | 获取群所有成员 | ✅ | ✅ | ✅ | ✅ | 无特殊权限限制 |
| GetGroupsInfo | 获取群组信息 | ✅ | ✅ | ✅ | ✅ | 获取群组基本信息 |
| GetGroupMembersInfo | 获取群成员详细信息 | ✅ | ✅ | ✅ | ✅ | 需要是群组成员或系统管理员 |
| GetGroupApplicationList | 获取群组申请列表 | ✅ | ✅ | ✅ | ❌ | 查看待处理的加群申请 |
| GetUserReqApplicationList | 获取用户申请列表 | ✅ | ✅ | ✅ | ✅ | 查看用户发起的申请(需权限验证) |
🏷️ 权限标识说明
| 标识 | 含义 | 说明 |
|---|---|---|
| ✅ | 完全权限 | 可以执行该操作,无特殊限制 |
| ⚠️ | 有条件权限 | 可以执行,但有特定条件或限制 |
| ❌ | 无权限 | 不能执行该操作 |
🔒 详细权限控制规则
1. 系统管理员权限特性
- 最高权限:系统管理员通过
authverify.IsAppManagerUid()验证,拥有所有群组的完全控制权 - 跨群组操作:可以操作任何群组,不受群组成员身份限制
- 权限覆盖:可以绕过大部分业务权限验证
2. 群主权限特性
- 群组所有者:拥有该群组的完全控制权(除了退出群组)
- 不可退出:群主不能直接退出群组,必须先转让群主身份
- 最高管理权:可以踢出任何成员、设置任何成员角色
3. 管理员权限特性
- 有限管理权:可以进行大部分管理操作,但不能操作群主和其他管理员
- 禁言限制:不能禁言群主,对其他管理员的操作受限
- 踢出限制:不能踢出群主和其他管理员
4. 普通成员权限特性
- 基础权限:主要是查看和自我管理权限
- 申请权限:可以申请加入群组、退出群组
- 受限操作:大部分管理操作需要更高权限
5. 特殊权限控制场景
| 场景 | 权限规则 | 代码实现 |
|---|---|---|
| 角色变更 | 只能降低或保持角色等级,不能提升自己角色 | SetGroupMemberInfo中的复杂权限验证 |
| 邀请验证 | 根据群组验证设置决定直接加入还是申请模式 | InviteUserToGroup中的验证逻辑 |
| 权限继承 | 高等级角色拥有低等级角色的所有权限 | 各方法中的角色等级比较 |
| 操作审计 | 所有管理操作记录操作者信息 | OperatorUserID字段记录 |
| Webhook扩展 | 支持业务自定义权限验证逻辑 | 各操作前后的Webhook回调 |
6. 权限验证代码模式
// 模式1:系统管理员检查
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
// 非系统管理员需要进一步权限验证
}
// 模式2:群组管理员检查
func (g *groupServer) CheckGroupAdmin(ctx context.Context, groupID string) error {
if !authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
groupMember, err := g.db.TakeGroupMember(ctx, groupID, mcontext.GetOpUserID(ctx))
if err != nil {
return err
}
if !(groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin) {
return errs.ErrNoPermission.WrapMsg("no group owner or admin")
}
}
return nil
}
// 模式3:群组成员检查
func (g *groupServer) checkAdminOrInGroup(ctx context.Context, groupID string) error {
if authverify.IsAppManagerUid(ctx, g.config.Share.IMAdminUserID) {
return nil
}
// 检查是否为群组成员
}
7. 权限验证函数映射表
| 验证函数 | 适用操作 | 权限要求 |
|---|---|---|
CheckGroupAdmin | 群组管理操作 | 系统管理员 或 群主/管理员 |
checkAdminOrInGroup | 群组信息查询 | 系统管理员 或 群组成员 |
authverify.CheckAccessV3 | 用户相关操作 | 本人操作 或 系统管理员 |
authverify.IsAppManagerUid | 所有操作 | 系统管理员验证 |
第四部分:群组管理操作详细流程分析
🔄 操作关系图谱
在深入分析每个操作的详细流程之前,我们先通过关系图谱了解各个操作之间的依赖和关联关系:
graph TD
subgraph "核心管理操作"
A[CreateGroup] --> B[InviteUserToGroup]
A --> C[SetGroupInfo]
B --> D[GetGroupMemberList]
C --> E[GroupInfoSetNotification]
end
subgraph "成员管理操作"
F[JoinGroup] --> G[GroupApplicationResponse]
G --> H[MemberEnterNotification]
B --> I[MuteGroupMember]
I --> J[CancelMuteGroupMember]
K[KickGroupMember] --> L[MemberQuitNotification]
M[QuitGroup] --> L
end
subgraph "权限管理操作"
N[TransferGroupOwner] --> O[GroupOwnerTransferredNotification]
P[SetGroupMemberInfo] --> Q[GroupMemberInfoSetNotification]
R[MuteGroup] --> S[CancelMuteGroup]
end
subgraph "解散相关操作"
T[DismissGroup] --> U[GroupDismissedNotification]
M --> V{是否群主}
V -->|是| T
V -->|否| L
end
subgraph "查询操作"
W[GetGroupsInfo] --> X[GetGroupMembersInfo]
D --> X
Y[GetGroupApplicationList] --> Z[GetUserReqApplicationList]
end
🎯 操作分类与数据流转模式
| 操作类型 | 典型操作 | 数据流转特点 | 缓存影响范围 | 通知触发 |
|---|---|---|---|---|
| 创建类 | CreateGroup, JoinGroup | 新增数据,大量缓存更新 | 全局影响 | 多用户通知 |
| 修改类 | SetGroupInfo, MuteGroupMember | 更新数据,局部缓存失效 | 局部影响 | 群组通知 |
| 删除类 | KickGroupMember, DismissGroup | 删除数据,大量缓存清理 | 广泛影响 | 多用户通知 |
| 查询类 | GetGroupMemberList, GetGroupsInfo | 读取操作,缓存优先 | 无影响 | 无通知 |
| 流程类 | GroupApplicationResponse | 状态变更,条件处理 | 条件影响 | 条件通知 |
📊 1. CreateGroup - 创建群组详细流程
sequenceDiagram
participant Client as 客户端
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
participant User as 用户服务
participant Conv as 会话服务
Client->>API: CreateGroupReq
Note over API: 1. 权限验证阶段
API->>API: CheckAccessV3(创建者权限)
Note over API: 2. 参数处理阶段
API->>API: GenGroupID(生成/验证GroupID)
API->>User: GetUsersInfo(验证初始成员)
User-->>API: 返回用户信息
Note over API: 3. 数据库操作阶段
API->>MongoDB: 开启事务
API->>MongoDB: 插入groups集合
Note over MongoDB: 插入字段:<br/>- group_id<br/>- group_name<br/>- notification<br/>- face_url<br/>- status=0<br/>- group_type<br/>- need_verification
API->>MongoDB: 批量插入group_members集合
Note over MongoDB: 群主成员记录:<br/>- role_level=100<br/>- join_source=1<br/>- join_time=now()
API->>MongoDB: 提交事务
Note over API: 4. 缓存清理阶段
API->>Redis: DEL GROUP_INFO:{groupID}
API->>Redis: DEL JOIN_GROUPS:{creatorUserID}
API->>Redis: DEL GROUP_MEMBER_IDS:{groupID}
API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID}
API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBER_IDS:{groupID}
loop 每个初始成员
API->>Redis: DEL JOIN_GROUPS:{memberUserID}
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{memberUserID}
end
Note over API: 5. 版本控制更新
API->>API: setVersion(groups, groupID)
API->>API: setSortVersion(group_members, groupID)
Note over API: 6. 通知发送阶段
API->>Notify: GroupCreatedNotification
Note over Notify: 通知内容类型:<br/>constant.GroupCreatedNotification<br/>会话类型: ReadGroupChatType
API->>Conv: SetConversations(创建群组会话)
API-->>Client: CreateGroupResp{GroupInfo}
关键Redis Key操作清单:
GROUP_INFO:{groupID}- DELETE (新群组,确保缓存一致性)GROUP_MEMBERS_HASH2:{groupID}- DELETE (新群组,确保缓存一致性)GROUP_MEMBER_NUM_CACHE:{groupID}- DELETEGROUP_MEMBER_IDS:{groupID}- DELETEJOIN_GROUPS:{userID}- DELETE (每个初始成员)GROUP_ROLE_LEVEL_MEMBER_IDS:{groupID}:{roleLevel}- DELETEGROUP_MEMBERS_HASH:{groupID}- DELETEGROUP_MEMBER_INFO:{groupID}:{userID}- DELETE
MongoDB操作清单:
groups集合 - INSERT ONE (新群组记录)group_members集合 - INSERT MANY (初始成员记录)
👥 2. InviteUserToGroup - 邀请用户加群详细流程
sequenceDiagram
participant Client as 客户端
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
participant User as 用户服务
participant Webhook as Webhook服务
Client->>API: InviteUserToGroupReq
Note over API: 1. 基础参数验证
API->>API: 验证被邀请用户列表非空
API->>API: 检查用户ID不重复
Note over API: 2. 群组状态验证
API->>MongoDB: TakeGroup(获取群组信息)
MongoDB-->>API: 群组基础信息
API->>API: 检查群组状态!=GroupStatusDismissed
Note over API: 3. 用户存在性验证
API->>User: GetUsersInfoMap(验证被邀请用户)
User-->>API: 用户信息映射
API->>API: 确认所有被邀请用户存在
Note over API: 4. 操作者权限验证
alt 系统管理员
API->>API: IsAppManagerUid(检查系统管理员)
API->>API: 获取操作者ID
else 普通用户
API->>MongoDB: TakeGroupMember(获取操作者群组信息)
MongoDB-->>API: 操作者群组成员信息
API->>User: PopulateGroupMember(填充用户信息)
end
Note over API: 5. Webhook前置回调
API->>Webhook: BeforeInviteUserToGroup
Webhook-->>API: 回调结果
Note over API: 6. 群组验证策略判断
alt 群组需要验证(AllNeedVerification=1)
alt 非系统管理员 && 非群主/管理员
Note over API: 创建入群申请模式
loop 每个被邀请用户
API->>API: 构建GroupRequest记录
Note over API: join_source=JoinByInvitation<br/>inviter_user_id=操作者ID<br/>req_time=当前时间
end
API->>MongoDB: CreateGroupRequest(批量创建申请)
loop 每个申请
API->>Notify: JoinGroupApplicationNotification
end
API-->>Client: 返回成功(申请已创建)
else 系统管理员或群主/管理员
Note over API: 继续直接邀请流程
end
else 其他验证策略
Note over API: 直接邀请流程
end
Note over API: 7. 直接邀请流程
loop 每个被邀请用户
API->>API: 构建GroupMember记录
Note over API: role_level=GroupOrdinaryUsers(20)<br/>join_source=JoinByInvitation(2)<br/>inviter_user_id=操作者ID<br/>join_time=当前时间
end
Note over API: 8. Webhook成员加入前回调
API->>Webhook: BeforeMemberJoinGroup
Webhook-->>API: 回调结果
Note over API: 9. 批量处理邀请(每批50个)
loop 分批处理(每批singleQuantity=50)
API->>MongoDB: CreateGroup(批量插入group_members)
Note over MongoDB: 事务插入群成员记录<br/>触发缓存清理链式操作
Note over API: 9.1 MongoDB事务操作
MongoDB->>MongoDB: group_members.insertMany()
Note over API: 9.2 Redis缓存清理
MongoDB->>Redis: 清理相关缓存
Redis->>Redis: DelGroupMembersHash(groupID)
Redis->>Redis: DelGroupsMemberNum(groupID)
Redis->>Redis: DelGroupMemberIDs(groupID)
loop 每个新成员
Redis->>Redis: DelJoinedGroupID(userID)
Redis->>Redis: DelGroupMembersInfo(groupID, userID)
end
Redis->>Redis: DelGroupAllRoleLevel(groupID)
Redis->>Redis: DelMaxJoinGroupVersion(userIDs)
Redis->>Redis: DelMaxGroupMemberVersion(groupID)
Note over API: 9.3 发送成员加入通知
API->>Notify: GroupApplicationAgreeMemberEnterNotification
Note over Notify: 通知类型: MemberEnterNotification<br/>通知对象: 群组所有成员<br/>消息内容: 新成员加入信息
end
API-->>Client: InviteUserToGroupResp(成功)
🔍 邀请验证策略详细解析
OpenIM支持三种群组邀请验证策略,通过NeedVerification字段控制:
| 验证值 | 常量名 | 验证策略 | 邀请者权限要求 | 行为描述 |
|---|---|---|---|---|
0 | ApplyNeedVerificationInviteDirectly | 申请需验证,邀请直接进 | 无特殊限制 | 任何成员邀请都直接加入群组 |
1 | AllNeedVerification | 所有人需要验证 | 群主/管理员可直接邀请 | 普通成员邀请创建申请,需管理员审核 |
2 | Directly | 直接进群 | 无特殊限制 | 所有邀请都直接加入群组 |
💾 数据库操作详细分析
1. MongoDB事务操作
直接邀请模式的MongoDB操作:
// 批量插入群成员记录
db.group_members.insertMany([
{
"group_id": "group_12345",
"user_id": "user_67890",
"role_level": 20, // GroupOrdinaryUsers
"join_source": 2, // JoinByInvitation
"inviter_user_id": "inviter_11111", // 邀请者ID
"operator_user_id": "inviter_11111", // 操作者ID
"join_time": ISODate("2024-01-15T10:30:00.000Z"),
"mute_end_time": ISODate("1970-01-01T00:00:00.000Z")
}
// ... 更多成员记录
])
申请模式的MongoDB操作:
// 批量插入群申请记录
db.group_requests.insertMany([
{
"group_id": "group_12345",
"user_id": "user_67890",
"join_source": 2, // JoinByInvitation
"inviter_user_id": "inviter_11111", // 邀请者ID
"req_time": ISODate("2024-01-15T10:30:00.000Z"),
"handled_time": ISODate("1970-01-01T00:00:00.000Z"),
"handle_result": 0, // 待处理状态
"req_msg": "", // 申请消息(邀请时为空)
"handled_msg": "" // 处理消息(待处理时为空)
}
// ... 更多申请记录
])
2. Redis缓存管理策略
OpenIM采用链式缓存清理机制,确保数据一致性:
缓存清理顺序与原因:
// 缓存清理链式操作
c := g.cache.CloneGroupCache()
// 1. 群组成员相关缓存
c = c.DelGroupMembersHash(groupID) // 成员列表哈希,用于变更检测
.DelGroupsMemberNum(groupID) // 成员数量缓存
.DelGroupMemberIDs(groupID) // 成员ID列表缓存
// 2. 用户相关缓存(针对每个新成员)
.DelJoinedGroupID(userID) // 用户加入的群组列表
.DelGroupMembersInfo(groupID, userID) // 单个成员详细信息
// 3. 角色相关缓存
.DelGroupAllRoleLevel(groupID) // 所有角色级别的成员缓存
// 4. 版本控制缓存
.DelMaxJoinGroupVersion(userIDs) // 用户加群版本
.DelMaxGroupMemberVersion(groupID) // 群成员版本
// 执行链式删除
return c.ChainExecDel(ctx)
关键Redis Key分析:
| 缓存Key模式 | 数据类型 | 作用 | 清理原因 |
|---|---|---|---|
GROUP_MEMBERS_HASH:{groupID} | String | 成员列表哈希值 | 成员变更需重新计算哈希 |
GROUP_MEMBER_NUM:{groupID} | String | 成员数量 | 新成员加入,数量发生变化 |
GROUP_MEMBER_IDS:{groupID} | List | 成员ID列表 | 新成员ID需要添加到列表 |
JOIN_GROUPS:{userID} | Set | 用户参与的群组 | 用户新加入群组 |
GROUP_MEMBERS_INFO:{groupID}:{userID} | Hash | 成员详细信息 | 新成员信息需要重新加载 |
GROUP_ROLE_LEVEL_*:{groupID} | Set | 各角色成员列表 | 新成员加入普通成员角色 |
🚪 3. KickGroupMember - 踢出群成员详细流程
sequenceDiagram
participant Admin as 管理员/群主
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
participant Conv as 会话服务
Admin->>API: KickGroupMemberReq
Note over API: 1. 权限验证阶段
API->>API: CheckGroupAdmin(操作者权限)
API->>Redis: HGET GROUP_MEMBER_INFO:{groupID}:{operatorUserID}
Redis-->>API: 操作者角色信息
Note over API: 2. 被踢用户权限检查
loop 每个被踢用户
API->>Redis: HGET GROUP_MEMBER_INFO:{groupID}:{kickedUserID}
Redis-->>API: 被踢用户角色信息
API->>API: 权限规则验证
Note over API: 规则:管理员不能踢群主<br/>管理员不能踢其他管理员
end
Note over API: 3. 数据库删除操作
API->>MongoDB: 开启事务
loop 每个被踢用户
API->>MongoDB: DELETE FROM group_members WHERE group_id=? AND user_id=?
end
API->>MongoDB: 提交事务
Note over API: 4. 大量缓存清理
loop 每个被踢用户
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{kickedUserID}
API->>Redis: DEL JOIN_GROUPS:{kickedUserID}
end
API->>Redis: DEL GROUP_MEMBER_IDS:{groupID}
API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID}
API->>Redis: DEL GROUP_MEMBERS_HASH:{groupID}
Note over API: 5. 会话管理
loop 每个被踢用户
API->>Conv: SetConversationMaxSeq(更新会话序号)
end
Note over API: 6. 版本控制
API->>API: setVersion(group_members, groupID)
Note over API: 7. 通知发送
API->>Notify: MemberKickedNotification
Note over Notify: 通知对象:<br/>1. 被踢用户:踢出通知<br/>2. 群内其他成员:成员变更通知<br/>通知类型:MemberKickedNotification
API-->>Admin: KickGroupMemberResp{Success}
详细缓存操作列表:
删除的Redis Key:
GROUP_MEMBER_INFO:{groupID}:{kickedUserID}- DELETE (每个被踢用户)JOIN_GROUPS:{kickedUserID}- DELETE (每个被踢用户)GROUP_MEMBER_IDS:{groupID}- DELETE (成员ID列表)GROUP_MEMBER_NUM_CACHE:{groupID}- DELETE (成员数量)GROUP_MEMBERS_HASH:{groupID}- DELETE (成员哈希)
权限验证规则代码逻辑:
// 权限验证逻辑
if operatorRole == constant.GroupOwner {
// 群主可以踢任何人
return true
} else if operatorRole == constant.GroupAdmin {
// 管理员只能踢普通成员
return targetRole == constant.GroupOrdinaryUsers
}
return false
⚙️ 4. SetGroupInfo - 设置群组信息详细流程
stateDiagram-v2
[*] --> ValidatePermission : SetGroupInfoReq
ValidatePermission --> CheckFields : 权限验证通过
ValidatePermission --> [*] : 权限不足返回错误
CheckFields --> DetectChanges : 字段有效性验证
DetectChanges --> HandleNameChange : 群名称变更
DetectChanges --> HandleAnnouncementChange : 群公告变更
DetectChanges --> HandleNormalChange : 其他信息变更
HandleNameChange --> UpdateMongoDB : 更新群名称
HandleAnnouncementChange --> UpdateMongoDB : 更新公告信息
HandleNormalChange --> UpdateMongoDB : 更新基础信息
UpdateMongoDB --> ClearRedisCache : MongoDB更新成功
ClearRedisCache --> UpdateVersion : 清理群组信息缓存
UpdateVersion --> SendNotification : 版本控制更新
SendNotification --> [*] : 通知发送完成
UpdateMongoDB --> [*] : 数据库更新失败
具体操作细节:
MongoDB更新操作:
// 根据不同字段执行不同的更新操作
db.groups.updateOne(
{ "group_id": "groupID" },
{
$set: {
// 群名称变更
"group_name": "新群名称",
// 群公告变更(特殊处理)
"notification": "新公告内容",
"notification_update_time": new Date(),
"notification_user_id": "operatorUserID",
// 其他基础信息
"introduction": "新群介绍",
"face_url": "http://new-avatar.url",
"need_verification": 1,
"look_member_info": 0,
"apply_member_friend": 1
}
}
)
Redis缓存操作:
GROUP_INFO:{groupID}- DELETE (群组基础信息缓存失效)
通知分发逻辑:
| 变更字段 | 通知类型 | 通知对象 | 特殊处理 |
|---|---|---|---|
| group_name | GroupInfoSetNameNotification | 群组所有成员 | 会话标题更新 |
| notification | GroupInfoSetAnnouncementNotification | 群组所有成员 | 公告弹窗提醒 |
| 其他字段 | GroupInfoSetNotification | 群组所有成员 | 基础信息同步 |
👑 5. TransferGroupOwner - 转让群主详细流程
sequenceDiagram
participant Owner as 当前群主
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
Owner->>API: TransferGroupOwnerReq
Note over API: 1. 身份验证阶段
API->>Redis: HGET GROUP_MEMBER_INFO:{groupID}:{currentOwnerID}
Redis-->>API: role_level=100 (群主身份确认)
API->>Redis: HGET GROUP_MEMBER_INFO:{groupID}:{newOwnerID}
Redis-->>API: 新群主成员信息
Note over API: 2. 数据库事务操作
API->>MongoDB: 开启事务
API->>MongoDB: UPDATE group_members SET role_level=20 WHERE group_id=? AND user_id=?
Note over MongoDB: 原群主降级为普通成员<br/>role_level: 100 → 20
API->>MongoDB: UPDATE group_members SET role_level=100 WHERE group_id=? AND user_id=?
Note over MongoDB: 新群主升级<br/>role_level: 20/60 → 100
API->>MongoDB: 提交事务
Note over API: 3. 大量缓存清理
API->>Redis: DEL GROUP_OWNER:{groupID}
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{currentOwnerID}
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{newOwnerID}
API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:100
API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:20
API->>Redis: DEL GROUP_ROLE_LEVEL_MEMBERS:{groupID}:60
Note over API: 4. 版本控制更新
API->>API: setVersion(group_members, groupID)
Note over API: 5. 通知发送
API->>Notify: GroupOwnerTransferredNotification
Note over Notify: 通知对象:<br/>1. 原群主:角色变更通知<br/>2. 新群主:群主权限获得<br/>3. 群内成员:群主变更通知
API-->>Owner: TransferGroupOwnerResp{Success}
关键操作分析:
MongoDB事务操作:
// 事务保证原子性操作
session.withTransaction(() => {
// 降低原群主权限
db.group_members.updateOne(
{ "group_id": groupID, "user_id": currentOwnerID },
{
$set: {
"role_level": 20,
"operator_user_id": currentOwnerID
}
}
);
// 提升新群主权限
db.group_members.updateOne(
{ "group_id": groupID, "user_id": newOwnerID },
{
$set: {
"role_level": 100,
"operator_user_id": currentOwnerID
}
}
);
});
角色相关缓存清理:
GROUP_OWNER:{groupID}- DELETE (群主信息)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:100- DELETE (群主角色成员列表)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:20- DELETE (普通成员角色列表)GROUP_ROLE_LEVEL_MEMBERS:{groupID}:60- DELETE (管理员角色列表)
🔕 6. MuteGroupMember - 禁言群成员详细流程
flowchart TD
A[MuteGroupMemberReq] --> B[权限验证]
B --> C{CheckGroupAdmin结果}
C -->|权限不足| D[返回权限错误]
C -->|权限通过| E[获取被禁言者信息]
E --> F[Redis查询]
F --> G["HGET GROUP_MEMBER_INFO:{groupID}:{mutedUserID}"]
G --> H[验证角色权限]
H --> I{被禁言者角色检查}
I -->|群主| J[禁止操作返回错误]
I -->|管理员且操作者非群主| J
I -->|可以禁言| K[计算禁言时间]
K --> L["muteEndTime = now() + mutedSeconds"]
L --> M[MongoDB更新操作]
M --> N["UPDATE group_members SET mute_end_time=? WHERE group_id=? AND user_id=?"]
N --> O[Redis缓存更新]
O --> P["DEL GROUP_MEMBER_INFO:{groupID}:{mutedUserID}"]
P --> Q[版本控制更新]
Q --> R[setVersion group_members]
R --> S[发送禁言通知]
S --> T[GroupMemberMutedNotification]
T --> U[返回成功响应]
禁言权限验证矩阵:
| 操作者角色 | 被禁言者角色 | 操作结果 | 说明 |
|---|---|---|---|
| 群主 | 任何角色 | ✅ 允许 | 群主拥有最高权限 |
| 管理员 | 普通成员 | ✅ 允许 | 管理员可以禁言普通成员 |
| 管理员 | 管理员 | ❌ 禁止 | 管理员间平级,不能相互操作 |
| 管理员 | 群主 | ❌ 禁止 | 管理员不能操作群主 |
| 普通成员 | 任何角色 | ❌ 禁止 | 普通成员无禁言权限 |
MongoDB更新字段:
{
"mute_end_time": new Date(Date.now() + mutedSeconds * 1000),
"operator_user_id": operatorUserID
}
Redis缓存影响:
GROUP_MEMBER_INFO:{groupID}:{mutedUserID}- DELETE (成员信息缓存)
📋 7. GetGroupMemberList - 获取群成员列表详细流程
sequenceDiagram
participant Client as 客户端
participant API as Group RPC
participant LocalCache as 本地缓存
participant Redis as Redis缓存
participant MongoDB as MongoDB
Client->>API: GetGroupMemberListReq{groupID, pagination}
Note over API: 1. 权限验证
API->>API: checkAdminOrInGroup(验证成员身份)
Note over API: 2. 本地缓存查询
API->>LocalCache: 查询成员列表缓存
LocalCache-->>API: 缓存未命中
Note over API: 3. Redis缓存查询
API->>Redis: LRANGE GROUP_MEMBER_IDS:{groupID} offset limit
alt Redis缓存命中
Redis-->>API: 返回成员ID列表
Note over API: 4. 批量查询成员详情
loop 每个成员ID
API->>Redis: HGETALL GROUP_MEMBER_INFO:{groupID}:{userID}
end
Redis-->>API: 成员详细信息
Note over API: 5. 缓存回写
API->>LocalCache: 更新本地缓存
else Redis缓存未命中
Note over API: 6. 数据库查询
API->>MongoDB: db.group_members.find({group_id}).sort({role_level: -1, join_time: 1}).skip().limit()
MongoDB-->>API: 完整成员信息
Note over API: 7. 缓存预热
API->>Redis: LPUSH GROUP_MEMBER_IDS:{groupID} memberIDs...
loop 每个成员
API->>Redis: HSET GROUP_MEMBER_INFO:{groupID}:{userID} memberInfo
end
API->>LocalCache: 更新本地缓存
end
Note over API: 8. 数据转换
API->>API: groupMemberDB2PB(格式转换)
API-->>Client: GetGroupMemberListResp{members, pagination}
缓存策略分析:
三级缓存架构:
- 本地缓存:进程内缓存,最快访问速度
- Redis缓存:分布式缓存,支持集群共享
- MongoDB:持久化存储,数据源头
Redis Key使用:
GROUP_MEMBER_IDS:{groupID}- List类型,存储成员ID列表GROUP_MEMBER_INFO:{groupID}:{userID}- Hash类型,存储成员详细信息
分页查询优化:
// MongoDB聚合查询,支持高效分页
db.group_members.aggregate([
{ $match: { "group_id": groupID } },
{ $sort: {
"role_level": -1, // 按角色等级倒序(群主>管理员>普通成员)
"join_time": 1 // 同等级按加入时间正序
}},
{ $skip: offset },
{ $limit: pageSize }
]);
📝 8. GroupApplicationResponse - 处理群组申请详细流程
stateDiagram-v2
[*] --> ReceiveRequest : GroupApplicationResponseReq
ReceiveRequest --> ValidateHandler : 接收处理请求
ValidateHandler --> GetApplication : 验证处理者权限
GetApplication --> CheckStatus : 获取申请详情
CheckStatus --> ProcessApproval : handle_result=1(同意)
CheckStatus --> ProcessRejection : handle_result=-1(拒绝)
CheckStatus --> [*] : 申请已处理返回错误
ProcessApproval --> CheckMemberExists : 同意申请
CheckMemberExists --> CreateMember : 用户未在群组
CheckMemberExists --> UpdateApplicationOnly : 用户已在群组
CreateMember --> MongoTransaction : 创建成员记录
MongoTransaction --> UpdateApplication : 更新申请状态
UpdateApplication --> ClearCache : 清理相关缓存
ClearCache --> SendApprovalNotify : 发送同意通知
SendApprovalNotify --> [*] : 完成处理
UpdateApplicationOnly --> SendApprovalNotify : 仅更新申请状态
ProcessRejection --> UpdateRejection : 拒绝申请
UpdateRejection --> SendRejectionNotify : 发送拒绝通知
SendRejectionNotify --> [*] : 完成处理
ValidateHandler --> [*] : 权限验证失败
详细数据操作:
同意申请的事务操作:
// MongoDB事务确保数据一致性
session.withTransaction(() => {
// 1. 更新申请状态
db.group_requests.updateOne(
{
"group_id": groupID,
"user_id": applicantUserID,
"handle_result": 0 // 仅处理待处理的申请
},
{
$set: {
"handle_result": 1, // 1=同意
"handled_msg": "欢迎加入群组",
"handle_user_id": handlerUserID,
"handled_time": new Date()
}
}
);
// 2. 创建群成员记录(如果用户不在群中)
db.group_members.insertOne({
"group_id": groupID,
"user_id": applicantUserID,
"role_level": 20, // 普通成员
"join_source": 3, // 通过申请加入
"join_time": new Date(),
"operator_user_id": handlerUserID,
"mute_end_time": new Date(0)
});
});
拒绝申请操作:
// 仅更新申请状态,不创建成员记录
db.group_requests.updateOne(
{ "group_id": groupID, "user_id": applicantUserID },
{
$set: {
"handle_result": -1, // -1=拒绝
"handled_msg": "申请被拒绝",
"handle_user_id": handlerUserID,
"handled_time": new Date()
}
}
);
缓存清理操作:
GROUP_MEMBER_IDS:{groupID}- DELETE (成员列表)GROUP_MEMBER_NUM_CACHE:{groupID}- DELETE (成员数量)JOIN_GROUPS:{applicantUserID}- DELETE (申请者加群列表)GROUP_PENDING_REQUESTS:{groupID}- DELETE (待处理申请列表)
通知发送逻辑:
| 处理结果 | 通知类型 | 通知对象 | 通知内容 |
|---|---|---|---|
| 同意 | GroupApplicationAcceptedNotification | 申请者 | "您的入群申请已通过" |
| 同意 | MemberEnterNotification | 群组成员 | "XXX加入了群组" |
| 拒绝 | GroupApplicationRejectedNotification | 申请者 | "您的入群申请被拒绝" |
🏠 9. QuitGroup - 退出群组详细流程
sequenceDiagram
participant Client as 客户端
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
participant Conv as 会话服务
Client->>API: QuitGroupReq
Note over API: 1. 验证用户身份
API->>MongoDB: TakeGroupMember(获取成员信息)
MongoDB-->>API: 成员角色信息
Note over API: 2. 成员身份检查
alt 非群成员
API-->>Client: 返回非成员错误
else 是群成员
Note over API: 3. 角色判断
alt 群主退群(role_level=100)
API->>MongoDB: FindGroupMemberNum(查询成员数量)
MongoDB-->>API: 群成员总数
alt 仅群主1人
Note over API: 自动解散群组
API->>API: 调用DismissGroup
API-->>Client: 群组解散完成
else 还有其他成员
API-->>Client: 返回错误:需先转让群主
end
else 普通成员退群
Note over API: 4. 执行退群流程
API->>MongoDB: 开启事务
API->>MongoDB: DELETE FROM group_members
Note over MongoDB: 删除成员记录
Note over API: 5. Redis缓存清理
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{userID}
API->>Redis: DEL JOIN_GROUPS:{userID}
API->>Redis: DEL GROUP_MEMBER_IDS:{groupID}
API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID}
Note over API: 6. 会话管理
API->>Conv: SetConversationMaxSeq(更新会话序号)
Note over API: 7. 版本控制更新
API->>API: setVersion(group_members)
Note over API: 8. 发送退群通知
API->>Notify: MemberQuitNotification
Note over Notify: 通知群内其他成员:<br/>XXX退出了群组
API-->>Client: 退群成功
end
end
群主退群特殊逻辑:
// 群主退群权限检查
func (g *groupServer) QuitGroup(ctx context.Context, req *pbgroup.QuitGroupReq) (*pbgroup.QuitGroupResp, error) {
// 1. 获取操作者在群中的信息
member, err := g.db.TakeGroupMember(ctx, req.GroupID, req.UserID)
if err != nil {
return nil, err
}
// 2. 群主退群特殊处理
if member.RoleLevel == constant.GroupOwner {
// 查询群成员总数
memberCount, err := g.db.FindGroupMemberNum(ctx, req.GroupID)
if err != nil {
return nil, err
}
if memberCount == 1 {
// 仅群主一人,解散群组
return g.DismissGroup(ctx, &pbgroup.DismissGroupReq{
GroupID: req.GroupID,
UserID: req.UserID,
})
} else {
// 还有其他成员,需要先转让群主
return nil, errs.ErrArgs.WrapMsg("群主需要先转让群主权限才能退群")
}
}
// 3. 普通成员直接退出
return g.quitGroupDirectly(ctx, req)
}
数据一致性保证:
- MongoDB删除操作:确保成员记录彻底删除
- Redis缓存清理:避免脏数据,保证缓存一致性
- 会话序号更新:确保消息同步的准确性
- 版本控制更新:支持增量同步机制
💀 10. DismissGroup - 解散群组详细流程
sequenceDiagram
participant Owner as 群主
participant API as Group RPC
participant Redis as Redis缓存
participant MongoDB as MongoDB
participant Notify as 通知服务
participant Conv as 会话服务
Owner->>API: DismissGroupReq
Note over API: 1. 权限验证
API->>API: CheckGroupAdmin(仅群主或系统管理员)
Note over API: 2. 获取群组信息
API->>MongoDB: 查询groups集合
MongoDB-->>API: 群组基础信息
API->>MongoDB: 查询group_members集合
MongoDB-->>API: 所有群成员列表
Note over API: 3. 数据库批量删除
API->>MongoDB: 开启事务
API->>MongoDB: DELETE FROM group_members WHERE group_id=?
Note over MongoDB: 删除所有群成员记录
API->>MongoDB: DELETE FROM groups WHERE group_id=?
Note over MongoDB: 删除群组记录
API->>MongoDB: DELETE FROM group_requests WHERE group_id=?
Note over MongoDB: 删除所有相关申请记录
API->>MongoDB: 提交事务
Note over API: 4. 大量缓存清理
API->>Redis: DEL GROUP_INFO:{groupID}
API->>Redis: DEL GROUP_MEMBER_IDS:{groupID}
API->>Redis: DEL GROUP_MEMBER_NUM_CACHE:{groupID}
API->>Redis: DEL GROUP_OWNER:{groupID}
API->>Redis: DEL GROUP_MEMBERS_HASH:{groupID}
loop 每个群成员
API->>Redis: DEL GROUP_MEMBER_INFO:{groupID}:{userID}
API->>Redis: DEL JOIN_GROUPS:{userID}
end
Note over API: 5. 会话清理
loop 每个群成员
API->>Conv: SetConversationMaxSeq(清理群组会话)
end
Note over API: 6. 版本控制
API->>API: setVersion(groups, groupID)
API->>API: setVersion(group_members, groupID)
Note over API: 7. 解散通知
API->>Notify: GroupDismissedNotification
Note over Notify: 通知对象:所有群成员<br/>通知内容:群组已解散<br/>触发客户端会话删除
API-->>Owner: DismissGroupResp{Success}
解散群组的数据清理范围:
MongoDB删除操作:
// 事务保证数据一致性
session.withTransaction(() => {
// 1. 删除所有群成员
db.group_members.deleteMany({ "group_id": groupID });
// 2. 删除群组记录
db.groups.deleteOne({ "group_id": groupID });
// 3. 删除相关申请记录
db.group_requests.deleteMany({ "group_id": groupID });
});
Redis缓存清理列表:
GROUP_INFO:{groupID}- DELETEGROUP_MEMBER_IDS:{groupID}- DELETEGROUP_MEMBER_NUM_CACHE:{groupID}- DELETEGROUP_OWNER:{groupID}- DELETEGROUP_MEMBERS_HASH:{groupID}- DELETEGROUP_MEMBER_INFO:{groupID}:{userID}- DELETE (每个成员)JOIN_GROUPS:{userID}- DELETE (每个成员)GROUP_PENDING_REQUESTS:{groupID}- DELETEGROUP_REQUEST_COUNT:{groupID}- DELETE
通知影响分析:
- GroupDismissedNotification:通知所有群成员群组已解散
- 会话清理:触发客户端删除群组会话
- 数据同步:版本控制确保所有设备同步解散状态
以上详细解析了OpenIM群聊管理的核心功能模块和完整的权限控制体系。每个功能都包含完整的权限验证、数据存储、缓存管理和通知机制,确保群组管理的安全性、一致性和用户体验。完善的权限矩阵为系统提供了精细化的访问控制,满足不同场景下的安全需求。