Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use queues from QueuesMonitor to determine Secure Conversations availability #1102

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,25 @@ extension SecureConversations {
for queueIds: [String],
completion: @escaping CompletionResult
) {
environment.listQueues { queues, error in
if let error = error {
// if provided queueIds array contains invalid ids,
// then log a warning message.
let invalidIds = queueIds.filter { UUID(uuidString: $0) == nil }
if !invalidIds.isEmpty {
environment.log.warning("Queue ID array for Secure Messaging contains invalid queue IDs: \(invalidIds).")
}

environment.queuesMonitor.fetchAndMonitorQueues(queuesIds: queueIds) { result in
switch result {
case .success(let queues):
self.checkQueues(fetchedQueues: queues, completion: completion)
case .failure(let error):
completion(.failure(error))
return
}

self.checkQueues(
queueIds: queueIds,
fetchedQueues: queues,
completion: completion
)
}
}

private func checkQueues(
queueIds: [String],
fetchedQueues: [CoreSdkClient.Queue]?,
fetchedQueues: [CoreSdkClient.Queue],
completion: (Result<Status, CoreSdkClient.SalemoveError>) -> Void
) {
guard environment.isAuthenticated() else {
Expand All @@ -35,50 +37,7 @@ extension SecureConversations {
return
}

guard let queues = fetchedQueues else {
// If no queue fetched from the server,
// return `.unavailable(.emptyQueue)`
completion(.success(.unavailable(.emptyQueue)))
return
}

// if provided queueIds array contains invalid ids,
// then log a warning message.
let invalidIds = queueIds.filter { UUID(uuidString: $0) == nil }
if !invalidIds.isEmpty {
environment.log.warning("Queue ID array for Secure Messaging contains invalid queue IDs: \(invalidIds).")
}

let matchedQueues = queues.filter { queueIds.contains($0.id) }

guard !matchedQueues.isEmpty else {
// if provided queue ids array is not empty, but ids do not
// match with any queue, then log a warning message
if !queueIds.isEmpty {
environment.log.warning("Provided queue IDs do not match with any queue.")
}
// If no passed queueId is matched with fetched queues,
// then check default queues instead
let defaultQueues = queues.filter(\.isDefault)
// Filter queues supporting `messaging` and have status other than `closed`
let filteredQueues = defaultQueues.filter(defaultPredicate)

if filteredQueues.isEmpty {
environment.log.warning("No default queues that have status other than closed and support messaging were found.")
// if no default queue supports `messaging` and
// have status other than `closed`, return `.unavailable(.emptyQueue)`
completion(.success(.unavailable(.emptyQueue)))
return
}

// Otherwise, return default queue ids
let defaultQueueIds = defaultQueues.map(\.id)
environment.log.info("Secure Messaging is available using queues that are set as **Default**.")
completion(.success(.available(queueIds: defaultQueueIds)))
return
}

let filteredQueues = matchedQueues.filter(defaultPredicate)
let filteredQueues = fetchedQueues.filter(defaultPredicate)

// Check if matched queues match support `messaging` and
// have status other than `closed`
Expand All @@ -87,16 +46,17 @@ extension SecureConversations {
completion(.success(.unavailable(.emptyQueue)))
return
}
let queueIds = filteredQueues.map { $0.id }

environment.log.info("Secure Messaging is available in queues with IDs: \(queueIds).")
completion(.success(.available(queueIds: queueIds)))
}

private var defaultPredicate: (CoreSdkClient.Queue) -> Bool {
return {
$0.state.status != .closed &&
$0.state.media.contains(CoreSdkClient.MediaType.messaging)
}
{
$0.state.status != .closed &&
$0.state.media.contains(CoreSdkClient.MediaType.messaging)
}
}
}
}
Expand All @@ -106,6 +66,7 @@ extension SecureConversations.Availability {
var listQueues: CoreSdkClient.ListQueues
var isAuthenticated: () -> Bool
var log: CoreSdkClient.Logger
var queuesMonitor: QueuesMonitor
}
}

Expand Down Expand Up @@ -139,15 +100,17 @@ extension SecureConversations.Availability.Environment {
.init(
listQueues: environment.listQueues,
isAuthenticated: environment.isAuthenticated,
log: environment.log
log: environment.log,
queuesMonitor: environment.queuesMonitor
)
}

static func create(with environment: SecureConversations.Coordinator.Environment) -> Self {
.init(
listQueues: environment.listQueues,
isAuthenticated: environment.isAuthenticated,
log: environment.log
log: environment.log,
queuesMonitor: environment.queuesMonitor
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extension SecureConversations.Coordinator {
var cameraDeviceManager: CoreSdkClient.GetCameraDeviceManageable
var flipCameraButtonStyle: FlipCameraButtonStyle
var alertManager: AlertManager
var queuesMonitor: QueuesMonitor
}
}

Expand Down Expand Up @@ -111,7 +112,8 @@ extension SecureConversations.Coordinator.Environment {
maximumUploads: environment.maximumUploads,
cameraDeviceManager: environment.cameraDeviceManager,
flipCameraButtonStyle: environment.flipCameraButtonStyle,
alertManager: environment.alertManager
alertManager: environment.alertManager,
queuesMonitor: environment.queuesMonitor
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extension ChatCoordinator {
var cameraDeviceManager: CoreSdkClient.GetCameraDeviceManageable
var flipCameraButtonStyle: FlipCameraButtonStyle
var alertManager: AlertManager
var queuesMonitor: QueuesMonitor
}
}

Expand Down Expand Up @@ -88,7 +89,8 @@ extension ChatCoordinator.Environment {
maximumUploads: environment.maximumUploads,
cameraDeviceManager: environment.cameraDeviceManager,
flipCameraButtonStyle: environment.flipCameraButtonStyle,
alertManager: environment.alertManager
alertManager: environment.alertManager,
queuesMonitor: environment.queuesMonitor
)
}

Expand Down Expand Up @@ -132,7 +134,8 @@ extension ChatCoordinator.Environment {
maximumUploads: environment.maximumUploads,
cameraDeviceManager: environment.cameraDeviceManager,
flipCameraButtonStyle: environment.flipCameraButtonStyle,
alertManager: environment.alertManager
alertManager: environment.alertManager,
queuesMonitor: environment.queuesMonitor
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ extension EngagementCoordinator.Environment {
.mock
},
flipCameraButtonStyle: .nop,
alertManager: .mock()
alertManager: .mock(),
queuesMonitor: .mock()
)
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extension EngagementCoordinator {
var cameraDeviceManager: CoreSdkClient.GetCameraDeviceManageable
var flipCameraButtonStyle: FlipCameraButtonStyle
var alertManager: AlertManager
var queuesMonitor: QueuesMonitor
}
}

Expand Down Expand Up @@ -95,7 +96,8 @@ extension EngagementCoordinator.Environment {
maximumUploads: maximumUploads,
cameraDeviceManager: environment.cameraDeviceManager,
flipCameraButtonStyle: viewFactory.theme.call.flipCameraButtonStyle,
alertManager: alertManager
alertManager: alertManager,
queuesMonitor: environment.queuesMonitor
)
}
}
7 changes: 3 additions & 4 deletions GliaWidgets/Sources/EntryWidget/EntryWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public extension EntryWidget {
func hide() {
hostedViewController?.dismiss(animated: true, completion: nil)
hostedViewController = nil
environment.queuesMonitor.stopMonitoring()
}
}

Expand Down Expand Up @@ -133,14 +132,14 @@ private extension EntryWidget {

viewModel.retryMonitoring = { [weak self] in
self?.viewState = .loading
self?.environment.queuesMonitor.startMonitoring(queuesIds: self?.queueIds ?? [])
self?.environment.queuesMonitor.fetchAndMonitorQueues(queuesIds: self?.queueIds ?? [])
}

return viewModel
}

func showView(in parentView: UIView) {
self.environment.queuesMonitor.startMonitoring(queuesIds: self.queueIds)
self.environment.queuesMonitor.fetchAndMonitorQueues(queuesIds: self.queueIds)
parentView.subviews.forEach { $0.removeFromSuperview() }
let model = makeViewModel(showHeader: false)
let view = makeView(model: model)
Expand All @@ -160,7 +159,7 @@ private extension EntryWidget {
}

func showSheet(in parentViewController: UIViewController) {
self.environment.queuesMonitor.startMonitoring(queuesIds: self.queueIds)
self.environment.queuesMonitor.fetchAndMonitorQueues(queuesIds: self.queueIds)
let model = makeViewModel(showHeader: true)
let view = makeView(model: model).accessibilityAction(.escape, {
self.hide()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extension Glia.Environment {
snackBar: .mock,
processInfo: .mock(),
cameraDeviceManager: { .mock },
queuesMonitor: .mock,
queuesMonitor: .mock(),
isAuthenticated: { false }
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extension Interactor {
struct Environment {
var coreSdk: CoreSdkClient
var queuesMonitor: QueuesMonitor
var gcd: GCD
var log: CoreSdkClient.Logger
}
Expand All @@ -13,6 +14,7 @@ extension Interactor.Environment {
) -> Self {
.init(
coreSdk: environment.coreSdk,
queuesMonitor: environment.queuesMonitor,
gcd: environment.gcd,
log: log
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
extension Interactor.Environment {
static let mock = Self(
coreSdk: .mock,
queuesMonitor: .mock(),
gcd: .mock,
log: .mock
)
Expand Down
1 change: 1 addition & 0 deletions GliaWidgets/Sources/Interactor/Interactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class Interactor {
extension Interactor {
func setQueuesIds(_ queueIds: [String]) {
self.queueIds = queueIds
environment.queuesMonitor.fetchAndMonitorQueues(queuesIds: queueIds)
}

func enqueueForEngagement(
Expand Down
73 changes: 54 additions & 19 deletions GliaWidgets/Sources/QueuesMonitor/QueuesMonitor.Live.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class QueuesMonitor {

@Published private(set) var state: State = .idle

/// Declared as internal var for unit tests purposes
// Declared as internal var for unit tests purposes
var environment: Environment
private var subscriptionId: String? {
_subscriptionId.value
Expand All @@ -27,40 +27,75 @@ final class QueuesMonitor {
self.environment = environment
}

func startMonitoring(queuesIds: [String]) {
/// Fetches all available site's queues and initiates queues monitoring for given queues IDs.
///
/// - Parameters:
/// - queuesIds: The queues IDs that will be monitored.
/// - fetchedQueuesCompletion: Returns fetched queues result for given `queuesIds`
/// if no queues were found among site's queues returns default queues.
///
func fetchAndMonitorQueues(
queuesIds: [String] = [],
fetchedQueuesCompletion: ((Result<[Queue], GliaCoreError>) -> Void)? = nil
) {
stopMonitoring()

fetchQueues(queuesIds: queuesIds) { [weak self] result in
if case let .success(queues) = result {
self?.observeQueuesUpdates(queues)
}
fetchedQueuesCompletion?(result)
}
}

/// Stops monitoring queues.
func stopMonitoring() {
if let subscriptionId {
igorkravchenko marked this conversation as resolved.
Show resolved Hide resolved
environment.unsubscribeFromUpdates(subscriptionId) { [weak self] error in
self?.state = .failed(error)
}
}
}
}

private extension QueuesMonitor {
func fetchQueues(queuesIds: [String], completion: @escaping (Result<[Queue], GliaCoreError>) -> Void) {
environment.listQueues { [weak self] queues, error in
guard let self else {
return
}
if let error {
self.state = .failed(error)
completion(.failure(error))
return
}

if let queues {
let integratorsQueues = queues.filter { queuesIds.contains($0.id) }

let observedQueues = integratorsQueues.isEmpty ? queues.filter { $0.isDefault } : integratorsQueues
let observedQueues = evaluateQueues(queuesIds: queuesIds, fetchedQueues: queues)

self.state = .updated(observedQueues)
self.observeQueuesUpdates(observedQueues)

self._observedQueues.setValue(observedQueues)
return
}
self.state = .updated(observedQueues)
self._observedQueues.setValue(observedQueues)
completion(.success(observedQueues))
}
}

func stopMonitoring() {
if let subscriptionId {
environment.unsubscribeFromUpdates(subscriptionId) { [weak self] error in
self?.state = .failed(error)
}
func evaluateQueues(queuesIds: [String], fetchedQueues: [Queue]?) -> [Queue] {
guard let queues = fetchedQueues else {
return []
}

let matchedQueues = queues.filter { queuesIds.contains($0.id) }

guard !matchedQueues.isEmpty else {
// If no passed queueId is matched with fetched queues,
// then check default queues instead
let defaultQueues = queues.filter(\.isDefault)

return defaultQueues
}

return matchedQueues
}
}

private extension QueuesMonitor {
func updateQueue(_ queue: Queue) {
_observedQueues.withValue { queues in
guard let indexToChange = queues.firstIndex(where: { $0.id == queue.id }) else {
Expand Down
Loading
Loading