another.im-ios/Monal/another.im/XMPP/MonalXmppWrapper.swift

213 lines
7.4 KiB
Swift
Raw Normal View History

2024-11-19 12:59:22 +00:00
import Foundation
import monalxmpp
final class MonalXmppWrapper: ObservableObject {
2024-11-21 16:03:55 +00:00
@Published private(set) var accountsAvailability: AccountsAvailability = .noAccounts
@Published private(set) var accounts: [Account] = []
@Published private(set) var contacts: [Contact] = []
2024-11-23 16:23:56 +00:00
@Published private(set) var activeChats: [Chat] = []
2024-11-19 12:59:22 +00:00
2024-11-20 15:52:49 +00:00
private let xmpp: MLXMPPManager
private let db: DataLayer
2024-11-19 12:59:22 +00:00
2024-11-21 16:03:55 +00:00
private var notificationObservers: [AnyObject] = []
2024-11-19 12:59:22 +00:00
init() {
2024-11-20 15:52:49 +00:00
// here is some inits (just for now)
MLProcessLock.initialize(forProcess: "MainApp")
2024-11-21 13:32:38 +00:00
// init monalxmpp components
xmpp = MLXMPPManager.sharedInstance()
db = DataLayer.sharedInstance()
2024-11-21 16:03:55 +00:00
// subscribe to monalxmpp notifications and fire notification for update
subscribeToUpdates()
NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil)
2024-11-25 10:51:00 +00:00
// reconnect
2024-11-25 11:49:47 +00:00
// xmpp.nowForegrounded()
// xmpp.connectIfNecessary()
2024-11-21 16:03:55 +00:00
}
deinit {
notificationObservers.forEach { NotificationCenter.default.removeObserver($0) }
2024-11-19 12:59:22 +00:00
}
2024-11-22 14:45:38 +00:00
}
2024-11-20 15:52:49 +00:00
2024-11-22 14:45:38 +00:00
// MARK: - Public
extension MonalXmppWrapper {
2024-11-20 15:52:49 +00:00
func tryLogin(_ login: String, _ password: String) async throws {
let loginObject = LoginTry(xmpp: xmpp)
let result = await loginObject.tryLogin(login, password)
if !result {
throw AimErrors.loginError
2024-11-19 12:59:22 +00:00
} else {
2024-11-21 16:03:55 +00:00
NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil)
2024-11-19 12:59:22 +00:00
}
}
2024-11-22 14:45:38 +00:00
2024-11-22 16:34:56 +00:00
func addContact(contactJid: String, forAccountID: Int) async {
2024-11-22 16:54:07 +00:00
let contact = MLContact.createContact(fromJid: contactJid, andAccountID: NSNumber(value: forAccountID))
xmpp.add(contact)
}
func deleteContact(_ contact: Contact) async throws {
if let mlContact = db.contactList().first(where: { $0.contactJid == contact.contactJid }) {
xmpp.remove(mlContact)
} else {
throw AimErrors.contactRemoveError
2024-11-22 16:34:56 +00:00
}
2024-11-22 14:45:38 +00:00
}
2024-11-23 23:22:07 +00:00
2024-11-24 18:42:46 +00:00
func chat(with: Contact) -> MonalChatWrapper {
let chatModel = MonalChatWrapper(contact: with, db: db, xmpp: xmpp)
2024-11-23 23:22:07 +00:00
return chatModel
}
2024-11-25 10:51:00 +00:00
func chat(with: Chat) -> MonalChatWrapper? {
guard let contact = contacts.first(where: { $0.ownerId == with.accountId && $0.contactJid == with.participantJid }) else { return nil }
let chatModel = MonalChatWrapper(contact: contact, db: db, xmpp: xmpp)
return chatModel
}
2024-11-19 12:59:22 +00:00
}
2024-11-20 15:52:49 +00:00
2024-11-21 13:32:38 +00:00
// MARK: - Try login from Login screen
2024-11-20 15:52:49 +00:00
private final class LoginTry {
weak var xmpp: MLXMPPManager?
var successObserver: AnyObject?
var failureObserver: AnyObject?
init(xmpp: MLXMPPManager) {
self.xmpp = xmpp
}
2024-11-21 13:32:38 +00:00
// TODO: Добавить автовключение отключенных аккаунтов при попытке ввести тот же JID
2024-11-20 15:52:49 +00:00
// Обработать кейс когда бесячий monalxmpp возвращает nil при попытке добавить тот же JID
func tryLogin(_ login: String, _ password: String) async -> Bool {
async let notify = await withCheckedContinuation { [weak self] continuation in
2024-11-25 11:49:47 +00:00
self?.successObserver = NotificationCenter.default.addObserver(forName: Notification.Name("kMLResourceBoundNotice"), object: nil, queue: .main) { _ in
2024-11-20 15:52:49 +00:00
continuation.resume(returning: true)
}
2024-11-25 11:49:47 +00:00
self?.failureObserver = NotificationCenter.default.addObserver(forName: Notification.Name("kXMPPError"), object: nil, queue: .main) { _ in
2024-11-20 15:52:49 +00:00
continuation.resume(returning: false)
}
}
defer {
if let successObserver {
NotificationCenter.default.removeObserver(successObserver)
}
if let failureObserver {
NotificationCenter.default.removeObserver(failureObserver)
}
}
let accountNumber = xmpp?.login(login, password: password)
let result = await notify
if let accountNumber, !result {
xmpp?.removeAccount(forAccountID: accountNumber)
}
2024-11-20 19:51:05 +00:00
2024-11-20 15:52:49 +00:00
return result
}
}
2024-11-21 16:03:55 +00:00
// MARK: - Handle notifications
private extension MonalXmppWrapper {
func subscribeToUpdates() {
2024-11-22 13:12:09 +00:00
// General
2024-11-21 16:03:55 +00:00
let generalRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalRefresh), object: nil, queue: .main) { [weak self] _ in
2024-11-22 13:12:09 +00:00
self?.refreshAccounts()
self?.refreshContacts()
2024-11-23 16:23:56 +00:00
self?.refreshChats()
2024-11-22 13:12:09 +00:00
}
notificationObservers.append(generalRefresh)
2024-11-21 16:03:55 +00:00
2024-11-22 13:12:09 +00:00
// For contacts
let contactRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRefresh), object: nil, queue: .main) { [weak self] _ in
self?.refreshContacts()
2024-11-23 16:23:56 +00:00
self?.refreshChats()
2024-11-22 13:12:09 +00:00
}
let contactRemove = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRemoved), object: nil, queue: .main) { [weak self] _ in
self?.refreshContacts()
2024-11-23 16:23:56 +00:00
self?.refreshChats()
2024-11-22 13:12:09 +00:00
}
notificationObservers.append(contentsOf: [contactRefresh, contactRemove])
2024-11-23 16:23:56 +00:00
// For chats
// ???
2024-11-22 13:12:09 +00:00
}
2024-11-21 16:03:55 +00:00
2024-11-22 13:12:09 +00:00
func refreshAccounts() {
let accounts = db.accountList()
.compactMap { dict -> Account? in
guard let dict = dict as? NSDictionary else { return nil }
return Account(dict)
}
self.accounts = accounts
xmpp.connectIfNecessary()
// mark accounts availability
if accounts.isEmpty {
accountsAvailability = .noAccounts
} else if accounts.filter({ $0.isEnabled }).isEmpty {
accountsAvailability = .allDisabled
} else {
accountsAvailability = .someEnabled
2024-11-21 16:03:55 +00:00
}
2024-11-22 13:12:09 +00:00
}
func refreshContacts() {
2024-11-22 16:34:56 +00:00
contacts = db.contactList()
.filter { $0.isSubscribedTo || $0.hasOutgoingContactRequest || $0.isSubscribedFrom }
.filter { !$0.isSelfChat } // removed for now
.compactMap { Contact($0) }
2024-11-21 16:03:55 +00:00
}
2024-11-23 16:23:56 +00:00
func refreshChats() {
activeChats = db.activeContacts(withPinned: false)
.compactMap {
guard let contact = $0 as? MLContact else { return nil }
return Chat(contact)
}
}
2024-11-21 16:03:55 +00:00
}
2024-11-23 23:22:07 +00:00
// MARK: - Chat object
2024-11-24 18:42:46 +00:00
final class MonalChatWrapper: ObservableObject {
@Published private(set) var messages: [Message] = []
2024-11-23 23:22:07 +00:00
let contact: Contact
2024-11-24 18:42:46 +00:00
private let xmpp: MLXMPPManager
private let db: DataLayer
2024-11-25 10:51:00 +00:00
private var notificationObservers: [AnyObject] = []
2024-11-23 23:22:07 +00:00
2024-11-24 18:42:46 +00:00
init(contact: Contact, db: DataLayer, xmpp: MLXMPPManager) {
2024-11-23 23:22:07 +00:00
self.contact = contact
2024-11-24 18:42:46 +00:00
self.db = db
self.xmpp = xmpp
2024-11-25 11:49:47 +00:00
subscribe()
2024-11-24 18:42:46 +00:00
}
2024-11-25 10:51:00 +00:00
deinit {
notificationObservers.forEach { NotificationCenter.default.removeObserver($0) }
}
private func subscribe() {
let newMsg = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalNewMessageNotice), object: nil, queue: .main) { [weak self] _ in
self?.refreshMessages()
}
notificationObservers.append(newMsg)
}
2024-11-24 18:42:46 +00:00
private func refreshMessages() {
messages = db.messages(forContact: contact.contactJid, forAccount: NSNumber(value: contact.ownerId))
.compactMap {
guard let message = $0 as? MLMessage else { return nil }
return Message(message)
}
2024-11-23 23:22:07 +00:00
}
}