170 lines
5.4 KiB
Swift
170 lines
5.4 KiB
Swift
//
|
||
// GroupIMService.swift
|
||
// QuickLocation
|
||
//
|
||
// Created by 八条 on 2026/6/4.
|
||
//
|
||
|
||
import Foundation
|
||
import OpenIMSDK
|
||
|
||
final class GroupIMService {
|
||
|
||
static let shared = GroupIMService()
|
||
|
||
private var isInited = false
|
||
private var isLogining = false
|
||
/// 登录进行中时排队的回调,登录结束统一回调,避免并发重复登录
|
||
private var pendingLoginCompletions: [(Bool) -> Void] = []
|
||
|
||
private init() {}
|
||
|
||
// MARK: - Init SDK
|
||
func initSDK() {
|
||
// 幂等:SDK 全局只初始化一次
|
||
guard !isInited else { return }
|
||
isInited = true
|
||
let config = OIMInitConfig()
|
||
config.apiAddr = URLManager.shared.openIM_API
|
||
config.wsAddr = URLManager.shared.openIM_WS
|
||
config.platform = .iPhone
|
||
OIMManager.manager.initSDK(with: config,
|
||
onConnecting: {},
|
||
onConnectFailure: { _, _ in },
|
||
onConnectSuccess: {},
|
||
onKickedOffline: {},
|
||
onUserTokenExpired: {},
|
||
onUserTokenInvalid: { _ in })
|
||
}
|
||
|
||
// MARK: - Login
|
||
/// 确保已登录(幂等):已登录直接回调,否则发起登录;登录中则排队等待
|
||
func ensureLogin(completion: @escaping (Bool) -> Void) {
|
||
if OIMManager.manager.getLoginStatus() == .logged {
|
||
completion(true)
|
||
return
|
||
}
|
||
login(completion: completion)
|
||
}
|
||
|
||
func login(completion: @escaping (Bool) -> Void) {
|
||
// 已登录,直接成功
|
||
if OIMManager.manager.getLoginStatus() == .logged {
|
||
completion(true)
|
||
return
|
||
}
|
||
guard let token = AppContextManager.shared.imToken, !token.isEmpty else {
|
||
completion(false)
|
||
return
|
||
}
|
||
let userId = AppContextManager.shared.userId
|
||
guard !userId.isEmpty else {
|
||
completion(false)
|
||
return
|
||
}
|
||
|
||
// 登录中:排队,复用同一次登录结果,避免重复发起
|
||
pendingLoginCompletions.append(completion)
|
||
guard !isLogining else { return }
|
||
isLogining = true
|
||
|
||
OIMManager.manager.login(userId, token: token) { [weak self] _ in
|
||
self?.finishLogin(success: true)
|
||
} onFailure: { [weak self] code, msg in
|
||
print("OpenIM login failed: \(code) \(msg ?? "")")
|
||
self?.finishLogin(success: false)
|
||
}
|
||
}
|
||
|
||
private func finishLogin(success: Bool) {
|
||
isLogining = false
|
||
let callbacks = pendingLoginCompletions
|
||
pendingLoginCompletions.removeAll()
|
||
callbacks.forEach { $0(success) }
|
||
}
|
||
|
||
// MARK: - Logout
|
||
func logout(completion: ((Bool) -> Void)? = nil) {
|
||
OIMManager.manager.logoutWith(onSuccess: { (_: String?) in
|
||
completion?(true)
|
||
}, onFailure: { (code: Int, msg: String?) in
|
||
print("OpenIM logout failed: \(code) \(msg ?? "")")
|
||
completion?(false)
|
||
})
|
||
}
|
||
|
||
// MARK: - Get Joined Groups
|
||
func getJoinedGroups(completion: @escaping ([OIMGroupInfo]) -> Void) {
|
||
OIMManager.manager.getJoinedGroupListWith(onSuccess: { groups in
|
||
completion(groups ?? [])
|
||
}, onFailure: { code, msg in
|
||
print("GroupIMService: getJoinedGroups failed: \(code) \(msg ?? "")")
|
||
completion([])
|
||
})
|
||
}
|
||
|
||
// MARK: - Conversation List (for unread count & last msg time)
|
||
func getConversationList(completion: @escaping ([OIMConversationInfo]) -> Void) {
|
||
OIMManager.manager.getAllConversationListWith(onSuccess: { list in
|
||
completion(list ?? [])
|
||
}, onFailure: { code, msg in
|
||
completion([])
|
||
})
|
||
}
|
||
|
||
// MARK: - Conversation Listener
|
||
private var conversationListener: ConversationListenerProxy?
|
||
|
||
func setConversationListener(_ handler: @escaping ([OIMConversationInfo]) -> Void) {
|
||
conversationListener = ConversationListenerProxy(handler: handler)
|
||
OIMManager.callbacker.addConversationListener(listener: conversationListener!)
|
||
}
|
||
|
||
// MARK: - Group Listener
|
||
private var groupListener: GroupListenerProxy?
|
||
|
||
/// 监听群组变化(加群/退群/群信息变更),用于 SDK 同步到新群时刷新列表
|
||
func setGroupListener(_ handler: @escaping () -> Void) {
|
||
groupListener = GroupListenerProxy(handler: handler)
|
||
OIMManager.callbacker.addGroupListener(listener: groupListener!)
|
||
}
|
||
}
|
||
|
||
// MARK: - GroupListenerProxy
|
||
private class GroupListenerProxy: NSObject, OIMGroupListener {
|
||
private let handler: () -> Void
|
||
|
||
init(handler: @escaping () -> Void) {
|
||
self.handler = handler
|
||
}
|
||
|
||
func onJoinedGroupAdded(_ groupInfo: OIMGroupInfo) {
|
||
handler()
|
||
}
|
||
|
||
func onJoinedGroupDeleted(_ groupInfo: OIMGroupInfo) {
|
||
handler()
|
||
}
|
||
|
||
func onGroupInfoChanged(_ changeInfo: OIMGroupInfo) {
|
||
handler()
|
||
}
|
||
}
|
||
|
||
// MARK: - ConversationListenerProxy
|
||
private class ConversationListenerProxy: NSObject, OIMConversationListener {
|
||
private let handler: ([OIMConversationInfo]) -> Void
|
||
|
||
init(handler: @escaping ([OIMConversationInfo]) -> Void) {
|
||
self.handler = handler
|
||
}
|
||
|
||
func onConversationChanged(_ conversations: [OIMConversationInfo]) {
|
||
handler(conversations)
|
||
}
|
||
|
||
func onNewConversation(_ conversations: [OIMConversationInfo]) {
|
||
handler(conversations)
|
||
}
|
||
}
|