diff --git a/MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift index 59095e2..67a6a9b 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift @@ -30,21 +30,21 @@ open class ActionActionsHandler: MVMCoreJSONActionHandlerProtocol { } } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionActionsModel else { return } if model.concurrent { // TODO: inspect warning. await withThrowingTaskGroup(of: Void.self) { group in for action in model.actions { group.addTask{ - try await MVMCoreActionHandler.shared()?.handleAction(with: action, additionalData: additionalData, delegateObject: delegateObject) + try await MVMCoreActionHandler.handleActionCheckingDelegate(with: action, additionalData: additionalData, delegateObject: delegateObject) } } } } else { for action in model.actions { try Task.checkCancellation() - try await MVMCoreActionHandler.shared()?.handleAction(with: action, additionalData: additionalData, delegateObject: delegateObject) + try await MVMCoreActionHandler.handleActionCheckingDelegate(with: action, additionalData: additionalData, delegateObject: delegateObject) } } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift index aa80a9a..6e93fd4 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift @@ -16,11 +16,11 @@ open class ActionBackHandler: MVMCoreJSONActionHandlerProtocol { // Legacy code will use the old handler function and break the task chain here. closure(JSON, additionalData) } else { - try await performAction(model, delegateObject: delegateObject, additionalData: additionalData) + try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData) } } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { await withCheckedContinuation { continuation in Task(priority: .userInitiated) { await MVMCoreNavigationHandler.shared()?.removeCurrentViewController(true, completionHandler: { diff --git a/MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift index 7010746..2d5d530 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift @@ -11,7 +11,7 @@ import Foundation open class ActionCallHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionCallModel else { return } // https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/PhoneLinks/PhoneLinks.html#//apple_ref/doc/uid/TP40007899-CH6-SW1 try await ActionOpenUrlHandler.openURL(with: "tel://\(model.callNumber)") diff --git a/MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift index 7f5169c..6dbe413 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift @@ -15,6 +15,6 @@ open class ActionCancelHandler: MVMCoreJSONActionHandlerProtocol { delegateObject?.actionDelegate?.handleCancel?(JSON, additionalData: additionalData) } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift index 7231eb2..5e73ba3 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift @@ -26,7 +26,7 @@ open class ActionContactHandler: NSObject, MVMCoreActionHandlerProtocol, CNConta } } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws { guard let model = model as? ActionContactModel else { return } switch model.approach { diff --git a/MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift b/MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift index eeb5734..fd9ad8c 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift @@ -9,8 +9,8 @@ import Foundation public protocol ActionDelegateProtocol: MVMCoreActionDelegateProtocol { - /// Allows the delegate to cancel the action. - func shouldPerform(action: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) -> Bool + /// Asks the delegate to perform the action. + func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws /// Allows the delegate to handle any custom actions that are not registered with the Action Handler. func handlesUnknownAction(for model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws -> Bool @@ -18,8 +18,8 @@ public protocol ActionDelegateProtocol: MVMCoreActionDelegateProtocol { public extension ActionDelegateProtocol { - func shouldPerform(action: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) -> Bool { - return true + func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws { + try await MVMCoreActionHandler.shared()?.handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject) } func handlesUnknownAction(for model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws -> Bool { diff --git a/MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift index 30e5780..c46afcd 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift @@ -11,5 +11,5 @@ import Foundation open class ActionNoopHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {} + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {} } diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift index f4f2e98..8c747c9 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift @@ -49,7 +49,7 @@ open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol { } } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionOpenPageModel else { return } do { let json = try MVMCoreActionHandler.convertActionToJSON(model) diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift index 904e712..f917fb5 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift @@ -24,7 +24,7 @@ extension String { open class ActionOpenSMSHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionOpenSMSModel else { return } // https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/SMSLinks/SMSLinks.html#:~:text=Note%3A%20SMS%20text%20links%20are,number%20of%20the%20SMS%20message. let string = try "sms:\(model.phoneNumber)&body=\(model.message ?? "")".addingPercentEncodingThrowable(withAllowedCharacters: CharacterSet.urlQueryAllowed) diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift index b731613..b38de51 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift @@ -63,10 +63,10 @@ open class ActionOpenUrlHandler: MVMCoreJSONActionHandlerProtocol { } open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { - try await performAction(model, delegateObject: delegateObject, additionalData: additionalData) + try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData) } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionOpenUrlModel else { return } // Try loading the app url first, otherwise fall back to browser url. diff --git a/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitHandler.swift index 4a56e7a..9fd12d4 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitHandler.swift @@ -17,10 +17,10 @@ open class ActionPreviousSubmitHandler: MVMCoreJSONActionHandlerProtocol { // Conform to MVMCoreJSONActionHandlerProtocol To allow for legacy handleOpenPage delegate open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { json = JSON - try await performAction(model, delegateObject: delegateObject, additionalData: additionalData) + try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData) } - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let loadObject = (delegateObject?.actionDelegate as? MVMCoreViewControllerProtocol)?.loadObject, let previousRequest = loadObject?.requestParameters else { return } diff --git a/MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift index d2744b6..20e7a90 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift @@ -11,7 +11,7 @@ import Foundation open class ActionRestartHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { guard let model = model as? ActionRestartModel else { return } let _: Void = try await withCheckedThrowingContinuation { continuation in diff --git a/MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift index e1c718d..0e468ce 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift @@ -11,7 +11,7 @@ import Foundation open class ActionSettingHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { try await ActionOpenUrlHandler.openURL(with: await UIApplication.openSettingsURLString) } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift b/MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift index 64fff19..9ae2c94 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift @@ -11,7 +11,7 @@ open class ActionShareHandler: MVMCoreActionHandlerProtocol { required public init() {} - open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws { + open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws { guard let model = model as? ActionShareModel else { return } var shareData: [Any] switch model.sharedType { diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift index a5490de..2dae006 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift @@ -11,10 +11,8 @@ import Foundation /// Handlers that can be registered and used by the MVMCoreActionHandler to handle actions. public protocol MVMCoreActionHandlerProtocol: ModelHandlerProtocol { init() - /// Legacy function to handle actions. - func handleAction(_ model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) - - func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws + + func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws } /// Protocol used to bridge legacy, non model based code. Allows us to keep the original json intact and not lose key values during decode/encode. @@ -23,16 +21,6 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws } -extension MVMCoreActionHandlerProtocol { - - public func handleAction(_ model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) { - } - - public func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { - handleAction(model, additionalData: additionalData, delegateObject: delegateObject) - } -} - @objc open class MVMCoreActionHandler: NSObject { enum ActionError: MVMError, CustomStringConvertible { @@ -50,6 +38,8 @@ extension MVMCoreActionHandlerProtocol { } } + private let jsonKey = "MVMCore.JSON" + /// Returns the action handler stored in the MVMCoreObject @objc(sharedActionHandler) public static func shared() -> Self? { @@ -93,11 +83,6 @@ extension MVMCoreActionHandlerProtocol { } } - /// Handles the error by calling actionDelegate handleActionError, else ActionHandler defaultHandleActionError. - open func handle(errorObject: MVMCoreErrorObject, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) { - delegateObject?.actionDelegate?.handleActionError?(errorObject, additionalData: additionalData) ?? defaultHandleActionError(errorObject, additionalData: additionalData) - } - /// Returns a common description for the error location. @objc public static func getErrorLocation(with delegate: MVMCoreActionDelegateProtocol?, actionType: String) -> String { return "\(String(describing: delegate))_\(actionType)" @@ -105,30 +90,49 @@ extension MVMCoreActionHandlerProtocol { // MARK: - Action Handling + /// Convenience function for letting the actionDelegate handle the action, else the handler handles the action. + public static func handleActionCheckingDelegate(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws { + if let closure = (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction { + try await closure(model, additionalData, delegateObject) + } else { + try await MVMCoreActionHandler.shared()?.handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject) + } + } + + /// Convenience function for letting the actionDelegate handle the action, else the handler handles the action. + @discardableResult + public static func asyncHandleActionCheckingDelegate(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> Task { + return Task(priority: .userInitiated) { + try await handleActionCheckingDelegate(with: model, additionalData: additionalData, delegateObject: delegateObject) + } + } + /// Handle an action with the given model. open func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws { try Task.checkCancellation() + var additionalData = MVMCoreActionHandler.setUUID(additionalData: additionalData) + let json = try additionalData?.removeValue(forKey: jsonKey) as? [AnyHashable : Any] ?? MVMCoreActionHandler.convertActionToJSON(model) - let additionalData = MVMCoreActionHandler.setUUID(additionalData: additionalData) - - // Allow the delegate to intercept. - guard (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.shouldPerform(action: model, additionalData: additionalData, delegateObject: delegateObject) ?? true else { return } + // Log the action + delegateObject?.actionDelegate?.logAction?(withActionInformation: json, additionalData: additionalData) + MVMCoreActionHandler.log(string: "Begin Action: \(model.actionType)", additionalData: additionalData) defer { MVMCoreActionHandler.log(string: "End Action: \(model.actionType)", additionalData: additionalData) } - - // Log the action - logAction(with: model, additionalData: additionalData, delegateObject: delegateObject) do { - MVMCoreActionHandler.log(string: "Begin Action: \(model.actionType)", additionalData: additionalData) let handlerType = try ModelRegistry.getHandler(model) as! MVMCoreActionHandlerProtocol.Type let handler = handlerType.init() - try await handler.performAction(model, delegateObject: delegateObject, additionalData: additionalData) + if let handler = handler as? MVMCoreJSONActionHandlerProtocol { + // Needed until we can remove legacy delegate functions. + try await handler.performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData) + } else { + try await handler.execute(with: model, delegateObject: delegateObject, additionalData: additionalData) + } } catch ModelRegistry.Error.handlerNotMapped { try Task.checkCancellation() // Allows custom handling if there no handler for the action. - guard try await handleUnregisteredAction(with: model, json: model.toJSON()!, additionalData: additionalData, delegateObject: delegateObject) else { + guard try await handleUnregisteredAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) else { MVMCoreActionHandler.log(string: "Failed Action Unknown", additionalData: additionalData) throw ActionError.unknownAction(type: model.actionType) } @@ -138,37 +142,6 @@ extension MVMCoreActionHandlerProtocol { } } - /// Performs the action as a task and returns immediately. - @discardableResult - open func asyncHandleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> Task { - let task = Task(priority: .userInitiated) { - try Task.checkCancellation() - do { - let json = try MVMCoreActionHandler.convertActionToJSON(model) - try await handleAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) - } catch { - try Task.checkCancellation() - let errorObject = getActionErrorObject(for: error, actionType: model.actionType, delegateObject: delegateObject) - handle(errorObject: errorObject, delegateObject: delegateObject, additionalData: additionalData) - } - } - - Task { - //try await Task.sleep(nanoseconds: 1 * 1_000_000_000) - //task.cancel() - } - Task { - let result = await task.result - do { - try result.get() - print("ActionHandler: task done") - } catch { - print("ActionHandler: \(error)") - } - } - return task - } - // MARK: - Subclassables /// Subclass to log the action was fired. @@ -177,6 +150,11 @@ extension MVMCoreActionHandlerProtocol { delegateObject?.actionDelegate?.logAction?(withActionInformation: model.toJSON(), additionalData: additionalData) } + open func defaultHandle(error: Error, model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) { + let errorObject = getActionErrorObject(for: error, actionType: model.actionType, delegateObject: delegateObject) + defaultHandleActionError(errorObject, additionalData: additionalData) + } + /// Logs the error. @objc open func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable: Any]?) { guard error.logError else { return } @@ -186,11 +164,8 @@ extension MVMCoreActionHandlerProtocol { // MARK: - Legacy Holdovers static public func setUUID(additionalData: [AnyHashable: Any]?) -> [AnyHashable: Any]? { - var additionalData = additionalData ?? [:] - if additionalData.optionalStringForKey("Action-UUID") == nil { - additionalData["Action-UUID"] = UUID().uuidString - } - return additionalData + guard getUUID(additionalData: additionalData) == nil else { return additionalData } + return additionalData.dictionaryAdding(key: "Action-UUID", value: UUID().uuidString) } static public func getUUID(additionalData: [AnyHashable: Any]?) -> String? { @@ -212,7 +187,12 @@ extension MVMCoreActionHandlerProtocol { throw ModelRegistry.Error.keyNotFound } let model = try MVMCoreActionHandler.createModel(with: json, delegateObject: delegateObject) - try await handleAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) + if let closure = (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction { + // Allow newer delegates to handle calls from legacy functions + try await closure(model, additionalData, delegateObject) + } else { + try await handleAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) + } } catch { let actionType = json?.optionalStringForKey(KeyActionType) switch error { @@ -227,7 +207,7 @@ extension MVMCoreActionHandlerProtocol { default: MVMCoreActionHandler.log(string: "Failed Action: Error \(error)", additionalData: additionalData) let errorObject = getActionErrorObject(for: error, actionType: actionType ?? "noAction", delegateObject: delegateObject) - handle(errorObject: errorObject, delegateObject: delegateObject, additionalData: additionalData) + delegateObject?.actionDelegate?.handleActionError?(errorObject, additionalData: additionalData) ?? defaultHandleActionError(errorObject, additionalData: additionalData) } } } @@ -245,43 +225,8 @@ extension MVMCoreActionHandlerProtocol { /// Bridges the legacy json using functions and the new model using functions. open func handleAction(with model: ActionModelProtocol, json: [AnyHashable: Any], additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws { try Task.checkCancellation() - let additionalData = MVMCoreActionHandler.setUUID(additionalData: additionalData) - - MVMCoreActionHandler.log(string: "Begin Action: type: \(model.actionType) json: \(String(describing: json))", additionalData: additionalData) - defer { - MVMCoreActionHandler.log(string: "End Action: \(model.actionType)", additionalData: additionalData) - } - - // Allow the delegate to intercept. - guard (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.shouldPerform(action: model, additionalData: additionalData, delegateObject: delegateObject) ?? true else { - MVMCoreActionHandler.log(string: "Action should not be performed: \(model.actionType)", additionalData: additionalData) - return - } - try Task.checkCancellation() - - // Log the action - delegateObject?.actionDelegate?.logAction?(withActionInformation: json, additionalData: additionalData) - - do { - MVMCoreActionHandler.log(string: "Begin Action: \(model.actionType)", additionalData: additionalData) - let handlerType = try ModelRegistry.getHandler(model) as! MVMCoreActionHandlerProtocol.Type - let handler = handlerType.init() - if let handler = handler as? MVMCoreJSONActionHandlerProtocol { - try await handler.performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData) - } else { - try await handler.performAction(model, delegateObject: delegateObject, additionalData: additionalData) - } - } catch ModelRegistry.Error.handlerNotMapped { - try Task.checkCancellation() - // Allows custom handling if there no handler for the action. - guard try await handleUnregisteredAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) else { - MVMCoreActionHandler.log(string: "Failed Action Unknown", additionalData: additionalData) - throw ActionError.unknownAction(type: model.actionType) - } - } catch { - MVMCoreActionHandler.log(string: "Failed Action \(error)", additionalData: additionalData) - throw error - } + let additionalData = additionalData.dictionaryAdding(key: jsonKey, value: json) + try await handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject) } /// Subclass to handle and any actions where a handler was not registered. Checks with the delegate handlesUnknownAction function