Merge remote-tracking branch 'refs/remotes/origin/develop'
This commit is contained in:
commit
d394bbea0e
@ -122,10 +122,6 @@ public extension ClientParameterHandler {
|
|||||||
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.stopLoading(true)
|
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.stopLoading(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return try await withCheckedThrowingContinuation({ continuation in
|
return await getParameters(with: model, requestParameters: requestParameters, actionId: actionId)
|
||||||
getParameters(with: model, requestParameters: requestParameters, actionId: actionId) { parameters in
|
|
||||||
continuation.resume(returning: parameters)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,14 +6,39 @@
|
|||||||
// Copyright © 2021 myverizon. All rights reserved.
|
// Copyright © 2021 myverizon. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@objcMembers open class ClientParameterHandler: NSObject {
|
/// Sample clientParameters
|
||||||
|
///{
|
||||||
|
/// "timeout": 30,
|
||||||
|
/// "list": [
|
||||||
|
/// {
|
||||||
|
/// "type": "currentLocation",
|
||||||
|
/// "inputParameters": {
|
||||||
|
/// "accuracy": 10,
|
||||||
|
/// "timeThreshold": 600
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ]
|
||||||
|
///}
|
||||||
|
/// completionHandler can return flat dictinary or a map. It depends on the paramters handler
|
||||||
|
|
||||||
|
|
||||||
|
@objc open class ClientParameterHandler: NSObject {
|
||||||
|
|
||||||
public static let DefaultTimeout = 30.0
|
public static let DefaultTimeout = 30.0
|
||||||
|
|
||||||
open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> ClientParameterProtocol? {
|
open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> (any ClientParameterProtocol)? {
|
||||||
do {
|
do {
|
||||||
let parameterType = try ModelRegistry.getHandler(clientParameterModel) as! ClientParameterProtocol.Type
|
//Ensure the handlerType return will be initable using ClientParameterHandler
|
||||||
return parameterType.init(clientParameterModel)
|
guard let handlerType = try ModelRegistry.getHandler(clientParameterModel) as? AnyClientParameterProtocol.Type else { throw ClientParameterError.castingError }
|
||||||
|
|
||||||
|
//init the handler
|
||||||
|
let handler = try handlerType.init(clientParameterModel: clientParameterModel)
|
||||||
|
|
||||||
|
//Cast from AnyClientParameterProtocol to AnyClientParameterProtocol, if not throw
|
||||||
|
guard let castedHandler = handler as? any ClientParameterProtocol else { throw ClientParameterError.castingError }
|
||||||
|
|
||||||
|
//Return the any ClientParameterProtocol
|
||||||
|
return castedHandler
|
||||||
} catch {
|
} catch {
|
||||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: #function) {
|
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: #function) {
|
||||||
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
|
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
|
||||||
@ -21,26 +46,13 @@
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
|
open func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
|
||||||
let data = try JSONSerialization.data(withJSONObject: clientParameters)
|
let data = try JSONSerialization.data(withJSONObject: clientParameters)
|
||||||
return try JSONDecoder.create().decode(ClientParameterModel.self, from: data)
|
return try JSONDecoder.create().decode(ClientParameterModel.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample clientParameters
|
@objc
|
||||||
///{
|
|
||||||
/// "timeout": 30,
|
|
||||||
/// "list": [
|
|
||||||
/// {
|
|
||||||
/// "type": "currentLocation",
|
|
||||||
/// "inputParameters": {
|
|
||||||
/// "accuracy": 10,
|
|
||||||
/// "timeThreshold": 600
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ]
|
|
||||||
///}
|
|
||||||
/// completionHandler can return flat dictinary or a map. It depends on the paramters handler
|
|
||||||
open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: Any]?) -> ()) throws {
|
open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: Any]?) -> ()) throws {
|
||||||
guard let clientParameterModel = try getClientParameterModel(clientParameters) else {
|
guard let clientParameterModel = try getClientParameterModel(clientParameters) else {
|
||||||
completionHandler(nil)
|
completionHandler(nil)
|
||||||
@ -49,7 +61,15 @@
|
|||||||
getParameters(with: clientParameterModel, requestParameters: requestParameters, actionId: actionId, completionHandler: completionHandler)
|
getParameters(with: clientParameterModel, requestParameters: requestParameters, actionId: actionId, completionHandler: completionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func getParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: Any]?) -> ()) {
|
open func getParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String) async -> [String: AnyHashable] {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
getParameters(with: model, requestParameters: requestParameters, actionId: actionId) { parameters in
|
||||||
|
continuation.resume(returning: parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: AnyHashable]) -> ()) {
|
||||||
|
|
||||||
let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter")
|
let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter")
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
@ -66,11 +86,12 @@
|
|||||||
var mergedParametersList: [String: AnyHashable] {
|
var mergedParametersList: [String: AnyHashable] {
|
||||||
return returnedList.enumerated().map { (index, element) -> [String: AnyHashable] in
|
return returnedList.enumerated().map { (index, element) -> [String: AnyHashable] in
|
||||||
guard let parameter = element else {
|
guard let parameter = element else {
|
||||||
|
let handler = parameterHandlerList[index]
|
||||||
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterTimeout(
|
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterTimeout(
|
||||||
name: model.list[index].type,
|
name: handler.clientParameterModel.type,
|
||||||
uuid: requestUUID[index],
|
uuid: requestUUID[index],
|
||||||
actionId: actionId))
|
actionId: actionId))
|
||||||
return parameterHandlerList[index].valueOnTimeout()
|
return handler.valueOnTimeout()
|
||||||
}
|
}
|
||||||
return parameter
|
return parameter
|
||||||
}.reduce(into: [String: AnyHashable]()) { partialResult, next in
|
}.reduce(into: [String: AnyHashable]()) { partialResult, next in
|
||||||
@ -81,13 +102,15 @@
|
|||||||
// Setup completion handlers. Barriered to ensure one happens after the other.
|
// Setup completion handlers. Barriered to ensure one happens after the other.
|
||||||
var complete = false
|
var complete = false
|
||||||
let timeoutWorkItem = DispatchWorkItem(qos: .userInitiated) {
|
let timeoutWorkItem = DispatchWorkItem(qos: .userInitiated) {
|
||||||
completionHandler(mergedParametersList);
|
let params = mergedParametersList
|
||||||
|
completionHandler(params);
|
||||||
complete = true
|
complete = true
|
||||||
}
|
}
|
||||||
let completionWorkItem = DispatchWorkItem(qos: .userInitiated) {
|
let completionWorkItem = DispatchWorkItem(qos: .userInitiated) {
|
||||||
timeoutWorkItem.cancel()
|
timeoutWorkItem.cancel()
|
||||||
if !complete { // In the case of firing after timeout.
|
if !complete { // In the case of firing after timeout.
|
||||||
completionHandler(mergedParametersList);
|
let params = mergedParametersList
|
||||||
|
completionHandler(params);
|
||||||
complete = true
|
complete = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,7 +123,7 @@
|
|||||||
let parameterType = parameterHandler.clientParameterModel.type
|
let parameterType = parameterHandler.clientParameterModel.type
|
||||||
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterStartFetch(name: parameterType, uuid: requestUUID[index], actionId: actionId))
|
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterStartFetch(name: parameterType, uuid: requestUUID[index], actionId: actionId))
|
||||||
group.enter()
|
group.enter()
|
||||||
parameterHandler.fetchClientParameters(requestParameters: requestParameters,
|
parameterHandler.fetchClientParametersBridge(requestParameters: requestParameters,
|
||||||
timingOutIn: timeout) { (receivedParameter) in
|
timingOutIn: timeout) { (receivedParameter) in
|
||||||
// Queue the results for merge.
|
// Queue the results for merge.
|
||||||
parametersWorkQueue.async {
|
parametersWorkQueue.async {
|
||||||
@ -124,3 +147,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileprivate extension ClientParameterProtocol {
|
||||||
|
func fetchClientParametersBridge(requestParameters: [String: Any], timingOutIn timeout: TimeInterval, completion: @escaping ([String: AnyHashable]?) -> ()) {
|
||||||
|
Task {
|
||||||
|
let parameters = await fetchClientParameters(requestParameters: requestParameters, timingOutIn: timeout)
|
||||||
|
completion(parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -8,8 +8,13 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
/// A protocol defining models for client parameter fetching handlers.
|
||||||
public protocol ClientParameterModelProtocol: ModelProtocol {
|
public protocol ClientParameterModelProtocol: ModelProtocol {
|
||||||
|
/// The type of client parameter.
|
||||||
var type: String { get }
|
var type: String { get }
|
||||||
|
|
||||||
|
/// A unique identifier for this instance.
|
||||||
|
var id: String { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension ClientParameterModelProtocol {
|
public extension ClientParameterModelProtocol {
|
||||||
|
|||||||
@ -8,32 +8,50 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public protocol ClientParameterProtocol: ModelHandlerProtocol {
|
/// Errors used for ClientParamter
|
||||||
static var name: String { get }
|
public enum ClientParameterError: Error {
|
||||||
|
case castingError
|
||||||
|
case modelMismatch(message: String)
|
||||||
|
}
|
||||||
|
|
||||||
init(_ clientParameterModel: ClientParameterModelProtocol)
|
public protocol AnyClientParameterProtocol {
|
||||||
|
/// Original init using a ClientParameterModelProtocol to get around the self - associatedType issues with ClientParameterProtocol
|
||||||
|
/// - Parameter clientParameterModel: any Model using the ClientParameterModelProtocol
|
||||||
|
init(clientParameterModel: ClientParameterModelProtocol) throws
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A protocol defining client parameter fetching handlers.
|
||||||
|
public protocol ClientParameterProtocol<Model>: ModelHandlerProtocol, AnyClientParameterProtocol {
|
||||||
|
|
||||||
var clientParameterModel: ClientParameterModelProtocol { get set }
|
associatedtype Model: ClientParameterModelProtocol
|
||||||
|
|
||||||
|
var clientParameterModel: Model { get set }
|
||||||
|
init(clientParameterModel: Model)
|
||||||
|
|
||||||
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: TimeInterval, completionHandler:@escaping ([String: AnyHashable]?) -> ())
|
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: TimeInterval) async -> [String: AnyHashable]
|
||||||
|
|
||||||
/// Default parameter for timeout scenarios. It will use the protocol extension method bydefault. Can override to send custom values.
|
/// Default parameter for timeout scenarios. It will use the protocol extension method bydefault. Can override to send custom values.
|
||||||
func valueOnTimeout() -> [String: AnyHashable]
|
func valueOnTimeout() -> [String: AnyHashable]
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension ClientParameterProtocol {
|
public extension ClientParameterProtocol {
|
||||||
|
/// Helper init to convert protocol to specific model. Default Implementation should never be overridden
|
||||||
func valueOnTimeout() -> [String: AnyHashable] {
|
init(clientParameterModel: ClientParameterModelProtocol) throws {
|
||||||
return [Self.name: "failed_to_collect"]
|
// Cast the clientParameterModel to ensure it matches the asscociatedType Model assigned to this Handler.
|
||||||
|
guard let castedModel = clientParameterModel as? Model else {
|
||||||
|
let message = "Expected \(Model.self) but received \(clientParameterModel.type)"
|
||||||
|
throw ClientParameterError.modelMismatch(message: message)
|
||||||
|
}
|
||||||
|
// Call init for the Handler Class and pass in the casted Model.
|
||||||
|
self.init(clientParameterModel: castedModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The handler should call this method to pass the parameter back to the caller.
|
func valueOnTimeout() -> [String: AnyHashable] {
|
||||||
/// If using isFlatMap, you must provide at least 1 element in parameters or it will result in triggering a timeout.
|
return [clientParameterModel.type: "failed_to_collect"]
|
||||||
func returnParameters(_ isFlatMap: Bool, _ parameter: [String: AnyHashable], completionHandler: @escaping ([String: AnyHashable]?) -> ()) {
|
}
|
||||||
if isFlatMap {
|
|
||||||
completionHandler(parameter)
|
/// Convenience function to format the return parameters consistently.
|
||||||
} else {
|
func formatReturnParameters(_ parameter: AnyHashable) -> [String: AnyHashable] {
|
||||||
completionHandler([Self.name: parameter])
|
return [clientParameterModel.type: parameter]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user