Browse Source

Make `OperationGroup` cache its `...Metadata` properties, as those methods actually *move* the metadata (so a second call to these methods would previously always return empty metadata objects).

Daniel Alm 7 years ago
parent
commit
9128b60c69
1 changed files with 18 additions and 4 deletions
  1. 18 4
      Sources/SwiftGRPC/Core/OperationGroup.swift

+ 18 - 4
Sources/SwiftGRPC/Core/OperationGroup.swift

@@ -46,6 +46,9 @@ class OperationGroup {
 
 
   /// Indicates that the OperationGroup completed successfully
   /// Indicates that the OperationGroup completed successfully
   var success = false
   var success = false
+  
+  fileprivate var cachedInitialMetadata: Metadata?
+  fileprivate var cachedTrailingMetadata: Metadata?
 
 
   /// Creates the underlying observer needed to run an operation
   /// Creates the underlying observer needed to run an operation
   ///
   ///
@@ -108,7 +111,8 @@ class OperationGroup {
     cgrpc_operations_destroy(underlyingOperations)
     cgrpc_operations_destroy(underlyingOperations)
   }
   }
 
 
-  /// WARNING: The following assumes that at most one operation of each type is in the group.
+  /// WARNING: The following assumes that at most one operation of each type is in the group,
+  ///          and these methods must ONLY be called after the operation has been returned to a completion queue.
 
 
   /// Gets the message that was received
   /// Gets the message that was received
   ///
   ///
@@ -132,10 +136,15 @@ class OperationGroup {
   ///
   ///
   /// - Returns: metadata
   /// - Returns: metadata
   func receivedInitialMetadata() -> Metadata? {
   func receivedInitialMetadata() -> Metadata? {
+    if let cachedInitialMetadata = self.cachedInitialMetadata {
+      return cachedInitialMetadata
+    }
     for (i, operation) in operations.enumerated() {
     for (i, operation) in operations.enumerated() {
       switch operation {
       switch operation {
       case .receiveInitialMetadata:
       case .receiveInitialMetadata:
-        return Metadata(underlyingArray: cgrpc_observer_recv_initial_metadata_get_metadata(underlyingObservers[i]))
+        cachedInitialMetadata = Metadata(
+          underlyingArray: cgrpc_observer_recv_initial_metadata_get_metadata(underlyingObservers[i]))
+        return cachedInitialMetadata!
       default:
       default:
         continue
         continue
       }
       }
@@ -165,7 +174,7 @@ class OperationGroup {
     for (i, operation) in operations.enumerated() {
     for (i, operation) in operations.enumerated() {
       switch operation {
       switch operation {
       case .receiveStatusOnClient:
       case .receiveStatusOnClient:
-        // We actually know that this method will never return nil, so we can forcibly the result. (Also below.)
+        // We actually know that this method will never return nil, so we can forcibly unwrap the result. (Also below.)
         let string = cgrpc_observer_recv_status_on_client_copy_status_details(underlyingObservers[i])!
         let string = cgrpc_observer_recv_status_on_client_copy_status_details(underlyingObservers[i])!
         defer { cgrpc_free_copied_string(string) }
         defer { cgrpc_free_copied_string(string) }
         return String(cString: string, encoding: String.Encoding.utf8)
         return String(cString: string, encoding: String.Encoding.utf8)
@@ -180,10 +189,15 @@ class OperationGroup {
   ///
   ///
   /// - Returns: metadata
   /// - Returns: metadata
   func receivedTrailingMetadata() -> Metadata? {
   func receivedTrailingMetadata() -> Metadata? {
+    if let cachedTrailingMetadata = self.cachedTrailingMetadata {
+      return cachedTrailingMetadata
+    }
     for (i, operation) in operations.enumerated() {
     for (i, operation) in operations.enumerated() {
       switch operation {
       switch operation {
       case .receiveStatusOnClient:
       case .receiveStatusOnClient:
-        return Metadata(underlyingArray: cgrpc_observer_recv_status_on_client_get_metadata(underlyingObservers[i]))
+        cachedTrailingMetadata = Metadata(
+          underlyingArray: cgrpc_observer_recv_status_on_client_get_metadata(underlyingObservers[i]))
+        return cachedTrailingMetadata!
       default:
       default:
         continue
         continue
       }
       }