Skip to content

Commit

Permalink
Introduce new configure interface with non-optional completion
Browse files Browse the repository at this point in the history
Commit also includes several improvements:
- filtering out empty queueIds;
- depracation of old `configure` method;
- replace checking interactor existance with configuration one to ensure SDK is configured;
- improve error handling in TestingApp

MOB-2784
  • Loading branch information
Egor Egorov authored and EgorovEI committed Nov 6, 2023
1 parent 21c1abf commit 6e1327f
Show file tree
Hide file tree
Showing 13 changed files with 208 additions and 114 deletions.
9 changes: 6 additions & 3 deletions GliaWidgets/Public/Glia/Glia+StartEngagement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extension Glia {
/// - `GliaError.engagementExists
/// - `GliaError.sdkIsNotConfigured`
///
/// - Important: Note, that `configure(with:queueID:visitorContext:)` must be called initially prior to this method,
/// - Important: Note, that `configure(with:uiConfig:assetsBuilder:completion:)` must be called initially prior to this method,
/// because `GliaError.sdkIsNotConfigured` will occur otherwise.
///
public func startEngagement(
Expand All @@ -28,7 +28,10 @@ extension Glia {
features: Features = .all,
sceneProvider: SceneProvider? = nil
) throws {
guard !queueIds.isEmpty else { throw GliaError.startingEngagementWithNoQueueIdsIsNotAllowed }
let trimmedQueueIds = queueIds
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
guard !trimmedQueueIds.isEmpty else { throw GliaError.startingEngagementWithNoQueueIdsIsNotAllowed }
guard engagement == .none else { throw GliaError.engagementExists }
guard let configuration = self.configuration else { throw GliaError.sdkIsNotConfigured }
if let engagement = environment.coreSdk.getCurrentEngagement(),
Expand All @@ -39,7 +42,7 @@ extension Glia {
// Creates interactor instance
let createdInteractor = setupInteractor(
configuration: configuration,
queueIds: queueIds
queueIds: trimmedQueueIds
)

theme.chat.connect.queue.firstText = companyName(
Expand Down
23 changes: 22 additions & 1 deletion GliaWidgets/Public/Glia/Glia.Deprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import GliaCoreSDK

extension Glia {
/// Deprecated.
@available(*, unavailable, message: "Use configure(with:queueId:uiConfig:assetsBuilder:completion:) instead.")
@available(*, unavailable, message: "Use configure(with:uiConfig:assetsBuilder:completion:) instead.")
public func configure(
with configuration: Configuration,
queueId: String,
Expand Down Expand Up @@ -184,6 +184,27 @@ extension Glia {
sceneProvider: sceneProvider
)
}

/// Deprecated, use the `configure` method that provides a `Result` in its completion instead.
@available(*, deprecated, message: "Use the `configure` method that provides a `Result` in its completion instead.")
public func configure(
with configuration: Configuration,
uiConfig: RemoteConfiguration? = nil,
assetsBuilder: RemoteConfiguration.AssetsBuilder = .standard,
completion: (() -> Void)? = nil
) throws {
try configure(
with: configuration,
uiConfig: uiConfig,
assetsBuilder: assetsBuilder
) { result in
defer {
completion?()
}
guard case let .failure(error) = result else { return }
debugPrint("💥 Core SDK configuration is not valid. Unexpected error='\(error)'.")
}
}
}

extension Glia.Authentication {
Expand Down
2 changes: 1 addition & 1 deletion GliaWidgets/Public/Glia/Glia.RemoteConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extension Glia {
/// - `GliaError.engagementExists
/// - `GliaError.sdkIsNotConfigured`
///
/// - Important: Note, that `configure(with:queueID:visitorContext:)` must be called initially prior to this method,
/// - Important: Note, that `configure(with:uiConfig:assetsBuilder:completion:)` must be called initially prior to this method,
/// because `GliaError.sdkIsNotConfigured` will occur otherwise.
///
public func startEngagementWithConfig(
Expand Down
47 changes: 27 additions & 20 deletions GliaWidgets/Public/Glia/Glia.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,25 @@ public class Glia {
/// Setup SDK using specific engagement configuration without starting the engagement.
/// - Parameters:
/// - configuration: Engagement configuration.
/// - visitorContext: Visitor context.
/// - uiConfig: Remote UI configuration.
/// - assetsBuilder: Provides assets for remote configuration.
/// - completion: Optional completion handler that will be fired once configuration is complete.
/// Passing `nil` will defer configuration. Passing closure will start configuration immediately.
/// - completion: Completion handler that will be fired once configuration is complete.
public func configure(
with configuration: Configuration,
uiConfig: RemoteConfiguration? = nil,
assetsBuilder: RemoteConfiguration.AssetsBuilder = .standard,
completion: (() -> Void)? = nil
completion: @escaping (Result<Void, Error>) -> Void
) throws {
guard environment.coreSdk.getCurrentEngagement() == nil else {
throw GliaError.configuringDuringEngagementIsNotAllowed
}
self.uiConfig = uiConfig
self.assetsBuilder = assetsBuilder
self.configuration = configuration
// `configuration` should be erased to avoid cases when integrators
// call `configure` and `startEngagement` asynchronously, and
// second-time configuration has not been complete, but `startEngagement`
// is fired and SDK has previous `configuration`.
self.configuration = nil

self.callVisualizer.delegate = { action in
switch action {
Expand All @@ -129,10 +131,15 @@ public class Glia {
}
}

// TODO: - Non-optional completion will be added in MOB-2784
do {
try environment.coreSDKConfigurator.configureWithConfiguration(configuration) { [weak self] in
guard let self else { return }
try environment.coreSDKConfigurator.configureWithConfiguration(configuration) { [weak self] result in
guard let self else { return }
switch result {
case .success:
// Storing `configuration` needs to be done once configuring SDK is complete
// Otherwise integrator can call `configure` and `startEngagement`
// asynchronously, without waiting configuration completion.
self.configuration = configuration

let getRemoteString = self.environment.coreSdk.localeProvider.getRemoteString
self.stringProviding = .init(getRemoteString: getRemoteString)

Expand All @@ -141,11 +148,11 @@ public class Glia {
self.setupInteractor(configuration: configuration)
}

completion?()
completion(.success(()))
case let .failure(error):
debugPrint("💥 Core SDK configuration is not valid. Unexpected error='\(error)'.")
completion(.failure(error))
}
} catch {
self.configuration = nil
debugPrint("💥 Core SDK configuration is not valid. Unexpected error='\(error)'.")
}
}

Expand Down Expand Up @@ -208,11 +215,11 @@ public class Glia {
/// - `GliaCoreSDK.ConfigurationError.invalidEnvironment`
/// - `GliaError.sdkIsNotConfigured`
///
/// - Important: Note, that in case of engagement has not been started yet, `configure(with:queueID:visitorContext:)` must be called initially prior to this method,
/// - Important: Note, that in case of engagement has not been started yet, `configure(with:uiConfig:assetsBuilder:completion:)` must be called initially prior to this method,
/// because `GliaError.sdkIsNotConfigured` will occur otherwise.
///
public func fetchVisitorInfo(completion: @escaping (Result<GliaCore.VisitorInfo, Error>) -> Void) {
guard interactor != nil else {
guard configuration != nil else {
completion(.failure(GliaError.sdkIsNotConfigured))
return
}
Expand Down Expand Up @@ -242,14 +249,14 @@ public class Glia {
/// - `GliaCoreSDK.ConfigurationError.invalidEnvironment`
/// - `GliaError.sdkIsNotConfigured`
///
/// - Important: Note, that in case of engagement has not been started yet, `configure(with:queueID:visitorContext:)` must be called initially prior to this method,
/// - Important: Note, that in case of engagement has not been started yet, `configure(with:uiConfig:assetsBuilder:completion:)` must be called initially prior to this method,
/// because `GliaError.sdkIsNotConfigured` will occur otherwise.
///
public func updateVisitorInfo(
_ info: VisitorInfoUpdate,
completion: @escaping (Result<Bool, Error>) -> Void
) {
guard interactor != nil else {
guard configuration != nil else {
completion(.failure(GliaError.sdkIsNotConfigured))
return
}
Expand All @@ -263,7 +270,7 @@ public class Glia {
rootCoordinator = nil
}

guard interactor != nil else {
guard configuration != nil else {
completion(.failure(GliaError.sdkIsNotConfigured))
return
}
Expand All @@ -278,10 +285,10 @@ public class Glia {
/// It is also possible to monitor Queues changes with [subscribeForUpdates](x-source-tag://subscribeForUpdates) method.
/// If the request is unsuccessful for any reason then the completion will have an Error.
/// - Parameters:
/// - completion: A callback that will return the Result struct with `Queue` list or `GliaCoreError`
/// - completion: A callback that will return the Result struct with `Queue` list or `GliaCoreError`.
///
public func listQueues(_ completion: @escaping (Result<[Queue], Error>) -> Void) {
guard interactor != nil else {
guard configuration != nil else {
completion(.failure(GliaError.sdkIsNotConfigured))
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct CoreSdkClient {

typealias ConfigureWithConfiguration = (
_ sdkConfiguration: Self.Salemove.Configuration,
_ completion: (() -> Void)?
_ completion: @escaping Self.ConfigureCompletion
) -> Void
var configureWithConfiguration: ConfigureWithConfiguration

Expand Down Expand Up @@ -249,4 +249,5 @@ extension CoreSdkClient {
typealias Cancellable = GliaCore.Cancellable
typealias ReactiveSwift = GliaCoreDependency.ReactiveSwift
typealias SendMessagePayload = GliaCoreSDK.SendMessagePayload
typealias ConfigureCompletion = GliaCoreSDK.GliaCore.ConfigureCompletion
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

struct CoreSDKConfigurator {
var configureWithInteractor: CoreSdkClient.ConfigureWithInteractor
var configureWithConfiguration: (Configuration, (() -> Void)?) throws -> Void
var configureWithConfiguration: (Configuration, @escaping (Result<Void, Error>) -> Void) throws -> Void
}

extension CoreSDKConfigurator {
Expand All @@ -16,9 +16,7 @@ extension CoreSDKConfigurator {
authorizingMethod: configuration.authorizationMethod.coreAuthorizationMethod,
pushNotifications: configuration.pushNotifications.coreSdk
)
coreSdk.configureWithConfiguration(sdkConfiguration) {
completion?()
}
coreSdk.configureWithConfiguration(sdkConfiguration, completion)
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ extension CallViewController {
let queueId = UUID.mock.uuidString
var interactorEnv = Interactor.Environment.mock
interactorEnv.coreSdk.configureWithConfiguration = { _, callback in
callback?()
callback(.success(()))
}
let interactor = Interactor.mock(
queueId: queueId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ extension ChatViewController {
chatViewModelEnv.fetchChatHistory = { $0(.success([])) }
var interEnv = Interactor.Environment.mock
interEnv.coreSdk.configureWithConfiguration = { _, callback in
callback?()
callback(.success(()))
}
let interactor = Interactor.mock(environment: interEnv)
let generateUUID = UUID.incrementing
Expand Down Expand Up @@ -540,7 +540,7 @@ extension ChatViewController {
chatViewModelEnv.fetchChatHistory = { $0(.success(messages)) }
var interEnv = Interactor.Environment.mock
interEnv.coreSdk.configureWithConfiguration = { _, callback in
callback?()
callback(.success(()))
}
let interactor = Interactor.mock(environment: interEnv)
let chatViewModel = ChatViewModel.mock(interactor: interactor, environment: chatViewModelEnv)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ class ChatViewModelTests: XCTestCase {
// we use the mocked one, which doesn't execute the completion,
// `sendMessageWithAttachment` will not be executed.
environment.coreSdk.configureWithConfiguration = { _, completion in
completion?()
completion(.success(()))
}

let viewModel: ChatViewModel = .mock(
Expand Down Expand Up @@ -595,7 +595,7 @@ class ChatViewModelTests: XCTestCase {
let interactor = Interactor.failing
interactor.environment.gcd.mainQueue.asyncIfNeeded = { $0() }
interactor.environment.coreSdk.configureWithInteractor = { _ in }
interactor.environment.coreSdk.configureWithConfiguration = { _, callback in callback?() }
interactor.environment.coreSdk.configureWithConfiguration = { _, callback in callback(.success(())) }
interactor.environment.coreSdk.sendMessagePreview = { _, _ in }
interactor.environment.coreSdk.sendMessageWithMessagePayload = { _, completion in
completion(.success(.mock(id: expectedMessageId)))
Expand Down Expand Up @@ -645,7 +645,7 @@ class ChatViewModelTests: XCTestCase {
let interactor = Interactor.failing
interactor.environment.gcd.mainQueue.asyncIfNeeded = { $0() }
interactor.environment.coreSdk.configureWithInteractor = { _ in }
interactor.environment.coreSdk.configureWithConfiguration = { _, callback in callback?() }
interactor.environment.coreSdk.configureWithConfiguration = { _, callback in callback(.success(())) }
interactor.environment.coreSdk.sendMessagePreview = { _, _ in }
interactor.environment.coreSdk.sendMessageWithMessagePayload = { [weak viewModel] _, completion in
// Deliver message via socket before REST API response.
Expand Down
Loading

0 comments on commit 6e1327f

Please sign in to comment.