docs: 补充 Phase 2b 设计文档和实施计划
- 设计文档新增 Mermaid 消息收发时序图 - IMService 依赖注入补充 *redis.Client(未读数 HASH 操作) - 实施计划同步更新 Redis 依赖和 unreadKeyPrefix Made-with: Cursor
This commit is contained in:
@@ -127,7 +127,33 @@ IM Service.RecallMessage()
|
|||||||
└── PubSub.PublishToUser(receiverID, im.message.recalled)
|
└── PubSub.PublishToUser(receiverID, im.message.recalled)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.5 跨模块依赖(接口注入模式)
|
### 3.5 消息收发时序图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Sender as 发送方Client
|
||||||
|
participant WS as WebSocketHandler
|
||||||
|
participant IM as IMService
|
||||||
|
participant DB as PostgreSQL
|
||||||
|
participant Redis as Redis
|
||||||
|
participant PubSub as PubSub
|
||||||
|
participant Receiver as 接收方Client
|
||||||
|
|
||||||
|
Sender->>WS: im.message.send {target_user_id, content, client_msg_id}
|
||||||
|
WS->>IM: SendMessage(senderID, targetUserID, content)
|
||||||
|
IM->>IM: FriendChecker.IsFriend()
|
||||||
|
IM->>IM: FindOrCreateConversation()
|
||||||
|
IM->>DB: INSERT im_messages
|
||||||
|
IM->>DB: UPDATE im_conversations
|
||||||
|
IM->>DB: UPDATE im_conversation_members (unread+1)
|
||||||
|
IM->>Redis: HINCRBY echo:im:unread:{receiverID} convID 1
|
||||||
|
IM-->>WS: messageID + conversationID
|
||||||
|
WS-->>Sender: im.message.send.ack {message_id, conversation_id}
|
||||||
|
IM->>PubSub: PublishToUser(receiverID, im.message.new)
|
||||||
|
PubSub-->>Receiver: im.message.new {消息详情}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.6 跨模块依赖(接口注入模式)
|
||||||
|
|
||||||
沿用 Phase 2a 的接口注入标准,避免 `im` 包直接 import `contact` 包:
|
沿用 Phase 2a 的接口注入标准,避免 `im` 包直接 import `contact` 包:
|
||||||
|
|
||||||
@@ -317,12 +343,15 @@ type IMService struct {
|
|||||||
conversationDAO *dao.ConversationDAO
|
conversationDAO *dao.ConversationDAO
|
||||||
messageDAO *dao.MessageDAO
|
messageDAO *dao.MessageDAO
|
||||||
pubsub *ws.PubSub // 复用 Phase 2a
|
pubsub *ws.PubSub // 复用 Phase 2a
|
||||||
|
rdb *redis.Client // Redis 操作(未读数 HASH)
|
||||||
friendChecker FriendChecker // 接口注入 → FriendshipDAO.IsFriend
|
friendChecker FriendChecker // 接口注入 → FriendshipDAO.IsFriend
|
||||||
userInfoGetter UserInfoGetter // 接口注入 → FriendshipDAO.GetUsersByIDs
|
userInfoGetter UserInfoGetter // 接口注入 → FriendshipDAO.GetUsersByIDs
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Wire 注入链:`contact.FriendshipDAO` → 隐式实现 `FriendChecker` + `UserInfoGetter`。
|
Wire 注入链:
|
||||||
|
- `contact.FriendshipDAO` → 隐式实现 `FriendChecker` + `UserInfoGetter`
|
||||||
|
- `*redis.Client` → 直接注入(已在 InfraSet 中提供)
|
||||||
|
|
||||||
### 7.3 IMService 核心方法
|
### 7.3 IMService 核心方法
|
||||||
|
|
||||||
|
|||||||
@@ -302,13 +302,18 @@ type FriendChecker interface {
|
|||||||
type UserInfoGetter interface {
|
type UserInfoGetter interface {
|
||||||
GetUsersByIDs(ctx context.Context, userIDs []int64) ([]authModel.User, error)
|
GetUsersByIDs(ctx context.Context, userIDs []int64) ([]authModel.User, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redis Key 前缀(未读数 HASH)
|
||||||
|
const unreadKeyPrefix = "echo:im:unread:"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 2: 创建 IMService**
|
**Step 2: 创建 IMService**
|
||||||
|
|
||||||
Create: `backend/go-service/app/im/service/im_service.go`
|
Create: `backend/go-service/app/im/service/im_service.go`
|
||||||
|
|
||||||
IMService 注入:`ConversationDAO`、`MessageDAO`、`*ws.PubSub`、`FriendChecker`、`UserInfoGetter`
|
IMService 注入:`ConversationDAO`、`MessageDAO`、`*ws.PubSub`、`*redis.Client`、`FriendChecker`、`UserInfoGetter`
|
||||||
|
|
||||||
|
注意:`*redis.Client` 用于操作未读数 Redis HASH(`echo:im:unread:{user_id}`)
|
||||||
|
|
||||||
核心方法(参考设计文档第七节):
|
核心方法(参考设计文档第七节):
|
||||||
- `SendMessage(ctx, senderID, targetUserID, content, msgType, clientMsgID)` — 核心链路:校验好友 → 查找/创建会话 → 写消息 → 更新 last_message → 增加未读 → 推送
|
- `SendMessage(ctx, senderID, targetUserID, content, msgType, clientMsgID)` — 核心链路:校验好友 → 查找/创建会话 → 写消息 → 更新 last_message → 增加未读 → 推送
|
||||||
|
|||||||
Reference in New Issue
Block a user