Skip to content
Snippets Groups Projects
Commit 86ecfb05 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk
Browse files

presence: fix possible crash when subscribe

This patch adds a queue to protect access to contact presence subscriptions.

Change-Id: I6c5cd6c0dc54c0536729d4bbcee1bae6c4a82045
parent 265f75b1
No related branches found
No related tags found
No related merge requests found
...@@ -30,7 +30,7 @@ struct Contact { ...@@ -30,7 +30,7 @@ struct Contact {
lazy var presenceStatus: BehaviorRelay<Bool>? = { lazy var presenceStatus: BehaviorRelay<Bool>? = {
self.presenceService self.presenceService
.contactPresence[self.hash] .getSubscriptionsForContact(contactId: self.hash)
}() }()
lazy var firstLine: String! = { lazy var firstLine: String! = {
......
...@@ -617,7 +617,7 @@ extension ConversationViewModel { ...@@ -617,7 +617,7 @@ extension ConversationViewModel {
private func subscribePresenceServiceContactPresence() { private func subscribePresenceServiceContactPresence() {
// subscribe to presence updates for the conversation's associated contact // subscribe to presence updates for the conversation's associated contact
if let contactPresence = self.presenceService.contactPresence[self.conversation.value.hash] { if let contactPresence = self.presenceService.getSubscriptionsForContact(contactId: self.conversation.value.hash) {
self.contactPresence = contactPresence self.contactPresence = contactPresence
} else { } else {
self.contactPresence.accept(false) self.contactPresence.accept(false)
...@@ -637,7 +637,7 @@ extension ConversationViewModel { ...@@ -637,7 +637,7 @@ extension ConversationViewModel {
private func subscribePresence() { private func subscribePresence() {
if let contactPresence = self.presenceService if let contactPresence = self.presenceService
.contactPresence[self.conversation.value.hash] { .getSubscriptionsForContact(contactId: self.conversation.value.hash) {
self.contactPresence = contactPresence self.contactPresence = contactPresence
} else { } else {
self.contactPresence.accept(false) self.contactPresence.accept(false)
......
...@@ -26,7 +26,8 @@ class PresenceService { ...@@ -26,7 +26,8 @@ class PresenceService {
private let presenceAdapter: PresenceAdapter private let presenceAdapter: PresenceAdapter
private let log = SwiftyBeaver.self private let log = SwiftyBeaver.self
var contactPresence: [String: BehaviorRelay<Bool>] private var contactPresence: [String: BehaviorRelay<Bool>]
private let presenceQueue = DispatchQueue(label: "com.presenceQueue", qos: .background) // used to protect access to contactPresence[]
private let responseStream = PublishSubject<ServiceEvent>() private let responseStream = PublishSubject<ServiceEvent>()
var sharedResponseStream: Observable<ServiceEvent> var sharedResponseStream: Observable<ServiceEvent>
...@@ -41,56 +42,68 @@ class PresenceService { ...@@ -41,56 +42,68 @@ class PresenceService {
PresenceAdapter.delegate = self PresenceAdapter.delegate = self
} }
func getSubscriptionsForContact(contactId: String) -> BehaviorRelay<Bool>? {
var value: BehaviorRelay<Bool>?
presenceQueue.sync {[weak self] in
value = self?.contactPresence[contactId]
}
return value
}
func subscribeBuddies(withAccount accountId: String, func subscribeBuddies(withAccount accountId: String,
withContacts contacts: [ContactModel], withContacts contacts: [ContactModel],
subscribe: Bool) { subscribe: Bool) {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let self = self else { return }
for contact in contacts where !contact.banned { for contact in contacts where !contact.banned {
self.subscribeBuddy(withAccountId: accountId, self.subscribeBuddy(withAccountId: accountId,
withUri: contact.hash, withUri: contact.hash,
withFlag: subscribe) withFlag: subscribe)
} }
} }
}
func subscribeBuddy(withAccountId accountId: String, func subscribeBuddy(withAccountId accountId: String,
withUri uri: String, withUri uri: String,
withFlag flag: Bool) { withFlag flag: Bool) {
if flag && contactPresence[uri] != nil { presenceQueue.async { [weak self] in
guard let self = self else { return }
if flag && self.contactPresence[uri] != nil {
// already subscribed // already subscribed
return return
} }
presenceAdapter.subscribeBuddy(withURI: uri, withAccountId: accountId, withFlag: flag) self.presenceAdapter.subscribeBuddy(withURI: uri, withAccountId: accountId, withFlag: flag)
if !flag { if !flag {
contactPresence[uri] = nil self.contactPresence[uri] = nil
return return
} }
if let presenceForContact = contactPresence[uri] { if let presenceForContact = self.contactPresence[uri] {
presenceForContact.accept(false) presenceForContact.accept(false)
return return
} }
let observableValue = BehaviorRelay<Bool>(value: false) let observableValue = BehaviorRelay<Bool>(value: false)
contactPresence[uri] = observableValue self.contactPresence[uri] = observableValue
DispatchQueue.global(qos: .background).async {
var event = ServiceEvent(withEventType: .presenseSubscribed) var event = ServiceEvent(withEventType: .presenseSubscribed)
event.addEventInput(.accountId, value: accountId) event.addEventInput(.accountId, value: accountId)
event.addEventInput(.uri, value: uri) event.addEventInput(.uri, value: uri)
self.responseStream.onNext(event) self.responseStream.onNext(event)
} }
} }
}
}
extension PresenceService: PresenceAdapterDelegate { extension PresenceService: PresenceAdapterDelegate {
func newBuddyNotification(withAccountId accountId: String, func newBuddyNotification(withAccountId accountId: String,
withUri uri: String, withUri uri: String,
withStatus status: Int, withStatus status: Int,
withLineStatus lineStatus: String) { withLineStatus lineStatus: String) {
presenceQueue.async {[weak self] in
guard let self = self else { return }
let value = status > 0 ? true : false let value = status > 0 ? true : false
if let presenceForContact = contactPresence[uri] { if let presenceForContact = self.contactPresence[uri] {
presenceForContact.accept(value) presenceForContact.accept(value)
return return
} }
let observableValue = BehaviorRelay<Bool>(value: value) let observableValue = BehaviorRelay<Bool>(value: value)
contactPresence[uri] = observableValue self.contactPresence[uri] = observableValue
log.debug("newBuddyNotification: uri=\(uri), status=\(status)") }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment