# SocketIO 模块架构设计分析

## 当前设计问题

### ❌ 问题 1：能力层依赖业务层逻辑
```kotlin
// capability-socketio 通过回调注入业务层的刷新逻辑
SocketIOManager.refreshTokenProvider = { AuthManager.refreshTokenIfNeeded() }
```

**问题：**
- `capability-socketio` 是能力层，不应该依赖 `app/auth` 的业务逻辑
- 回调注入的方式虽然避免了编译时依赖，但逻辑上仍然是依赖关系
- 违反了"能力层只依赖基础设施，不依赖业务逻辑"的原则

### ❌ 问题 2：职责混乱
- SocketIO 模块既要负责连接，又要负责 Token 刷新
- Token 刷新是业务逻辑，应该在业务层处理

---

## 市面上常规设计

### ✅ 方案 1：能力层只读取 Token，不刷新（推荐）

**原则：**
- 能力层（capability）只负责技术能力（SocketIO 连接、消息收发）
- 业务层（app/auth）负责业务逻辑（Token 刷新、登录状态管理）

**实现：**
```kotlin
// capability-socketio：直接从存储读取 Token（基础设施）
class SocketIORepository {
    private fun getToken(): String? {
        return StorageImpl.getString("access_token").takeIf { it.isNotEmpty() }
    }
    
    suspend fun connect(): Result<Unit> {
        val token = getToken()
        if (token.isNullOrEmpty()) {
            return Result.failure(Exception("未登录"))
        }
        // 直接使用 Token 连接，不负责刷新
        return socketService.connect(token)
    }
}
```

**Token 刷新处理：**
- HTTP 请求：由 `TokenRefreshInterceptor` 统一处理（已实现）
- SocketIO 连接：如果连接失败（Token 过期），通过回调通知上层，由上层处理

### ✅ 方案 2：接口抽象（如果必须刷新）

**如果 SocketIO 必须在连接前刷新 Token：**

```kotlin
// base-core：定义接口（基础设施）
interface ITokenProvider {
    suspend fun getToken(): String?
    suspend fun refreshTokenIfNeeded(): String?
}

// app/auth：实现接口
object AuthManager : ITokenProvider {
    override suspend fun getToken(): String? = TokenStore.getAccessToken()
    override suspend fun refreshTokenIfNeeded(): String? { /* ... */ }
}

// capability-socketio：使用接口（不依赖具体实现）
class SocketIORepository(
    private val tokenProvider: ITokenProvider? = null  // 通过 DI 注入
) {
    suspend fun connect() {
        val token = tokenProvider?.refreshTokenIfNeeded() 
            ?: StorageImpl.getString("access_token")
        // ...
    }
}
```

**优点：**
- 能力层只依赖接口（base-core），不依赖业务层
- 符合依赖倒置原则

**缺点：**
- 增加了接口抽象层，复杂度提升
- SocketIO 通常不需要主动刷新 Token（连接失败时再处理即可）

---

## 推荐方案：简化设计

### 核心原则
1. **能力层只读取 Token，不刷新**
2. **刷新统一由 Network 拦截器处理**
3. **SocketIO 连接失败时，由上层处理重连**

### 具体实现

#### 1. capability-socketio：简化，移除刷新逻辑
```kotlin
class SocketIORepository {
    // 直接从存储读取 Token（基础设施，可以依赖）
    private fun getToken(): String? {
        return StorageImpl.getString("access_token").takeIf { it.isNotEmpty() }
    }
    
    suspend fun connect(): Result<Unit> {
        val token = getToken()
        if (token.isNullOrEmpty()) {
            return Result.failure(Exception("未登录（Token 为空）"))
        }
        // 直接连接，不负责刷新
        return socketService.connect(token)
    }
    
    // 连接失败回调（通知上层处理）
    var onConnectionFailed: ((Exception) -> Unit)? = null
}
```

#### 2. app 层：处理连接失败和刷新
```kotlin
// UserViewModel 或专门的 SocketIO 管理类
class SocketIOConnectionManager {
    suspend fun connectWithRetry() {
        var retryCount = 0
        while (retryCount < 3) {
            when (val result = SocketIOManager.connect()) {
                is Result.Success -> return
                is Result.Failure -> {
                    val error = result.exception
                    if (error.message?.contains("401") == true || 
                        error.message?.contains("Token") == true) {
                        // Token 可能过期，刷新后重试
                        val newToken = AuthManager.refreshTokenIfNeeded()
                        if (newToken != null) {
                            retryCount++
                            continue
                        }
                    }
                    // 其他错误，直接失败
                    break
                }
            }
        }
    }
}
```

#### 3. Network 层：统一处理 HTTP 请求的 Token 刷新
```kotlin
// TokenRefreshInterceptor 已实现，统一处理 HTTP 请求的 401/402
// SocketIO 不需要单独处理
```

---

## 对比总结

| 维度 | 当前设计 | 推荐设计 |
|------|---------|---------|
| **能力层职责** | 连接 + Token 刷新 | 只负责连接 |
| **依赖关系** | 通过回调依赖业务层 | 只依赖基础设施（StorageImpl） |
| **刷新逻辑** | SocketIO 自己刷新 | 统一由 Network 拦截器处理 |
| **连接失败处理** | SocketIO 内部处理 | 上层（app）处理 |
| **复杂度** | 高（能力层包含业务逻辑） | 低（职责清晰） |
| **可测试性** | 低（依赖业务层） | 高（只依赖接口） |

---

## 结论

**当前设计的问题：**
- 能力层不应该包含业务逻辑（Token 刷新）
- 通过回调注入业务逻辑，虽然避免了编译时依赖，但逻辑上仍然是依赖关系

**推荐方案：**
- 能力层只读取 Token，不刷新
- Token 刷新统一由 Network 拦截器处理（HTTP 请求）
- SocketIO 连接失败时，由上层（app）处理刷新和重连
- 这样职责清晰，符合分层架构原则


