field_ios

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

TeraGeneratedComposer.swift (7532B)


      1 import Foundation
      2 import TeraKitBindings
      3 
      4 enum TeraGeneratedComposer {
      5   static func reserveID() throws -> String {
      6     let record = try composerReserveId()
      7     try version(record.schemaVersion)
      8     return record.id
      9   }
     10 
     11   static func save(runtime: TeraRuntime, request: TeraComposerSaveRequest) async throws -> TeraComposerSaveReceipt {
     12     let record = try await runtime.composerSave(request: request.generatedValue)
     13     try version(record.schemaVersion)
     14     let draft = try record.draft.composerAppValue
     15     guard draft.scope == request.scope, draft.id == request.id,
     16           draft.editSequence == request.editSequence, draft.form == request.form,
     17           draft.revision == (request.expectedRevision.map { $0 &+ 1 } ?? 1)
     18     else { throw mismatch() }
     19     return TeraComposerSaveReceipt(draft: draft, replayed: record.replayed)
     20   }
     21 
     22   static func load(runtime: TeraRuntime, scope: TeraComposerScope, id: String) async throws -> TeraComposerDraft {
     23     let draft = try await runtime.composerLoad(scope: scope.generatedValue, composerId: id).composerAppValue
     24     guard draft.scope == scope, draft.id == id else { throw mismatch() }
     25     return draft
     26   }
     27 
     28   static func list(runtime: TeraRuntime, scope: TeraComposerScope, limit: UInt16, cursor: String?) async throws -> TeraComposerPage {
     29     let record = try await runtime.composerList(schemaVersion: 1, scope: scope.generatedValue, limit: limit, cursor: cursor)
     30     try version(record.schemaVersion)
     31     let actualScope = try record.scope.composerAppValue
     32     guard actualScope == scope else { throw mismatch() }
     33     return try TeraComposerPage(scope: actualScope, entries: record.entries.map { entry in
     34       switch entry {
     35       case let .draft(summary):
     36         try version(summary.schemaVersion)
     37         return .draft(TeraComposerSummary(
     38           id: summary.id, revision: summary.revision, editSequence: summary.editSequence,
     39           commandType: summary.commandType.composerAppValue,
     40           createdAtUnixMilliseconds: summary.createdAtUnixMs,
     41           updatedAtUnixMilliseconds: summary.updatedAtUnixMs
     42         ))
     43       case let .repair(draftKey, revision, reason):
     44         return .repair(draftKey: draftKey, revision: revision,
     45                        reason: reason == .unsupportedSchema ? .unsupportedSchema : .corruptRecord)
     46       }
     47     }, nextCursor: record.nextCursor)
     48   }
     49 
     50   static func version(_ version: UInt16) throws {
     51     guard version == 1 else {
     52       throw TeraRuntimeFailure.local(operation: "runtime.composer", code: "composer_schema_unsupported",
     53                                      safeMessage: "This local composer format requires a compatible app.")
     54     }
     55   }
     56 
     57   private static func mismatch() -> TeraRuntimeFailure {
     58     .local(operation: "runtime.composer", code: "composer_receipt_mismatch",
     59            safeMessage: "The local composer response could not be reconciled.")
     60   }
     61 }
     62 
     63 extension TeraComposerScope {
     64   var generatedValue: FfiComposerScopeRecord {
     65     FfiComposerScopeRecord(schemaVersion: 1, authorPublicKey: authorPublicKey, localNetworkId: localNetworkID)
     66   }
     67 }
     68 
     69 extension FfiComposerScopeRecord {
     70   var composerAppValue: TeraComposerScope {
     71     get throws {
     72       try TeraGeneratedComposer.version(schemaVersion)
     73       return TeraComposerScope(authorPublicKey: authorPublicKey, localNetworkID: localNetworkId)
     74     }
     75   }
     76 }
     77 
     78 extension TeraComposerSaveRequest {
     79   var generatedValue: FfiComposerSaveRequest {
     80     FfiComposerSaveRequest(schemaVersion: 1, scope: scope.generatedValue, id: id,
     81                            expectedRevision: expectedRevision, editSequence: editSequence, form: form.generatedValue)
     82   }
     83 }
     84 
     85 extension FfiComposerDraftRecord {
     86   var composerAppValue: TeraComposerDraft {
     87     get throws {
     88       try TeraGeneratedComposer.version(schemaVersion)
     89       return try TeraComposerDraft(scope: scope.composerAppValue, id: id, revision: revision,
     90                                    editSequence: editSequence, form: form.composerAppValue)
     91     }
     92   }
     93 }
     94 
     95 extension TeraComposerForm {
     96   var generatedValue: FfiComposerFormRecord {
     97     FfiComposerFormRecord(
     98       schemaVersion: 1,
     99       commandType: commandType.composerGeneratedValue,
    100       content: content,
    101       identifier: identifier,
    102       title: title,
    103       summary: summary,
    104       location: location,
    105       eventTiming: eventTiming?.composerGeneratedValue,
    106       eventStartDate: eventStartDate,
    107       eventEndDate: eventEndDate,
    108       eventStartUnixS: eventStartUnixSeconds,
    109       eventEndUnixS: eventEndUnixSeconds,
    110       eventTimezone: eventTimezone,
    111       priceAmount: priceAmount,
    112       currency: currency,
    113       unit: unit,
    114       quantity: quantity,
    115       foodPublishedAtUnixS: foodPublishedAtUnixSeconds,
    116       foodStatus: foodStatus,
    117       media: media.map(\.generatedValue)
    118     )
    119   }
    120 }
    121 
    122 extension FfiComposerFormRecord {
    123   var composerAppValue: TeraComposerForm {
    124     get throws {
    125       try TeraGeneratedComposer.version(schemaVersion)
    126       var form = TeraComposerForm(commandType: commandType.composerAppValue)
    127       form.content = content
    128       form.identifier = identifier
    129       form.title = title
    130       form.summary = summary
    131       form.location = location
    132       form.eventTiming = eventTiming?.composerAppValue
    133       form.eventStartDate = eventStartDate
    134       form.eventEndDate = eventEndDate
    135       form.eventStartUnixSeconds = eventStartUnixS
    136       form.eventEndUnixSeconds = eventEndUnixS
    137       form.eventTimezone = eventTimezone
    138       form.priceAmount = priceAmount
    139       form.currency = currency
    140       form.unit = unit
    141       form.quantity = quantity
    142       form.foodPublishedAtUnixSeconds = foodPublishedAtUnixS
    143       form.foodStatus = foodStatus
    144       form.media = try media.map { try $0.composerAppValue }
    145       return form
    146     }
    147   }
    148 }
    149 
    150 extension TeraComposerMedia {
    151   var generatedValue: FfiComposerMediaRecord {
    152     FfiComposerMediaRecord(
    153       schemaVersion: 1,
    154       opaqueReference: opaqueReference,
    155       sha256: sha256,
    156       mediaType: mediaType,
    157       byteSize: byteSize,
    158       width: width,
    159       height: height,
    160       alt: alt,
    161       preparedAtUnixS: preparedAtUnixSeconds
    162     )
    163   }
    164 }
    165 
    166 extension FfiComposerMediaRecord {
    167   var composerAppValue: TeraComposerMedia {
    168     get throws {
    169       try TeraGeneratedComposer.version(schemaVersion)
    170       return TeraComposerMedia(
    171         opaqueReference: opaqueReference,
    172         sha256: sha256,
    173         mediaType: mediaType,
    174         byteSize: byteSize,
    175         width: width,
    176         height: height,
    177         alt: alt,
    178         preparedAtUnixSeconds: preparedAtUnixS
    179       )
    180     }
    181   }
    182 }
    183 
    184 extension TeraAddCommandType {
    185   fileprivate var composerGeneratedValue: FfiAddCommandType {
    186     switch self {
    187     case .createUpdate: .createUpdate
    188     case .createPhotoUpdate: .createPhotoUpdate
    189     case .createAsk: .createAsk
    190     case .createEvent: .createEvent
    191     case .createFoodAvailability: .createFoodAvailability
    192     }
    193   }
    194 }
    195 
    196 extension FfiAddCommandType {
    197   fileprivate var composerAppValue: TeraAddCommandType {
    198     switch self {
    199     case .createUpdate: .createUpdate
    200     case .createPhotoUpdate: .createPhotoUpdate
    201     case .createAsk: .createAsk
    202     case .createEvent: .createEvent
    203     case .createFoodAvailability: .createFoodAvailability
    204     }
    205   }
    206 }
    207 
    208 extension TeraEventTiming {
    209   fileprivate var composerGeneratedValue: FfiEventTimingKind {
    210     switch self {
    211     case .allDay: .allDay
    212     case .timed: .timed
    213     }
    214   }
    215 }
    216 
    217 extension FfiEventTimingKind {
    218   fileprivate var composerAppValue: TeraEventTiming {
    219     switch self {
    220     case .allDay: .allDay
    221     case .timed: .timed
    222     }
    223   }
    224 }