field_ios

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

TeraRecoveryCompletion.swift (3203B)


      1 import Foundation
      2 import RadrootsKit
      3 
      4 struct TeraRecoveryUploadReceipt: Sendable {
      5   let parent: String
      6   let revision: UInt64
      7   let attempt: String
      8   let uploadURL: String
      9   let media: TeraPreparedMedia
     10   let response: TeraAddBackgroundUploadReceipt
     11 
     12   init(snapshot: RadrootsBackgroundTransferSnapshot, owner: TeraNativeUploadRecoveryOwner) throws {
     13     guard snapshot.state == .awaitingVerification || snapshot.state == .completed,
     14           let identity = TeraBackgroundUploadRequest.transferIdentity(snapshot.identifier),
     15           identity.draftID == owner.id, identity.revision <= owner.revision,
     16           let hash = snapshot.request.expectedSourceSHA256,
     17           let media = owner.media.first(where: { $0.sha256 == hash }),
     18           owner.media.filter({ $0.sha256 == hash }).count == 1,
     19           let url = media.remoteURL, let uploadURL = owner.uploadURLs[url],
     20           snapshot.request.remoteURL.absoluteString == uploadURL
     21           || (owner.verifiedURLs.contains(url) && snapshot.request.remoteURL.absoluteString == url),
     22           try TeraBackgroundUploadRequest.persistedRequestMatchesMedia(snapshot.request, media: media, uploadURL: uploadURL),
     23           let response = snapshot.response, let status = UInt16(exactly: response.statusCode),
     24           let body = response.body,
     25           body.count <= 16384, (response.mediaType?.utf8.count ?? 0) <= 8192,
     26           (response.contentEncoding?.utf8.count ?? 0) <= 8192,
     27           body.count + (response.mediaType?.utf8.count ?? 0) + (response.contentEncoding?.utf8.count ?? 0) <= 16384
     28     else { throw TeraNativeRecoveryFault.associationMismatch }
     29     parent = identity.draftID
     30     revision = identity.revision
     31     attempt = identity.attempt
     32     self.uploadURL = snapshot.request.remoteURL.absoluteString
     33     self.media = media
     34     self.response = .init(identifier: snapshot.identifier.rawValue, draftID: parent, expectedRevision: revision,
     35                           statusCode: status, mediaType: response.mediaType, contentEncoding: response.contentEncoding, body: body)
     36   }
     37 }
     38 
     39 struct TeraRecoveryCompletionReceipt: Sendable, Equatable {
     40   let parent: String
     41   let attempt: String
     42   let canonicalURL: String
     43   let sha256: String
     44   let mediaType: String
     45   let byteSize: UInt64
     46   let verifiedAtUnixMS: UInt64
     47 
     48   func confirm(_ input: TeraRecoveryUploadReceipt) throws {
     49     guard parent == input.parent, attempt == input.attempt, canonicalURL == input.media.remoteURL,
     50           sha256 == input.media.sha256, mediaType == input.media.mediaType, byteSize == input.media.byteSize,
     51           verifiedAtUnixMS > 0, verifiedAtUnixMS <= UInt64(Int64.max) else { throw TeraComposerAcknowledgment.unconfirmed }
     52   }
     53 }
     54 
     55 extension TeraRuntimeClient {
     56   func recoverNativeUpload(_ receipt: TeraRecoveryUploadReceipt, media: TeraPreparedMediaHandle) async throws -> TeraRecoveryCompletionReceipt {
     57     try await addOperation("runtime.recovery.complete") { try await $0.recoverNativeUpload(receipt, media: media) }
     58   }
     59 }
     60 
     61 extension TeraRuntimeBackend {
     62   func recoverNativeUpload(_: TeraRecoveryUploadReceipt, media _: TeraPreparedMediaHandle) async throws -> TeraRecoveryCompletionReceipt {
     63     throw TeraComposerAcknowledgment.unconfirmed
     64   }
     65 }