mv-experiment #1
24
ConversationsClassic/AppData/Client/Client+MartinDisco.swift
Normal file
24
ConversationsClassic/AppData/Client/Client+MartinDisco.swift
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import GRDB
|
||||||
|
import Martin
|
||||||
|
|
||||||
|
final class ClientMartinDiscoManager {
|
||||||
|
private(set) var features: [ServerFeature] = []
|
||||||
|
private var cancellables: Set<AnyCancellable> = []
|
||||||
|
|
||||||
|
init(_ xmppConnection: XMPPClient) {
|
||||||
|
// subscribe to client server features
|
||||||
|
xmppConnection.module(DiscoveryModule.self).$serverDiscoResult
|
||||||
|
.sink { [weak self] disco in
|
||||||
|
let allFeatures = ServerFeature.allFeatures
|
||||||
|
let features = disco.features
|
||||||
|
.compactMap { featureId in
|
||||||
|
allFeatures.first(where: { $0.xmppId == featureId })
|
||||||
|
}
|
||||||
|
self?.features = features
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,15 @@ final class ClientMartinMessagesManager {
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.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
|
// enable carbons if available
|
||||||
xmppConnection.module(.messageCarbons).$isAvailable.filter { $0 }
|
xmppConnection.module(.messageCarbons).$isAvailable.filter { $0 }
|
||||||
.sink(receiveValue: { [weak xmppConnection] _ in
|
.sink(receiveValue: { [weak xmppConnection] _ in
|
||||||
|
|
|
@ -25,12 +25,14 @@ final class Client: ObservableObject {
|
||||||
private var rosterManager = ClientMartinRosterManager()
|
private var rosterManager = ClientMartinRosterManager()
|
||||||
private var chatsManager = ClientMartinChatsManager()
|
private var chatsManager = ClientMartinChatsManager()
|
||||||
private var messageManager: ClientMartinMessagesManager
|
private var messageManager: ClientMartinMessagesManager
|
||||||
|
private var discoManager: ClientMartinDiscoManager
|
||||||
|
|
||||||
init(credentials: Credentials) {
|
init(credentials: Credentials) {
|
||||||
self.credentials = credentials
|
self.credentials = credentials
|
||||||
state = credentials.isActive ? .enabled(.disconnected) : .disabled
|
state = credentials.isActive ? .enabled(.disconnected) : .disabled
|
||||||
connection = Self.prepareConnection(credentials, rosterManager, chatsManager)
|
connection = Self.prepareConnection(credentials, rosterManager, chatsManager)
|
||||||
messageManager = ClientMartinMessagesManager(connection)
|
messageManager = ClientMartinMessagesManager(connection)
|
||||||
|
discoManager = ClientMartinDiscoManager(connection)
|
||||||
connectionCancellable = connection.$state
|
connectionCancellable = connection.$state
|
||||||
.sink { [weak self] state in
|
.sink { [weak self] state in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
@ -134,6 +136,16 @@ extension Client {
|
||||||
throw URLError(.badServerResponse)
|
throw URLError(.badServerResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestArchivedMessages(for roster: Roster) async {
|
||||||
|
if !discoManager.features.map({ $0.xep }).contains("XEP-0313") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let module = connection.module(MessageArchiveManagementModule.self)
|
||||||
|
let endDate = Date()
|
||||||
|
let startDate = Calendar.current.date(byAdding: .day, value: -Const.mamRequestDaysLength, to: endDate) ?? Date()
|
||||||
|
let response = try? await module.queryItems(componentJid: JID(credentials.bareJid), with: JID(roster.bareJid), start: startDate, end: endDate, queryId: UUID().uuidString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Client {
|
extension Client {
|
||||||
|
@ -163,7 +175,7 @@ private extension Client {
|
||||||
|
|
||||||
client.modulesManager.register(PubSubModule())
|
client.modulesManager.register(PubSubModule())
|
||||||
client.modulesManager.register(MessageModule(chatManager: chat))
|
client.modulesManager.register(MessageModule(chatManager: chat))
|
||||||
// client.modulesManager.register(MessageArchiveManagementModule())
|
client.modulesManager.register(MessageArchiveManagementModule())
|
||||||
|
|
||||||
client.modulesManager.register(MessageCarbonsModule())
|
client.modulesManager.register(MessageCarbonsModule())
|
||||||
|
|
||||||
|
|
21
ConversationsClassic/AppData/Model/ServerFeature.swift
Normal file
21
ConversationsClassic/AppData/Model/ServerFeature.swift
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct ServerFeature: Identifiable & Codable {
|
||||||
|
let xep: String
|
||||||
|
let name: String
|
||||||
|
let xmppId: String?
|
||||||
|
let description: String?
|
||||||
|
|
||||||
|
var id: String { xep }
|
||||||
|
|
||||||
|
static var allFeatures: [ServerFeature] {
|
||||||
|
guard
|
||||||
|
let url = Bundle.main.url(forResource: "server_features", withExtension: "plist"),
|
||||||
|
let data = try? Data(contentsOf: url),
|
||||||
|
let loaded = try? PropertyListDecoder().decode([ServerFeature].self, from: data)
|
||||||
|
else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return loaded
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,9 @@ final class ConversationStore: ObservableObject {
|
||||||
self.client = client
|
self.client = client
|
||||||
self.roster = roster
|
self.roster = roster
|
||||||
subscribe()
|
subscribe()
|
||||||
|
Task {
|
||||||
|
await client.requestArchivedMessages(for: roster)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue