自建好友 / 群业务接入 Server Core
本文说明:如果你要自己实现好友、群、组织、黑名单、禁言等业务系统,应该如何与 flare-im-core 服务端集成。
结论
flare-im-core 不负责好友关系和群目录的业务规则。它负责 IM 主干:长连接、消息、会话、成员投影、seq、有序同步和事件。
自建业务系统推荐通过一个 Business Bridge 接入 IM Core:
App / Client SDK
│
├── 好友、群资料、申请、角色、组织关系 ──► 你的业务 API
│
└── 消息、会话、同步、已读 ───────────────► flare-im-core SDK
你的业务服务 ──► Business Bridge ──► flare-im-core 管理 / 命令面
│
├── PreSend Hook:发消息前做好友/群权限校验
├── PostSend Hook:发信事实回流业务系统
└── Conversation/Member Hook:同步会话与成员变化
责任边界
| 模块 | 负责什么 | 不负责什么 |
|---|---|---|
| 你的业务系统 | 用户资料、好友关系、群目录、入群申请、角色、禁言、黑名单、组织权限 | 消息 seq、长连接投递、客户端离线同步 |
| Business Bridge | 把业务关系映射成 IM 会话和成员投影;实现 Hook;做幂等和重试 | 不持有 IM 消息事实,不绕过 Core 分配 seq |
flare-im-core | 会话、消息、成员投影、已读、同步、事件、能力扩展 | 不判断“是不是好友”“是不是群主”等业务规则 |
| Client SDK | 登录、收发消息、会话列表、消息同步、事件监听 | 不保存业务权威关系;好友/群资料从你的业务 API 拉取 |
接入点 1:登录与租户身份
客户端登录 IM 时携带业务系统签发的 Token。Token 至少应能解析出:
| Claim | 说明 |
|---|---|
tenant_id | 租户隔离。多租户场景必须显式传递 |
user_id | 当前业务用户 ID,也是 IM 中的 actor |
device_id | 可选,用于多端策略和审计 |
expires_at | 过期时间 |
客户端侧只需要把 Token 交给 SDK:
await client.login({
userId: currentUser.id,
token: accessToken,
})
生产环境中,Token 由你的账号系统签发;IM 网关只验证身份和租户,不把好友/群权限写死在 Token 里。
接入点 2:发消息前校验
好友、群成员、禁言、黑名单等会影响“能不能发消息”的规则,应接 PreSend Hook。
Hook operation:
flare.hook.v1.pre_send
推荐校验:
| 场景 | 校验 |
|---|---|
| 单聊 | 发送者与接收者是否是好友;是否被拉黑;是否允许陌生人消息 |
| 群聊 | 发送者是否是群成员;群是否解散/冻结;用户是否被禁言 |
| 组织会话 | 发送者是否有组织/项目空间权限 |
| 风控 | 内容安全、频控、审计等级 |
返回策略:
allow = true -> Core 继续分配 seq 并进入消息主链
allow = false -> 业务拒绝,返回稳定 deny_reason_code
Hook 超时 -> 权限类建议 fail-fast;纯审计类不要放在 PreSend
注意:PreSend Hook 不应写消息表、不应分配 seq,也不应执行长耗时外部调用。
接入点 3:会话与成员映射
好友或群创建成功后,你的业务服务需要把业务关系映射到 IM 会话。
推荐由 Business Bridge 暴露自己的业务接口,例如:
POST /im-bridge/conversations/ensure
请求示例:
{
"tenantId": "0",
"businessType": "group",
"businessId": "group_123",
"conversationType": "group",
"operatorUserId": "u_001",
"participantUserIds": ["u_001", "u_002", "u_003"],
"idempotencyKey": "group_123:init"
}
Bridge 内部再调用 flare-im-core 的管理面或命令面完成:
- 确保会话存在:
businessType + businessId -> conversation_id - 同步参与者投影:成员列表、角色、禁言状态、
participant_version - 发布或触发会话成员变更事件
- 将
conversation_id回写到你的业务库映射表
映射表建议:
| 字段 | 说明 |
|---|---|
tenant_id | 租户 |
business_type | friend / group / org_space 等 |
business_id | 你的业务对象 ID |
conversation_id | IM 会话 ID |
participant_version | 成员投影版本 |
updated_at | 最后同步时间 |
接入点 4:客户端读模型
客户端页面不要只靠 IM 会话列表展示好友/群完整资料。
推荐组合:
| 数据 | 来源 |
|---|---|
| 会话列表、最后一条消息、未读、已读 | flare-im-core SDK |
| 好友昵称、头像、备注、群公告、群角色 | 你的业务 API |
| 群成员完整资料 | 你的业务 API |
| 消息内容、seq、同步游标 | flare-im-core SDK |
客户端拿到会话里的 conversation_id 或业务映射字段后,再向你的业务 API 查询展示资料。这样 IM Core 保持业务中立,业务系统保持资料权威。
常见流程
单聊发消息
- App 从你的好友服务选择好友。
- 业务服务或 Bridge 确保单聊会话存在。
- Client SDK 使用
conversation_id发消息。 PreSend Hook校验好友关系和黑名单。- Core 分配 seq、落库、下发并支持离线同步。
PostSend Hook将发信事实回流给审计、风控或业务统计。
创建群并发消息
- 你的群服务创建群,写入群成员和角色。
- 群服务调用 Business Bridge
ensure conversation。 - Bridge 同步 IM 会话参与者投影。
- Client SDK 拉取会话或收到会话变更事件。
- 用户发消息时,
PreSend Hook校验群成员、禁言和群状态。
幂等与失败策略
| 环节 | 建议 |
|---|---|
| Bridge 命令 | 必须带 idempotencyKey,重复调用返回同一个 conversation_id |
| 业务到 IM 同步 | 使用 outbox 或重试队列,避免业务事务提交后 IM 映射丢失 |
| Hook | 权限类短超时 fail-fast;审计类放到 post_send 或旁路事件 |
| 成员同步 | 用 participant_version 做增量和覆盖保护 |
| 客户端 | IM 会话可先出现,业务资料稍后补齐;UI 要允许资料加载中状态 |
不要这样做
- 不要把好友、群、组织规则写进
flare-im-core。 - 不要用
metadata承载稳定业务语义,例如“群主”“好友状态”。这些应在你的业务系统或明确类型字段中维护。 - 不要让客户端直接相信本地群成员缓存来决定能不能发消息;最终门禁在服务端 Hook。
- 不要绕过 Core 直接写消息表或手工分配 seq。
- 不要把群目录塞进 IM 同步 payload;群资料应由业务 API 或独立业务 SDK 管理。
最小落地清单
- 业务账号系统签发 IM 登录 Token。
- 建一个 Business Bridge,维护
business_id -> conversation_id映射。 - 实现
flare.hook.v1.pre_send,校验好友/群权限。 - 群/好友变化时,通过 Bridge 同步会话参与者投影。
- 客户端用 IM SDK 收发消息,用业务 API 拉好友/群资料。
- 用
post_send/ 会话成员事件做审计、统计和业务 read model 回流。