import Combine import Foundation import GRDB import Martin final class ClientMartinMessagesManager { private var cancellables: Set = [] init(_ xmppConnection: XMPPClient) { // subscribe to client messages xmppConnection.module(MessageModule.self).messagesPublisher .sink { [weak self] message in self?.handleMessage(message.message) } .store(in: &cancellables) // subscribe to carbons xmppConnection.module(MessageCarbonsModule.self).carbonsPublisher .sink { [weak self] carbon in self?.handleMessage(carbon.message) } .store(in: &cancellables) // subscribe to archived messages xmppConnection.module(.mam).archivedMessagesPublisher .sink(receiveValue: { [weak self] archived in let message = archived.message message.attribute("archived_date", newValue: "\(archived.timestamp.timeIntervalSince1970)") self?.handleMessage(message) }) .store(in: &cancellables) // enable carbons if available xmppConnection.module(.messageCarbons).$isAvailable.filter { $0 } .sink(receiveValue: { [weak xmppConnection] _ in xmppConnection?.module(.messageCarbons).enable() }) .store(in: &cancellables) } private func handleMessage(_ received: Martin.Message) { #if DEBUG print("---") print("Message received: \(received)") print("---") #endif // Check that the message type is supported let chatTypes: [StanzaType] = [.chat, .groupchat] guard let mType = received.type, chatTypes.contains(mType) else { #if DEBUG print("Unsupported received type: \(received.type?.rawValue ?? "nil")") #endif return } // Type let type = MessageType(rawValue: received.type?.rawValue ?? "") ?? .chat // Content type var contentType: MessageContentType = .text if let oob = received.oob { contentType = .attachment(.init( type: oob.attachmentType, localName: nil, thumbnailName: nil, remotePath: oob )) } else if received.hints.contains(.noStore) { contentType = .typing // skip for now return } // From/To let from = received.from?.bareJid.stringValue ?? "" let to = received.to?.bareJid.stringValue // Extract date or set current var date = Date() if let timestampStr = received.attribute("archived_date"), let timeInterval = TimeInterval(timestampStr) { date = Date(timeIntervalSince1970: timeInterval) } // Msg let msg = Message( id: received.id ?? UUID().uuidString, type: type, date: date, contentType: contentType, status: .sent, from: from, to: to, body: received.body, subject: received.subject, thread: received.thread, oobUrl: received.oob ) // Save message Task { do { try await msg.save() } catch { logIt(.error, "Error saving message: \(error)") } } } }