Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,66 +1,23 @@
public import Foundation
import Foundation

extension CmxIrohClientRuntime {
func performSignOut(
pendingRevocation: CmxIrohPendingRevocation?,
bindingAuthorization: CmxIrohBindingRequestAuthorization?,
revision: UInt64
) async -> CmxIrohClientSignOutPreparation {
async let wasPersisted = Self.persist(pendingRevocation, to: pendingRevocations)
async let networkTeardown: Void = tearDownNetwork(preserveBinding: true)
let (persisted, _) = await (wasPersisted, networkTeardown)
let preparation = CmxIrohClientSignOutPreparation(
await performSignOutFlow(
pendingRevocation: pendingRevocation,
wasPersisted: persisted,
bindingAuthorization: bindingAuthorization
bindingAuthorization: bindingAuthorization,
revision: revision,
tearDownNetwork: {
await self.tearDownNetwork(preserveBinding: true)
},
deactivateLocalState: { [offlinePolicyCache, handleLocalDeactivation] in
try? await offlinePolicyCache?.deactivate()
await handleLocalDeactivation()
}
)

guard lifecyclePhase == .signingOut,
lifecycleRevision == revision else {
signOutOperation = nil
return preparation
}
guard persisted else {
lifecyclePhase = .quarantined
currentSnapshot = CmxIrohClientRuntimeSnapshot(
state: .quarantined,
endpointID: nil,
bindingID: pendingRevocation?.bindingID
)
signOutOperation = nil
return preparation
}

try? await offlinePolicyCache?.deactivate()
await handleLocalDeactivation()
guard lifecyclePhase == .signingOut,
lifecycleRevision == revision else {
signOutOperation = nil
return preparation
}
localBinding = nil
lastRegistrationRefreshState = nil
lifecyclePhase = .inactive
currentSnapshot = CmxIrohClientRuntimeSnapshot(
state: .inactive,
endpointID: nil,
bindingID: nil
)
signOutOperation = nil
return preparation
}

nonisolated static func persist(
_ revocation: CmxIrohPendingRevocation?,
to pendingRevocations: CmxIrohPendingRevocationOutbox
) async -> Bool {
guard let revocation else { return true }
do {
try await pendingRevocations.enqueue(revocation)
return true
} catch {
return false
}
}

func tearDownNetwork(preserveBinding: Bool = false) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,53 +39,23 @@ extension CmxIrohClientRuntime {
|| profile.allowedRelayURLs.isSubset(of: replacementManagedURLs) else {
throw CmxIrohClientRuntimeError.relayFleetMismatch
}
let revision = lifecycleRevision

await relayCoordinator?.deactivate()
relayCoordinator = nil
if profile.source == .managed, !profile.allowedRelayURLs.isEmpty {
let refreshSchedule = CmxIrohRelayRefreshSchedule(
role: .client,
endpointIdentity: binding.endpointID
)
let coordinator = CmxIrohRelayCredentialCoordinator(
supervisor: connectivityEngine,
broker: broker,
managedRelayURLs: replacementManagedURLs,
selectedRelayURLs: profile.allowedRelayURLs,
jitter: { now, refreshAfter in
refreshSchedule.deadline(now: now, refreshAfter: refreshAfter)
},
retrySchedule: .foregroundClient,
automaticRefreshEnabled: automaticRelayCredentialRefreshEnabled,
credentialDidInstall: { [handleRelayCredential] response in
await handleRelayCredential(response, binding)
}
)
relayCoordinator = coordinator
do {
try await coordinator.activateManagedPolicy(
bindingID: binding.bindingID,
endpointIdentity: binding.endpointID,
profile: profile,
bootstrap: relayBootstrap
)
} catch {
await coordinator.deactivate()
if relayCoordinator === coordinator {
relayCoordinator = nil
}
throw error
let revision = try await swapRelayCoordinator(
profile: profile,
replacementManagedURLs: replacementManagedURLs,
relayBootstrap: relayBootstrap,
role: .client,
bindingID: binding.bindingID,
endpointIdentity: binding.endpointID,
connectivityEngine: connectivityEngine,
broker: broker,
retrySchedule: .foregroundClient,
automaticRefreshEnabled: automaticRelayCredentialRefreshEnabled,
credentialDidInstall: { [handleRelayCredential] response in
await handleRelayCredential(response, binding)
}
} else {
try await connectivityEngine.replaceRelayProfile(
profile,
expectedIdentity: binding.endpointID
)
}
try requireCurrent(revision)
)

managedRelayURLs = replacementManagedURLs
endpointRelayProfile = profile
let expectation = try CmxIrohLocalBindingExpectation(
deviceID: binding.deviceID,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
public extension CmxIrohClientRuntime {
/// Returns whether the live authenticated endpoint currently advertises an allowed relay.
func hasReachableRelay(in allowedRelayURLs: Set<String>) async -> Bool? {
guard !allowedRelayURLs.isEmpty,
lifecyclePhase == .active,
let address = try? await connectivityEngine.endpointAddress() else {
return nil
}
return address.pathHints.contains {
$0.kind == .relayURL && allowedRelayURLs.contains($0.value)
}
await activeRelayReachability(in: allowedRelayURLs, connectivityEngine: connectivityEngine)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,7 @@ public actor CmxIrohClientRuntime {
let task: Task<CmxIrohLiveDiscoveryRefreshOutcome, Never>
}

enum LifecyclePhase: Equatable, Sendable {
case inactive
case starting
case active
case stopping
case signingOut
case quarantined
case failed

var allowsStart: Bool {
self == .inactive || self == .failed
}

var ownsNetworkOperation: Bool {
self == .starting || self == .active
}
}
typealias LifecyclePhase = CmxIrohRuntimeLifecyclePhase

/// The route-aware factory registered by the iOS app before fallback transports.
public nonisolated let transportFactory: CmxConnectivityByteTransportFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,53 +41,23 @@ extension CmxIrohHostRuntime {
|| profile.allowedRelayURLs.isSubset(of: replacementManagedURLs) else {
throw CmxIrohHostRuntimeError.relayFleetMismatch
}
let revision = lifecycleRevision

relayActivationTask?.cancel()
relayActivationTask = nil
await relayCoordinator?.deactivate()
relayCoordinator = nil
if profile.source == .managed, !profile.allowedRelayURLs.isEmpty {
let refreshSchedule = CmxIrohRelayRefreshSchedule(
role: .host,
endpointIdentity: binding.endpointID
)
let coordinator = CmxIrohRelayCredentialCoordinator(
supervisor: connectivityEngine,
broker: broker,
managedRelayURLs: replacementManagedURLs,
selectedRelayURLs: profile.allowedRelayURLs,
jitter: { now, refreshAfter in
refreshSchedule.deadline(now: now, refreshAfter: refreshAfter)
},
credentialDidInstall: { [handleRelayCredential] response in
await handleRelayCredential(response, binding)
}
)
relayCoordinator = coordinator
do {
try await coordinator.activateManagedPolicy(
bindingID: binding.bindingID,
endpointIdentity: binding.endpointID,
profile: profile,
bootstrap: relayBootstrap
)
} catch {
await coordinator.deactivate()
if relayCoordinator === coordinator {
relayCoordinator = nil
}
throw error
let revision = try await swapRelayCoordinator(
profile: profile,
replacementManagedURLs: replacementManagedURLs,
relayBootstrap: relayBootstrap,
role: .host,
bindingID: binding.bindingID,
endpointIdentity: binding.endpointID,
connectivityEngine: connectivityEngine,
broker: broker,
credentialDidInstall: { [handleRelayCredential] response in
await handleRelayCredential(response, binding)
}
} else {
try await connectivityEngine.replaceRelayProfile(
profile,
expectedIdentity: binding.endpointID
)
}
try requireCurrent(revision)
)

managedRelayURLs = replacementManagedURLs
currentEndpointRelayProfile = profile
await admissionController?.updateManagedRelayURLs(replacementManagedURLs)
try requireCurrent(revision)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
public extension CmxIrohHostRuntime {
/// Returns whether the live authenticated endpoint currently advertises an allowed relay.
func hasReachableRelay(in allowedRelayURLs: Set<String>) async -> Bool? {
guard !allowedRelayURLs.isEmpty,
lifecyclePhase == .active,
let connectivityEngine,
let address = try? await connectivityEngine.endpointAddress() else {
return nil
}
return address.pathHints.contains {
$0.kind == .relayURL && allowedRelayURLs.contains($0.value)
}
await activeRelayReachability(in: allowedRelayURLs, connectivityEngine: connectivityEngine)
}
}
Original file line number Diff line number Diff line change
@@ -1,66 +1,21 @@
public import Foundation

extension CmxIrohHostRuntime {
func performSignOut(
pendingRevocation: CmxIrohPendingRevocation?,
bindingAuthorization: CmxIrohBindingRequestAuthorization?,
requiresNetworkDeactivation: Bool,
revision: UInt64
) async -> CmxIrohHostSignOutPreparation {
async let wasPersisted = Self.persist(
pendingRevocation,
to: pendingRevocations
)
async let networkTeardown: Void = deactivateNetworkForSignOut(
bindingID: pendingRevocation?.bindingID,
required: requiresNetworkDeactivation
)
let (persisted, _) = await (wasPersisted, networkTeardown)
let preparation = CmxIrohHostSignOutPreparation(
await performSignOutFlow(
pendingRevocation: pendingRevocation,
wasPersisted: persisted,
bindingAuthorization: bindingAuthorization
bindingAuthorization: bindingAuthorization,
revision: revision,
tearDownNetwork: {
await self.deactivateNetworkForSignOut(
bindingID: pendingRevocation?.bindingID,
required: requiresNetworkDeactivation
)
}
)

guard lifecyclePhase == .signingOut,
lifecycleRevision == revision else {
signOutOperation = nil
return preparation
}
guard persisted else {
lifecyclePhase = .quarantined
currentSnapshot = CmxIrohHostRuntimeSnapshot(
state: .quarantined,
endpointID: nil,
bindingID: pendingRevocation?.bindingID
)
signOutOperation = nil
return preparation
}

localBinding = nil
lastRegistrationRefreshState = nil
lifecyclePhase = .inactive
currentSnapshot = CmxIrohHostRuntimeSnapshot(
state: .inactive,
endpointID: nil,
bindingID: nil
)
signOutOperation = nil
return preparation
}

nonisolated static func persist(
_ revocation: CmxIrohPendingRevocation?,
to pendingRevocations: CmxIrohPendingRevocationOutbox
) async -> Bool {
guard let revocation else { return true }
do {
try await pendingRevocations.enqueue(revocation)
return true
} catch {
return false
}
}

func deactivateNetworkForSignOut(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,7 @@ public actor CmxIrohHostRuntime {
let registrationRetryAfterSeconds: Int?
}

enum LifecyclePhase: Equatable, Sendable {
case inactive
case starting
case active
case stopping
case signingOut
case quarantined
case failed

var allowsStart: Bool {
self == .inactive || self == .failed
}

var ownsNetworkOperation: Bool {
self == .starting || self == .active
}
}
typealias LifecyclePhase = CmxIrohRuntimeLifecyclePhase

let factory: any CmxIrohEndpointFactory
let broker: any CmxIrohHostBrokerServing
Expand Down
Loading
Loading