conversations-classic-ios/ConversationsClassic/AppData/Client/Client.swift
2024-08-11 13:39:17 +02:00

117 lines
3.8 KiB
Swift

import Combine
import Foundation
import Martin
enum ClientState: Equatable {
enum ClientConnectionState {
case connected
case disconnected
}
case disabled
case enabled(ClientConnectionState)
}
final class Client: ObservableObject {
@Published private(set) var state: ClientState = .enabled(.disconnected)
@Published private(set) var credentials: Credentials
private var connection: XMPPClient
private var connectionCancellable: AnyCancellable?
private var rosterManager = ClientMartinRosterManager()
init(credentials: Credentials) {
self.credentials = credentials
state = credentials.isActive ? .enabled(.disconnected) : .disabled
connection = Self.prepareConnection(credentials, rosterManager)
connectionCancellable = connection.$state
.sink { [weak self] state in
guard let self = self else { return }
guard self.credentials.isActive else {
self.state = .disabled
return
}
switch state {
case .connected:
self.state = .enabled(.connected)
default:
self.state = .enabled(.disconnected)
}
}
}
func addRoster(_ roster: Roster) async throws {
_ = try await connection.module(.roster).addItem(
jid: JID(roster.contactBareJid),
name: roster.name,
groups: roster.data.groups
)
}
func deleteRoster(_ roster: Roster) async throws {
_ = try await connection.module(.roster).removeItem(jid: JID(roster.contactBareJid))
}
}
extension Client {
enum ClientLoginResult {
case success(Client)
case failure
}
static func tryLogin(with credentials: Credentials) async -> ClientLoginResult {
let client = Client(credentials: credentials)
do {
try await client.connection.loginAndWait()
return .success(client)
} catch {
return .failure
}
}
}
private extension Client {
static func prepareConnection(_ credentials: Credentials, _ roster: RosterManager) -> XMPPClient {
let client = XMPPClient()
// register modules
// core modules RFC 6120
client.modulesManager.register(StreamFeaturesModule())
client.modulesManager.register(SaslModule())
client.modulesManager.register(AuthModule())
client.modulesManager.register(SessionEstablishmentModule())
client.modulesManager.register(ResourceBinderModule())
client.modulesManager.register(DiscoveryModule(identity: .init(category: "client", type: "iOS", name: Const.appName)))
// messaging modules RFC 6121
client.modulesManager.register(RosterModule(rosterManager: roster))
client.modulesManager.register(PresenceModule())
// client.modulesManager.register(PubSubModule())
// client.modulesManager.register(MessageModule(chatManager: manager))
// client.modulesManager.register(MessageArchiveManagementModule())
// client.modulesManager.register(MessageCarbonsModule())
// file transfer modules
// client.modulesManager.register(HttpFileUploadModule())
// extensions
client.modulesManager.register(SoftwareVersionModule())
client.modulesManager.register(PingModule())
client.connectionConfiguration.userJid = .init(credentials.bareJid)
client.connectionConfiguration.credentials = .password(password: credentials.pass)
// group chats
// client.modulesManager.register(MucModule(roomManager: manager))
// channels
// client.modulesManager.register(MixModule(channelManager: manager))
// add client to clients
return client
}
}