From 562332f386697bcdde28e81b77bcef2ca1f205c0 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Fri, 22 Jul 2022 11:42:19 +0100
Subject: [PATCH] Add CmixWaitForMessageDelivery functor

---
 Sources/ElixxirDAppsSDK/Cmix.swift            |  7 +-
 .../CmixWaitForMessageDelivery.swift          | 32 +++++++++
 .../Legacy/MessageDeliveryWaiter.swift        | 71 -------------------
 .../MessageDeliveryCallback.swift             | 58 +++++++++++++++
 .../{Legacy => }/MessageSendReport.swift      |  8 +++
 5 files changed, 103 insertions(+), 73 deletions(-)
 create mode 100644 Sources/ElixxirDAppsSDK/CmixWaitForMessageDelivery.swift
 delete mode 100644 Sources/ElixxirDAppsSDK/Legacy/MessageDeliveryWaiter.swift
 create mode 100644 Sources/ElixxirDAppsSDK/MessageDeliveryCallback.swift
 rename Sources/ElixxirDAppsSDK/{Legacy => }/MessageSendReport.swift (72%)

diff --git a/Sources/ElixxirDAppsSDK/Cmix.swift b/Sources/ElixxirDAppsSDK/Cmix.swift
index 327e630c..527f5069 100644
--- a/Sources/ElixxirDAppsSDK/Cmix.swift
+++ b/Sources/ElixxirDAppsSDK/Cmix.swift
@@ -12,6 +12,7 @@ public struct Cmix {
   public var waitForNetwork: CmixWaitForNetwork
   public var registerClientErrorCallback: CmixRegisterClientErrorCallback
   public var addHealthCallback: CmixAddHealthCallback
+  public var waitForMessageDelivery: CmixWaitForMessageDelivery
 }
 
 extension Cmix {
@@ -27,7 +28,8 @@ extension Cmix {
       stopNetworkFollower: .live(bindingsCmix),
       waitForNetwork: .live(bindingsCmix),
       registerClientErrorCallback: .live(bindingsCmix),
-      addHealthCallback: .live(bindingsCmix)
+      addHealthCallback: .live(bindingsCmix),
+      waitForMessageDelivery: .live(bindingsCmix)
     )
   }
 }
@@ -44,6 +46,7 @@ extension Cmix {
     stopNetworkFollower: .unimplemented,
     waitForNetwork: .unimplemented,
     registerClientErrorCallback: .unimplemented,
-    addHealthCallback: .unimplemented
+    addHealthCallback: .unimplemented,
+    waitForMessageDelivery: .unimplemented
   )
 }
diff --git a/Sources/ElixxirDAppsSDK/CmixWaitForMessageDelivery.swift b/Sources/ElixxirDAppsSDK/CmixWaitForMessageDelivery.swift
new file mode 100644
index 00000000..e326a279
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixWaitForMessageDelivery.swift
@@ -0,0 +1,32 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct CmixWaitForMessageDelivery {
+  public var run: (MessageSendReport, Int, MessageDeliveryCallback) throws -> Void
+
+  public func callAsFunction(
+    report: MessageSendReport,
+    timeoutMS: Int,
+    callback: MessageDeliveryCallback
+  ) throws {
+    try run(report, timeoutMS, callback)
+  }
+}
+
+extension CmixWaitForMessageDelivery {
+  public static func live(_ bindingsCmix: BindingsCmix) -> CmixWaitForMessageDelivery {
+    CmixWaitForMessageDelivery { report, timeoutMS, callback in
+      try bindingsCmix.wait(
+        forMessageDelivery: try report.encode(),
+        mdc: callback.makeBindingsMessageDeliveryCallback(),
+        timeoutMS: timeoutMS
+      )
+    }
+  }
+}
+
+extension CmixWaitForMessageDelivery {
+  public static let unimplemented = CmixWaitForMessageDelivery(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/Legacy/MessageDeliveryWaiter.swift b/Sources/ElixxirDAppsSDK/Legacy/MessageDeliveryWaiter.swift
deleted file mode 100644
index fa6620f2..00000000
--- a/Sources/ElixxirDAppsSDK/Legacy/MessageDeliveryWaiter.swift
+++ /dev/null
@@ -1,71 +0,0 @@
-import Bindings
-
-public struct MessageDeliveryWaiter {
-  public enum Result: Equatable {
-    case delivered(roundResults: [Int])
-    case notDelivered(timedOut: Bool)
-  }
-
-  public var wait: (MessageSendReport, Int, @escaping (Result) -> Void) throws -> Void
-
-  public func callAsFunction(
-    report: MessageSendReport,
-    timeoutMS: Int,
-    callback: @escaping (Result) -> Void
-  ) throws {
-    try wait(report, timeoutMS, callback)
-  }
-}
-
-extension MessageDeliveryWaiter {
-  public static func live(bindingsClient: BindingsCmix) -> MessageDeliveryWaiter {
-    MessageDeliveryWaiter { report, timeoutMS, callback in
-      let encoder = JSONEncoder()
-      let reportData = try encoder.encode(report)
-      try bindingsClient.wait(
-        forMessageDelivery: reportData,
-        mdc: Callback(onCallback: callback),
-        timeoutMS: timeoutMS
-      )
-    }
-  }
-}
-
-private final class Callback: NSObject, BindingsMessageDeliveryCallbackProtocol {
-  init(onCallback: @escaping (MessageDeliveryWaiter.Result) -> Void) {
-    self.onCallback = onCallback
-    super.init()
-  }
-
-  let onCallback: (MessageDeliveryWaiter.Result) -> Void
-
-  func eventCallback(_ delivered: Bool, timedOut: Bool, roundResults: Data?) {
-    if delivered, !timedOut, let roundResultsData = roundResults {
-      let decoder = JSONDecoder()
-      do {
-        let roundResults = try decoder.decode([Int].self, from: roundResultsData)
-        return onCallback(.delivered(roundResults: roundResults))
-      } catch {
-        return onCallback(.delivered(roundResults: [Int]()))
-      }
-    }
-    if !delivered, roundResults == nil {
-      return onCallback(.notDelivered(timedOut: timedOut))
-    }
-    fatalError("""
-      BindingsMessageDeliveryCallback received invalid parameters:
-      - delivered → \(delivered)
-      - timedOut → \(timedOut)
-      - roundResults == nil → \(roundResults == nil)
-      """)
-  }
-}
-
-#if DEBUG
-extension MessageDeliveryWaiter {
-  public static let failing = MessageDeliveryWaiter { _, _, _ in
-    struct NotImplemented: Error {}
-    throw NotImplemented()
-  }
-}
-#endif
diff --git a/Sources/ElixxirDAppsSDK/MessageDeliveryCallback.swift b/Sources/ElixxirDAppsSDK/MessageDeliveryCallback.swift
new file mode 100644
index 00000000..329c804c
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/MessageDeliveryCallback.swift
@@ -0,0 +1,58 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct MessageDeliveryCallback {
+  public enum Result: Equatable {
+    case delivered(roundResults: [Int])
+    case notDelivered(timedOut: Bool)
+  }
+
+  public init(handle: @escaping (Result) -> Void) {
+    self.handle = handle
+  }
+
+  public var handle: (Result) -> Void
+}
+
+extension MessageDeliveryCallback {
+  public static let unimplemented = MessageDeliveryCallback(
+    handle: XCTUnimplemented("\(Self.self)")
+  )
+}
+
+extension MessageDeliveryCallback {
+  func makeBindingsMessageDeliveryCallback() -> BindingsMessageDeliveryCallbackProtocol {
+    class Callback: NSObject, BindingsMessageDeliveryCallbackProtocol {
+      init(_ callback: MessageDeliveryCallback) {
+        self.callback = callback
+      }
+
+      let callback: MessageDeliveryCallback
+
+      func eventCallback(_ delivered: Bool, timedOut: Bool, roundResults: Data?) {
+        if delivered,
+           !timedOut,
+           let roundResultsData = roundResults,
+           let roundResults = try? JSONDecoder().decode([Int].self, from: roundResultsData)
+        {
+          callback.handle(.delivered(roundResults: roundResults))
+          return
+        }
+
+        if !delivered {
+          callback.handle(.notDelivered(timedOut: timedOut))
+          return
+        }
+
+        fatalError("""
+          BindingsMessageDeliveryCallback received invalid parameters:
+          - delivered → \(delivered)
+          - timedOut → \(timedOut)
+          - roundResults → \(roundResults.map { String(data: $0, encoding: .utf8) ?? "" } ?? "")
+          """)
+      }
+    }
+
+    return Callback(self)
+  }
+}
diff --git a/Sources/ElixxirDAppsSDK/Legacy/MessageSendReport.swift b/Sources/ElixxirDAppsSDK/MessageSendReport.swift
similarity index 72%
rename from Sources/ElixxirDAppsSDK/Legacy/MessageSendReport.swift
rename to Sources/ElixxirDAppsSDK/MessageSendReport.swift
index 60af863f..8ac2038b 100644
--- a/Sources/ElixxirDAppsSDK/Legacy/MessageSendReport.swift
+++ b/Sources/ElixxirDAppsSDK/MessageSendReport.swift
@@ -22,4 +22,12 @@ extension MessageSendReport: Codable {
     case messageId = "MessageID"
     case timestamp = "Timestamp"
   }
+
+  static func decode(_ data: Data) throws -> MessageSendReport {
+    try JSONDecoder().decode(Self.self, from: data)
+  }
+
+  func encode() throws -> Data {
+    try JSONEncoder().encode(self)
+  }
 }
-- 
GitLab