144 lines
5.3 KiB
Swift
144 lines
5.3 KiB
Swift
import Foundation
|
||
import monalxmpp
|
||
|
||
final class MonalXmppWrapper: ObservableObject {
|
||
@Published private(set) var accountsAvailability: AccountsAvailability = .noAccounts
|
||
@Published private(set) var accounts: [Account] = []
|
||
@Published private(set) var contacts: [Contact] = []
|
||
|
||
private let xmpp: MLXMPPManager
|
||
private let db: DataLayer
|
||
|
||
private var notificationObservers: [AnyObject] = []
|
||
|
||
init() {
|
||
// here is some inits (just for now)
|
||
MLProcessLock.initialize(forProcess: "MainApp")
|
||
|
||
// init monalxmpp components
|
||
xmpp = MLXMPPManager.sharedInstance()
|
||
db = DataLayer.sharedInstance()
|
||
|
||
// subscribe to monalxmpp notifications and fire notification for update
|
||
subscribeToUpdates()
|
||
NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil)
|
||
}
|
||
|
||
deinit {
|
||
notificationObservers.forEach { NotificationCenter.default.removeObserver($0) }
|
||
}
|
||
}
|
||
|
||
// MARK: - Public
|
||
extension MonalXmppWrapper {
|
||
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
|
||
} else {
|
||
NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil)
|
||
}
|
||
}
|
||
|
||
func addContact(contactJid: String, forAccountID: Int) async {
|
||
await withCheckedContinuation { [weak self] cnt in
|
||
let contact = MLContact.createContact(fromJid: contactJid, andAccountID: NSNumber(value: forAccountID))
|
||
self?.xmpp.add(contact)
|
||
cnt.resume()
|
||
}
|
||
NotificationCenter.default.post(name: Notification.Name(kMonalContactRefresh), object: nil)
|
||
}
|
||
}
|
||
|
||
// MARK: - Try login from Login screen
|
||
private final class LoginTry {
|
||
weak var xmpp: MLXMPPManager?
|
||
|
||
var successObserver: AnyObject?
|
||
var failureObserver: AnyObject?
|
||
|
||
init(xmpp: MLXMPPManager) {
|
||
self.xmpp = xmpp
|
||
}
|
||
|
||
// TODO: Добавить автовключение отключенных аккаунтов при попытке ввести тот же JID
|
||
// Обработать кейс когда бесячий monalxmpp возвращает nil при попытке добавить тот же JID
|
||
func tryLogin(_ login: String, _ password: String) async -> Bool {
|
||
async let notify = await withCheckedContinuation { [weak self] continuation in
|
||
self?.successObserver = NotificationCenter.default.addObserver(forName: Notification.Name("kMLResourceBoundNotice"), object: nil, queue: .main) { notification in
|
||
print(notification.debugDescription)
|
||
continuation.resume(returning: true)
|
||
}
|
||
self?.failureObserver = NotificationCenter.default.addObserver(forName: Notification.Name("kXMPPError"), object: nil, queue: .main) { notification in
|
||
print(notification.debugDescription)
|
||
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)
|
||
}
|
||
|
||
return result
|
||
}
|
||
}
|
||
|
||
// MARK: - Handle notifications
|
||
private extension MonalXmppWrapper {
|
||
func subscribeToUpdates() {
|
||
// General
|
||
let generalRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalRefresh), object: nil, queue: .main) { [weak self] _ in
|
||
self?.refreshAccounts()
|
||
self?.refreshContacts()
|
||
}
|
||
notificationObservers.append(generalRefresh)
|
||
|
||
// For contacts
|
||
let contactRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRefresh), object: nil, queue: .main) { [weak self] _ in
|
||
self?.refreshContacts()
|
||
}
|
||
let contactRemove = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRemoved), object: nil, queue: .main) { [weak self] _ in
|
||
self?.refreshContacts()
|
||
}
|
||
notificationObservers.append(contentsOf: [contactRefresh, contactRemove])
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
func refreshContacts() {
|
||
contacts = db.contactList()
|
||
.filter { $0.isSubscribedTo || $0.hasOutgoingContactRequest || $0.isSubscribedFrom }
|
||
.filter { !$0.isSelfChat } // removed for now
|
||
.compactMap { Contact($0) }
|
||
}
|
||
}
|