5 func onMOCQueueFindBottle(bottleID: String) throws -> (BottleMO) {
6 guard let containerBottles = self.containerMO.bottles as? Set<BottleMO> else {
7 throw ContainerError.noBottlesPresent
10 let bottles = containerBottles.filter { $0.bottleID == bottleID }
12 guard let bottle = bottles.first else {
13 throw ContainerError.noBottlesForEscrowRecordID
19 func preflightVouchWithBottle(bottleID: String,
20 reply: @escaping (String?, TPSyncingPolicy?, Bool, Error?) -> Void) {
22 let reply: (String?, TPSyncingPolicy?, Bool, Error?) -> Void = {
23 os_log("preflightVouchWithBottle complete: %{public}@",
24 log: tplogTrace, type: .info, traceError($3))
25 self.semaphore.signal()
29 self.moc.performAndWait {
31 let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
32 reply(peerID, syncingPolicy, false, nil)
34 os_log("preflightVouchWithBottle failed; forcing refetch and retrying: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
36 self.fetchAndPersistChanges { fetchError in
37 guard fetchError == nil else {
38 os_log("preflightVouchWithBottle unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
39 reply(nil, nil, true, fetchError)
43 // Ensure we have all policy versions claimed by peers, including our sponsor
44 let allPolicyVersions = self.model.allPolicyVersions()
45 self.fetchPolicyDocumentsWithSemaphore(versions: allPolicyVersions) { _, fetchPolicyDocumentsError in
46 guard fetchPolicyDocumentsError == nil else {
47 os_log("preflightVouchWithBottle unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
48 reply(nil, nil, true, fetchPolicyDocumentsError)
52 self.fetchViableBottlesWithSemaphore { _, _, fetchBottlesError in
53 guard fetchBottlesError == nil else {
54 os_log("preflightVouchWithBottle unable to fetch viable bottles: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
55 reply(nil, nil, true, fetchBottlesError)
60 self.moc.performAndWait {
62 let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
63 reply(peerID, syncingPolicy, true, nil)
65 os_log("preflightVouchWithBottle failed after refetches; failing: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
66 reply(nil, nil, true, error)
76 func onMOCQueuePerformPreflight(bottleID: String) throws -> (BottleMO, String, TPSyncingPolicy) {
77 guard let egoPeerID = self.containerMO.egoPeerID,
78 let egoPermData = self.containerMO.egoPeerPermanentInfo,
79 let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
80 os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
81 throw ContainerError.noPreparedIdentity
84 let keyFactory = TPECPublicKeyFactory()
85 guard let egoPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
86 os_log("fetchCurrentPolicy failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
87 throw ContainerError.invalidPermanentInfoOrSig
90 let bottleMO = try self.onMOCQueueFindBottle(bottleID: bottleID)
92 guard let sponsorPeer = self.model.peer(withID: bottleMO.peerID ?? "") else {
93 os_log("preflightVouchWithBottle found no peer to match bottle", log: tplogDebug, type: .default)
94 throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
97 guard let sponsorPeerStableInfo = sponsorPeer.stableInfo else {
98 os_log("preflightVouchWithBottle sponsor peer has no stable info", log: tplogDebug, type: .default)
99 throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
102 // We need to extract the syncing policy that the remote peer would have used (if they were the type of device that we are)
103 let policy = try self.syncingPolicyFor(modelID: egoPermanentInfo.modelID, stableInfo: sponsorPeerStableInfo)
104 return (bottleMO, sponsorPeer.peerID, policy)