TeraGeneratedRuntimeStartup.swift (5720B)
1 import Foundation 2 import TeraKitBindings 3 4 extension TeraGeneratedRuntimeBackend { 5 static func start( 6 configuration: TeraRuntimeLaunchConfiguration, localBackups: Bool = false 7 ) async throws -> TeraRuntimeBackendStart { 8 var createdRuntime: TeraRuntime? 9 do { 10 let mediaUse = try TeraMediaProcessUse.admit(applicationSupportDirectory: configuration.applicationSupportDirectory) 11 defer { withExtendedLifetime(mediaUse) {} } 12 let (runtime, restored) = try await construct(configuration: configuration, localBackups: localBackups) 13 createdRuntime = runtime 14 runtime.setAppInfoPlatform( 15 platform: "iOS", 16 bundleId: configuration.app.bundleIdentifier, 17 version: configuration.app.version, 18 buildNumber: configuration.app.buildNumber, 19 buildSha: configuration.app.buildSHA 20 ) 21 22 let backend = TeraGeneratedRuntimeBackend(runtime: runtime) 23 if !restored { 24 try await bootstrap(runtime: runtime, backend: backend, configuration: configuration) 25 } 26 return try await TeraRuntimeBackendStart( 27 backend: backend, 28 snapshot: backend.snapshot() 29 ) 30 } catch { 31 if let createdRuntime { 32 _ = try? await createdRuntime.shutdown() 33 } 34 throw TeraGeneratedRuntimeFailure.from(error) 35 } 36 } 37 38 private static func bootstrap(runtime: TeraRuntime, backend: TeraGeneratedRuntimeBackend, 39 configuration: TeraRuntimeLaunchConfiguration) async throws 40 { 41 let currentSettings = try await backend.mobileSettings() 42 if configuration.adoptBootstrapSettings 43 || currentSettings.revision == 1 && currentSettings.identity.identities.isEmpty 44 { 45 _ = try await backend.replaceMobileSettings(input: configuration.bootstrapSettingsReplacement(current: currentSettings)) 46 } 47 _ = try await runtime.phase1ApplySettingsToRuntime() 48 } 49 50 private static func construct(configuration: TeraRuntimeLaunchConfiguration, localBackups: Bool) async throws -> (TeraRuntime, Bool) { 51 if let guardBytes = try TeraRestoreFiles.readGuard( 52 applicationSupportDirectory: configuration.applicationSupportDirectory, publicKey: configuration.publicKeyHex 53 ) { 54 let runtime = try await TeraRuntime.withHostSignerAndRestoreGuard( 55 store: FfiRestoreStore(applicationSupportDirectory: configuration.applicationSupportDirectory, 56 publicKey: configuration.publicKeyHex, sourceGeneration: configuration.sourceGenerationHex, 57 sourceGenerationCreatedAtMs: configuration.sourceGenerationCreatedAtUnixMilliseconds, 58 protectedData: configuration.protectedData.generatedValue), 59 hostSigner: TeraGeneratedHostSigner(signer: configuration.signer), guard: guardBytes, localBackups: localBackups 60 ) 61 return (runtime, true) 62 } 63 let constructor = localBackups ? TeraRuntime.withHostSignerAndLocalBackups : TeraRuntime.withHostSigner 64 let runtime = try await constructor( 65 configuration.applicationSupportDirectory, configuration.publicKeyHex, 66 configuration.sourceGenerationHex, configuration.sourceGenerationCreatedAtUnixMilliseconds, 67 configuration.protectedData.generatedValue, TeraGeneratedHostSigner(signer: configuration.signer) 68 ) 69 return (runtime, false) 70 } 71 } 72 73 extension TeraRuntimeLaunchConfiguration { 74 fileprivate func bootstrapSettingsReplacement( 75 current: TeraMobileSettings 76 ) -> TeraReplaceSettings { 77 let environment = networkProfile.settingsValue 78 var relays = writableRelays.map { 79 TeraRelayPreference(url: $0, access: .readWrite) 80 } 81 if networkProfile != .simulator, 82 !relays.contains(where: { $0.url == TeraNetworkValidator.canonicalRelay }) 83 { 84 relays.insert( 85 TeraRelayPreference( 86 url: TeraNetworkValidator.canonicalRelay, 87 access: .readWrite 88 ), 89 at: 0 90 ) 91 } 92 let authority = blossom?.endpointAuthority.settingsValue 93 ?? current.blossomAuthority 94 let primaryOrigin = blossom?.primaryOrigin ?? current.blossomPrimaryOrigin 95 let fallbackOrigins = blossom?.fallbackOrigins ?? current.blossomFallbackOrigins 96 return TeraReplaceSettings( 97 expectedRevision: current.revision, 98 networkEnvironment: environment, 99 relays: relays, 100 blossomAuthority: authority, 101 blossomPrimaryOrigin: primaryOrigin, 102 blossomFallbackOrigins: fallbackOrigins, 103 allowCellularDownloads: current.allowCellularDownloads, 104 allowCellularUploads: current.allowCellularUploads, 105 allowBackgroundTransfers: current.allowBackgroundTransfers, 106 mediaCacheBytes: current.mediaCacheBytes, 107 mediaCacheArtifacts: current.mediaCacheArtifacts 108 ) 109 } 110 } 111 112 extension TeraRuntimeNetworkProfile { 113 fileprivate var settingsValue: TeraSettingsNetworkEnvironment { 114 switch self { 115 case .publicNetwork: .publicNetwork 116 case .simulator: .simulator 117 case .device: .physicalDevice 118 } 119 } 120 } 121 122 extension TeraBlossomEndpointAuthority { 123 fileprivate var settingsValue: TeraBlossomAuthorityPreference { 124 switch self { 125 case .publicWebPKI: .publicWebPKI 126 case .loopbackDevelopment: .loopbackDevelopment 127 case .privateNetworkDevelopment: .privateNetworkDevelopment 128 } 129 } 130 } 131 132 extension TeraRuntimeClient { 133 static func production() -> TeraRuntimeClient { 134 TeraRuntimeClient { configuration in 135 try await TeraGeneratedRuntimeBackend.start(configuration: configuration) 136 } 137 } 138 } 139 140 extension TeraProtectedDataState { 141 fileprivate var generatedValue: ProtectedDataAvailability { 142 switch self { 143 case .available: .available 144 case .unavailable: .unavailable 145 } 146 } 147 }