diff --git a/Sources/XuqmSDK/IM/ImClient.swift b/Sources/XuqmSDK/IM/ImClient.swift index 126c525..68e43fc 100644 --- a/Sources/XuqmSDK/IM/ImClient.swift +++ b/Sources/XuqmSDK/IM/ImClient.swift @@ -84,6 +84,7 @@ public final class ImClient: NSObject, URLSessionWebSocketDelegate, @unchecked S status: .sending, mentionedUserIds: mentionedUserIds?.isEmpty == false ? mentionedUserIds : nil, groupReadCount: nil, + revoked: false, createdAt: now ) guard let activeAppId else { @@ -199,6 +200,9 @@ public final class ImClient: NSObject, URLSessionWebSocketDelegate, @unchecked S let msg = try? JSONDecoder().decode(ImMessage.self, from: messageData) else { continue } + if (msg.revoked ?? false) || msg.status == .revoked || msg.msgType == .revoked { + delegate?.imClientDidReceiveRevokedMessage(msg) + } if msg.chatType == .group { delegate?.imClientDidReceiveGroupMessage(msg) } else { @@ -298,6 +302,7 @@ private extension ImMessage { status: .failed, mentionedUserIds: mentionedUserIds, groupReadCount: groupReadCount, + revoked: false, createdAt: createdAt ) } diff --git a/Sources/XuqmSDK/IM/ImSDK.swift b/Sources/XuqmSDK/IM/ImSDK.swift index f5a242c..b8c68e9 100644 --- a/Sources/XuqmSDK/IM/ImSDK.swift +++ b/Sources/XuqmSDK/IM/ImSDK.swift @@ -248,6 +248,16 @@ public final class ImSDK { client?.revoke(messageId: messageId) } + public func editMessage(messageId: String, content: String) async throws -> ImMessage { + let config = XuqmSDK.shared.requireConfig() + return try await ApiClient.shared.request( + path: "/api/im/messages/\(messageId)", + method: "PUT", + queryItems: [URLQueryItem(name: "appId", value: config.appId)], + body: EditMessageRequest(content: content) + ) + } + public func subscribeGroup(_ groupId: String) { client?.subscribeGroup(groupId) } @@ -274,6 +284,7 @@ public final class ImSDK { status: .failed, mentionedUserIds: mentionedUserIds, groupReadCount: nil, + revoked: false, createdAt: Int64(Date().timeIntervalSince1970 * 1000) ) } @@ -319,6 +330,57 @@ public final class ImSDK { ) } + public func locateHistoryPage( + toId: String, + messageId: String, + pageSize: Int = 20, + maxPages: Int = 20 + ) async throws -> [ImMessage]? { + try await locatePage( + messageId: messageId, + maxPages: maxPages, + pageSize: pageSize, + loadPage: { page in + try await self.fetchHistory(toId: toId, page: page, size: pageSize) + } + ) + } + + public func locateGroupHistoryPage( + groupId: String, + messageId: String, + pageSize: Int = 20, + maxPages: Int = 20 + ) async throws -> [ImMessage]? { + try await locatePage( + messageId: messageId, + maxPages: maxPages, + pageSize: pageSize, + loadPage: { page in + try await self.fetchGroupHistory(groupId: groupId, page: page, size: pageSize) + } + ) + } + + private func locatePage( + messageId: String, + maxPages: Int, + pageSize: Int, + loadPage: @escaping (Int) async throws -> [ImMessage] + ) async throws -> [ImMessage]? { + let pageCount = max(maxPages, 1) + for page in 0.. [ImGroup] { let config = XuqmSDK.shared.requireConfig() let groups: [ImGroup] = try await ApiClient.shared.request( diff --git a/Sources/XuqmSDK/IM/ImTypes.swift b/Sources/XuqmSDK/IM/ImTypes.swift index 2e436a7..dc5ddcd 100644 --- a/Sources/XuqmSDK/IM/ImTypes.swift +++ b/Sources/XuqmSDK/IM/ImTypes.swift @@ -43,6 +43,7 @@ public struct ImMessage: Codable, Sendable { public let status: MsgStatus public let mentionedUserIds: String? public let groupReadCount: Int? + public let revoked: Bool? public let createdAt: Int64 } @@ -63,9 +64,14 @@ public protocol ImEventDelegate: AnyObject { func imClientDidDisconnect(reason: String?) func imClientDidReceiveMessage(_ message: ImMessage) func imClientDidReceiveGroupMessage(_ message: ImMessage) + func imClientDidReceiveRevokedMessage(_ message: ImMessage) func imClientDidError(_ error: String) } +public extension ImEventDelegate { + func imClientDidReceiveRevokedMessage(_ message: ImMessage) {} +} + public struct ImGroup: Codable, Sendable { public let id: String public let appId: String @@ -139,6 +145,10 @@ public struct ImSendMessageRequest: Encodable, Sendable { public let mentionedUserIds: String? } +public struct EditMessageRequest: Encodable, Sendable { + public let content: String +} + public struct ImLoginResponse: Decodable, Sendable { public let token: String }