2024-08-18 17:20:55 +00:00
|
|
|
import Combine
|
|
|
|
import Foundation
|
|
|
|
import GRDB
|
|
|
|
import Martin
|
|
|
|
|
2024-08-19 02:47:56 +00:00
|
|
|
private typealias ArchMsg = Martin.MessageArchiveManagementModule.ArchivedMessageReceived
|
|
|
|
|
2024-08-18 17:20:55 +00:00
|
|
|
final class ClientMartinMAM {
|
|
|
|
private var cancellables: Set<AnyCancellable> = []
|
2024-08-19 02:47:56 +00:00
|
|
|
private var processor = ArchiveMessageProcessor()
|
2024-08-18 17:20:55 +00:00
|
|
|
|
|
|
|
init(_ xmppConnection: XMPPClient) {
|
|
|
|
// subscribe to archived messages
|
2024-08-19 02:47:56 +00:00
|
|
|
xmppConnection.module(.mam).archivedMessagesPublisher
|
2024-08-18 17:20:55 +00:00
|
|
|
.sink(receiveValue: { [weak self] archived in
|
2024-08-18 20:27:12 +00:00
|
|
|
guard let self = self else { return }
|
|
|
|
Task {
|
2024-08-19 02:47:56 +00:00
|
|
|
await self.processor.append(archived)
|
2024-08-18 20:27:12 +00:00
|
|
|
}
|
2024-08-18 17:20:55 +00:00
|
|
|
})
|
|
|
|
.store(in: &cancellables)
|
|
|
|
}
|
2024-08-19 02:47:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private actor ArchiveMessageProcessor {
|
|
|
|
private var accumulator: [ArchMsg] = []
|
|
|
|
|
|
|
|
init() {
|
|
|
|
Task {
|
|
|
|
while true {
|
|
|
|
try? await Task.sleep(nanoseconds: 700 * NSEC_PER_MSEC)
|
|
|
|
await process()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-18 17:20:55 +00:00
|
|
|
|
2024-08-19 02:47:56 +00:00
|
|
|
func append(_ msg: ArchMsg) async {
|
|
|
|
accumulator.append(msg)
|
2024-08-19 05:56:04 +00:00
|
|
|
if accumulator.count >= Const.mamRequestPageSize {
|
2024-08-19 02:47:56 +00:00
|
|
|
await process()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func process() async {
|
|
|
|
if accumulator.isEmpty { return }
|
|
|
|
await handleMessages(accumulator)
|
|
|
|
accumulator.removeAll()
|
|
|
|
}
|
2024-08-18 17:20:55 +00:00
|
|
|
|
2024-08-19 02:47:56 +00:00
|
|
|
private func handleMessages(_ received: [ArchMsg]) async {
|
|
|
|
if received.isEmpty { return }
|
2024-08-19 02:38:06 +00:00
|
|
|
try? await Database.shared.dbQueue.write { db in
|
2024-08-19 02:47:56 +00:00
|
|
|
for recv in received {
|
|
|
|
let message = recv.message
|
|
|
|
let date = recv.timestamp
|
|
|
|
if let msgId = message.id {
|
|
|
|
if try Message.fetchOne(db, key: msgId) != nil {
|
|
|
|
#if DEBUG
|
|
|
|
print("---")
|
|
|
|
print("Skipping archived message with id \(msgId) (message exists)")
|
|
|
|
print("---")
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#if DEBUG
|
|
|
|
print("---")
|
|
|
|
print("Archive message received: \(message)")
|
|
|
|
print("Date: \(date)")
|
|
|
|
print("---")
|
|
|
|
#endif
|
2024-09-03 13:07:53 +00:00
|
|
|
if var msg = Message.map(message, context: nil) {
|
2024-08-19 02:47:56 +00:00
|
|
|
msg.date = date
|
|
|
|
try msg.insert(db)
|
|
|
|
}
|
|
|
|
}
|
2024-08-18 17:20:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|