docs(deploy): 添加部署文档并更新SDK API设计规范
- 新增完整的XuqmGroup部署文档,包含服务器配置、Docker Compose部署策略 - 更新SDK API重设计规范至V2.0,统一各端SDK初始化和登录接口 - 添加安全设计规范文档,涵盖密码安全、AppSecret验证等内容 - 新增离线推送架构设计文档,定义厂商推送集成方案 - 重构SDK登录流程,统一使用userId + userSig鉴权模式 - 移除dbName等外部配置参数,实现零感知平台地址配置 - 完善部署架构图和配置示例文件
这个提交包含在:
父节点
8cf9699441
当前提交
255974ae09
@ -34,7 +34,7 @@ public final class XuqmSDK: NSObject {
|
||||
self.userSig = userSig
|
||||
|
||||
do {
|
||||
try await ImSDK.shared.loginWithUserSig(userId, userSig)
|
||||
try await ImSDK.shared.login(userId, userSig)
|
||||
} catch {
|
||||
// IM login failed; silently ignored per facade pattern
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public final class ImSDK {
|
||||
}
|
||||
}
|
||||
|
||||
public func loginWithUserSig(_ userId: String, _ userSig: String) async throws {
|
||||
public func login(_ userId: String, _ userSig: String) async throws {
|
||||
let config = XuqmSDK.shared.requireConfig()
|
||||
currentUserId = userId
|
||||
XuqmSDK.shared.tokenStore?.save(userSig)
|
||||
@ -36,57 +36,6 @@ public final class ImSDK {
|
||||
client?.connect()
|
||||
}
|
||||
|
||||
public func login(userId: String) async throws {
|
||||
let config = XuqmSDK.shared.requireConfig()
|
||||
|
||||
let items = [
|
||||
URLQueryItem(name: "appId", value: config.appId),
|
||||
URLQueryItem(name: "userId", value: userId),
|
||||
]
|
||||
|
||||
let res: ImLoginResponse = try await ApiClient.shared.request(
|
||||
path: "/api/im/auth/login",
|
||||
method: "POST",
|
||||
queryItems: items
|
||||
)
|
||||
currentUserId = userId
|
||||
XuqmSDK.shared.tokenStore?.save(res.token)
|
||||
client?.disconnect()
|
||||
client = ImClient(token: res.token, appId: config.appId)
|
||||
client?.setCurrentUserId(userId)
|
||||
client?.delegate = self
|
||||
updateConnectionState(.connecting)
|
||||
client?.connect()
|
||||
}
|
||||
|
||||
public func loginWithDemo(userId: String, password: String = "123456") async throws {
|
||||
let config = XuqmSDK.shared.requireConfig()
|
||||
struct DemoLoginResponse: Decodable, Sendable {
|
||||
let profile: DemoProfile
|
||||
let imToken: String
|
||||
struct DemoProfile: Decodable, Sendable {
|
||||
let appId: String
|
||||
let userId: String
|
||||
let nickname: String?
|
||||
let avatar: String?
|
||||
}
|
||||
}
|
||||
let res: DemoLoginResponse = try await ApiClient.shared.request(
|
||||
path: "/api/demo/auth/login",
|
||||
method: "POST",
|
||||
queryItems: [URLQueryItem(name: "appId", value: config.appId)],
|
||||
body: ["appId": config.appId, "userId": userId, "password": password]
|
||||
)
|
||||
currentUserId = res.profile.userId
|
||||
XuqmSDK.shared.tokenStore?.save(res.imToken)
|
||||
client?.disconnect()
|
||||
client = ImClient(token: res.imToken, appId: config.appId)
|
||||
client?.setCurrentUserId(res.profile.userId)
|
||||
client?.delegate = self
|
||||
updateConnectionState(.connecting)
|
||||
client?.connect()
|
||||
}
|
||||
|
||||
public func setDelegate(_ delegate: ImEventDelegate) {
|
||||
self.delegate = delegate
|
||||
client?.delegate = self
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
| 字段 | 内容 |
|
||||
|------|------|
|
||||
| **测试目的** | 验证 UserSig 鉴权登录与登出流程 |
|
||||
| **测试步骤** | 1. 调用 `XuqmSDK.shared.login(userId: "user_001", userSig: "xxx")` <br> 2. 观察 `ImSDK.shared.loginWithUserSig` 内部触发 WebSocket 连接 <br> 3. 监听 `ImEventDelegate.imClientDidConnect()` <br> 4. 调用 `XuqmSDK.shared.logout()` <br> 5. 确认 `ImSDK.shared.disconnect()` 执行,Push Token 解注册 |
|
||||
| **测试步骤** | 1. 调用 `XuqmSDK.shared.login(userId: "user_001", userSig: "xxx")` <br> 2. 观察 `ImSDK.shared.login` 内部触发 WebSocket 连接 <br> 3. 监听 `ImEventDelegate.imClientDidConnect()` <br> 4. 调用 `XuqmSDK.shared.logout()` <br> 5. 确认 `ImSDK.shared.disconnect()` 执行,Push Token 解注册 |
|
||||
| **预期结果** | 1. `currentUserId` 被赋值 <br> 2. WebSocket 连接成功,状态变为 `.connecting` → `.connected` <br> 3. delegate `imClientDidConnect()` 触发 <br> 4. 登出后 `currentUserId` 置 nil <br> 5. `PushSDK.shared.unregisterToken` 被调用 |
|
||||
| **实际结果** | 待测试 |
|
||||
| **通过状态** | ⬜ |
|
||||
|
||||
@ -7,6 +7,14 @@ final class AuthViewModel: ObservableObject {
|
||||
@Published var currentUserId: String = ""
|
||||
@Published var currentNickname: String = ""
|
||||
|
||||
private struct DemoLoginResponse: Decodable, Sendable {
|
||||
let imToken: String
|
||||
let profile: DemoProfile
|
||||
struct DemoProfile: Decodable, Sendable {
|
||||
let userId: String
|
||||
}
|
||||
}
|
||||
|
||||
func login(userId: String, password: String) {
|
||||
guard !userId.isEmpty, !password.isEmpty else {
|
||||
state = .error("请输入用户 ID 和密码")
|
||||
@ -15,9 +23,16 @@ final class AuthViewModel: ObservableObject {
|
||||
state = .loading
|
||||
Task {
|
||||
do {
|
||||
try await ImSDK.shared.loginWithDemo(userId: userId, password: password)
|
||||
currentUserId = userId
|
||||
currentNickname = userId
|
||||
let config = XuqmSDK.shared.requireConfig()
|
||||
let res: DemoLoginResponse = try await ApiClient.shared.request(
|
||||
path: "/api/demo/auth/login",
|
||||
method: "POST",
|
||||
queryItems: [URLQueryItem(name: "appId", value: config.appId)],
|
||||
body: ["appId": config.appId, "userId": userId, "password": password]
|
||||
)
|
||||
await XuqmSDK.shared.login(userId: res.profile.userId, userSig: res.imToken)
|
||||
currentUserId = res.profile.userId
|
||||
currentNickname = res.profile.userId
|
||||
state = .success
|
||||
} catch {
|
||||
state = .error(error.localizedDescription)
|
||||
@ -26,7 +41,7 @@ final class AuthViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
func logout() {
|
||||
ImSDK.shared.disconnect()
|
||||
Task { await XuqmSDK.shared.logout() }
|
||||
currentUserId = ""
|
||||
currentNickname = ""
|
||||
state = .idle
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户