field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraNativeUploadReconciliation.swift (2262B)


      1 import Foundation
      2 import RadrootsKit
      3 
      4 /// Rust has already confirmed the exact attempt. Native settlement cannot
      5 /// create or advance that completion, including after a lost native reply.
      6 enum TeraNativeUploadReconciliation {
      7   static func settle(_ expected: RadrootsBackgroundTransferSnapshot, input: TeraRecoveryUploadReceipt,
      8                      receipt: TeraRecoveryCompletionReceipt, transfer: any RadrootsBackgroundTransfer) async throws
      9   {
     10     try receipt.confirm(input)
     11     guard input.response.identifier == expected.identifier.rawValue,
     12           input.uploadURL == expected.request.remoteURL.absoluteString,
     13           input.media.sha256 == expected.request.expectedSourceSHA256 else { throw TeraComposerAcknowledgment.unconfirmed }
     14     let current = try await matchingSnapshot(expected, transfer: transfer)
     15     try Task.checkCancellation()
     16     if current.state == .completed {
     17       return
     18     }
     19     guard current.state == .awaitingVerification else { throw TeraComposerAcknowledgment.unconfirmed }
     20     do {
     21       try await transfer.settle(expected.identifier, verification: .accepted)
     22     } catch {
     23       try Task.checkCancellation()
     24       // A storage or transport reply can be lost after its state is committed.
     25       // Only matching durable native success makes this success-equivalent.
     26       let recovered = try await matchingSnapshot(expected, transfer: transfer)
     27       guard recovered.state == .completed else { throw error }
     28       return
     29     }
     30     let confirmed = try await matchingSnapshot(expected, transfer: transfer)
     31     guard confirmed.state == .completed else { throw TeraComposerAcknowledgment.unconfirmed }
     32   }
     33 
     34   private static func matchingSnapshot(_ expected: RadrootsBackgroundTransferSnapshot,
     35                                        transfer: any RadrootsBackgroundTransfer) async throws -> RadrootsBackgroundTransferSnapshot
     36   {
     37     guard let current = try await transfer.snapshot(for: expected.identifier),
     38           current.identifier == expected.identifier, current.request == expected.request,
     39           current.response == expected.response, current.executionID == expected.executionID,
     40           current.uploadLease == expected.uploadLease else { throw TeraComposerAcknowledgment.unconfirmed }
     41     return current
     42   }
     43 }