package com.xuqm.sdk.im import com.xuqm.sdk.XuqmLoginSession import com.xuqm.sdk.XuqmSDK import com.xuqm.sdk.core.ServiceEndpointRegistry import com.xuqm.sdk.im.api.AddMemberRequest import com.xuqm.sdk.im.api.CreateGroupRequest import com.xuqm.sdk.im.api.ImApi import com.xuqm.sdk.im.api.SetMutedRequest import com.xuqm.sdk.im.api.SetPinnedRequest import com.xuqm.sdk.im.api.UpdateGroupRequest import com.xuqm.sdk.im.listener.ImEventListener import com.xuqm.sdk.im.model.ImConnectionState import com.xuqm.sdk.im.model.ConversationData import com.xuqm.sdk.im.model.ImGroup import com.xuqm.sdk.im.model.ImMessage import com.xuqm.sdk.network.ApiClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow object ImSDK { private var client: ImClient? = null private val api: ImApi get() = ApiClient.create(ImApi::class.java, ServiceEndpointRegistry.imApiBaseUrl) private val connectionListener = object : ImEventListener { override fun onConnected() { _connectionState.value = ImConnectionState.Connected } override fun onDisconnected(reason: String?) { _connectionState.value = ImConnectionState.Disconnected(reason) } override fun onError(error: String) { _connectionState.value = ImConnectionState.Disconnected(error) } } private val _connectionState = MutableStateFlow(ImConnectionState.Disconnected("未连接")) val connectionState: StateFlow = _connectionState var currentUserId: String = "" private set init { XuqmSDK.currentLoginSession?.let { onSdkLogin(it) } } suspend fun login( userId: String, userSig: String, nickname: String? = null, avatar: String? = null, ) = withContext(Dispatchers.IO) { XuqmSDK.requireInit() currentUserId = userId connectWithToken(userSig) } suspend fun loginWithUserSig(userId: String, userSig: String) = withContext(Dispatchers.IO) { XuqmSDK.requireInit() currentUserId = userId connectWithToken(userSig) } @Deprecated("Use loginWithUserSig(userId, userSig) instead.") suspend fun loginWithToken(userId: String, token: String) = loginWithUserSig(userId, token) fun sendMessage(toId: String, chatType: String, msgType: String, content: String) { client?.sendMessage(toId, chatType, msgType, content) } suspend fun fetchHistory(toId: String, page: Int = 0, size: Int = 20): List = withContext(Dispatchers.IO) { api.fetchHistory(toId, XuqmSDK.appId, page, size).data ?: emptyList() } suspend fun fetchGroupHistory(groupId: String, page: Int = 0, size: Int = 20): List = withContext(Dispatchers.IO) { api.fetchGroupHistory(groupId, XuqmSDK.appId, page, size).data ?: emptyList() } suspend fun listGroups(): List = withContext(Dispatchers.IO) { api.listGroups(XuqmSDK.appId).data ?: emptyList() } suspend fun createGroup(name: String, memberIds: List): ImGroup? = withContext(Dispatchers.IO) { api.createGroup(XuqmSDK.appId, CreateGroupRequest(name, memberIds)).data } suspend fun getGroupInfo(groupId: String): ImGroup? = withContext(Dispatchers.IO) { api.getGroupInfo(groupId).data } suspend fun updateGroupInfo(groupId: String, name: String? = null, announcement: String? = null) = withContext(Dispatchers.IO) { api.updateGroupInfo(groupId, UpdateGroupRequest(name, announcement)) } suspend fun addGroupMember(groupId: String, userId: String) = withContext(Dispatchers.IO) { api.addGroupMember(groupId, AddMemberRequest(userId)) } suspend fun removeGroupMember(groupId: String, userId: String) = withContext(Dispatchers.IO) { api.removeGroupMember(groupId, userId) } suspend fun leaveGroup(groupId: String) = withContext(Dispatchers.IO) { api.removeGroupMember(groupId, currentUserId) } suspend fun listFriends(): List = withContext(Dispatchers.IO) { api.listFriends(XuqmSDK.appId).data ?: emptyList() } suspend fun addFriend(friendId: String) = withContext(Dispatchers.IO) { api.addFriend(XuqmSDK.appId, friendId) } suspend fun removeFriend(friendId: String) = withContext(Dispatchers.IO) { api.removeFriend(friendId, XuqmSDK.appId) } suspend fun listConversations(): List = withContext(Dispatchers.IO) { api.listConversations(XuqmSDK.appId).data ?: emptyList() } suspend fun setConversationPinned(targetId: String, chatType: String, pinned: Boolean) = withContext(Dispatchers.IO) { api.setConversationPinned(targetId, chatType, SetPinnedRequest(pinned)) } suspend fun setConversationMuted(targetId: String, chatType: String, muted: Boolean) = withContext(Dispatchers.IO) { api.setConversationMuted(targetId, chatType, SetMutedRequest(muted)) } suspend fun markRead(targetId: String, chatType: String = "SINGLE") = withContext(Dispatchers.IO) { api.markRead(targetId, XuqmSDK.appId, chatType) } fun addListener(listener: ImEventListener) = client?.addListener(listener) fun removeListener(listener: ImEventListener) = client?.removeListener(listener) fun disconnect() { disconnectInternal(clearTokenStore = true) } fun onSdkLogin(session: XuqmLoginSession) { XuqmSDK.requireInit() currentUserId = session.userId connectWithToken(session.userSig) } fun onSdkLogout() { disconnectInternal(clearTokenStore = false) } private fun connectWithToken(token: String) { XuqmSDK.tokenStore.saveToken(token) client?.disconnect() _connectionState.value = ImConnectionState.Connecting client = ImClient(ServiceEndpointRegistry.imWsUrl, token, XuqmSDK.appId) client?.addListener(connectionListener) client?.connect() } private fun disconnectInternal(clearTokenStore: Boolean) { client?.disconnect() client = null currentUserId = "" _connectionState.value = ImConnectionState.Disconnected("已断开") if (clearTokenStore) { XuqmSDK.tokenStore.clear() } } }