mirror of
https://github.com/luxfi/safe-ios.git
synced 2026-10-30 15:19:20 +00:00
# Conflicts: # Multisig.xcodeproj/project.pbxproj # Multisig.xcworkspace/xcshareddata/swiftpm/Package.resolved # Multisig/App/NSNotification+Events.swift # Multisig/App/SceneDelegate.swift # Multisig/Data/Services/Safe Client Gateway Service/SCGModels.swift # Multisig/Info.plist # Multisig/Logic/Models/DataString.swift # Multisig/Logic/Models/HashString.swift # Multisig/Logic/Models/Multisig.xcdatamodeld/Multisig.xcdatamodel/contents # Multisig/Logic/Models/Transaction.swift # Multisig/UI/App/ViewControllerFactory.swift # Multisig/UI/Settings/AppSettingsViewController/AppSettingsViewController.swift # Multisig/UI/Settings/AppSettingsViewController/ImportedKeyCell.xib # Multisig/UI/Settings/OwnerKeyManagement/EnterKeyOrSeedPhraseViewController.swift # Multisig/UI/Settings/SafeSettingsViewController/SafeSettingsViewController.swift # Multisig/UI/UI Library/Views/BasicCell.xib # MultisigIntegrationTests/Info.plist # MultisigTests/Info.plist # NotificationServiceExtension/Info.plist # Podfile # Podfile.lock # Pods/Manifest.lock # Pods/Pods.xcodeproj/project.pbxproj # Pods/Target Support Files/Pods-Multisig/Pods-Multisig-acknowledgements.markdown # Pods/Target Support Files/Pods-Multisig/Pods-Multisig-acknowledgements.plist # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.development.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.production.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.debug.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.development.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.production.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-Multisig/Pods-Multisig.release.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.development.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.production.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.debug.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.development.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.production.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigIntegrationTests/Pods-MultisigIntegrationTests.release.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.development.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.production.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.debug.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.development.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.production.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-MultisigTests/Pods-MultisigTests.release.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.development.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.production.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.staging.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.development.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.development.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.production.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.production.rinkeby.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.staging.mainnet.xcconfig # Pods/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.staging.rinkeby.xcconfig
139 lines
4.9 KiB
Swift
139 lines
4.9 KiB
Swift
//
|
|
// NetworkStatusObserver.swift
|
|
// Multisig
|
|
//
|
|
// Created by Dmitry Bespalov on 22.03.21.
|
|
// Copyright © 2021 Gnosis Ltd. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SystemConfiguration
|
|
import CoreFoundation
|
|
|
|
/// Class that can observe a network host reachability status and post
|
|
/// notifications when the status changes.
|
|
///
|
|
/// All methods MUST be called on main thread.
|
|
class NetworkHostStatusObserver {
|
|
|
|
/// Host to observe
|
|
let host: String
|
|
|
|
private var target: SCNetworkReachability?
|
|
|
|
enum Status {
|
|
case unknown, online, offline
|
|
|
|
fileprivate static func from(reachabilityFlags: SCNetworkReachabilityFlags) -> Self {
|
|
// if reachable and not need to connect
|
|
let reachableWithoutConnection = reachabilityFlags.contains(.reachable) && !reachabilityFlags.contains(.connectionRequired)
|
|
let reachableWithoutIntervention = reachabilityFlags.contains(.reachable) && !reachabilityFlags.contains(.interventionRequired) &&
|
|
(reachabilityFlags.contains(.connectionOnTraffic) || reachabilityFlags.contains(.connectionOnDemand))
|
|
|
|
if reachableWithoutConnection || reachableWithoutIntervention {
|
|
return .online
|
|
} else {
|
|
return .offline
|
|
}
|
|
}
|
|
}
|
|
|
|
private (set) var status: Status = .unknown
|
|
|
|
/// Constructor
|
|
/// - Parameter host: Pass the URL's host name to observe.
|
|
init(host: String) {
|
|
self.host = host
|
|
}
|
|
|
|
/// Starts asynchronous observing of the network host.
|
|
/// - Posts `networkHostUnreachable` when the host becomes unreachable or
|
|
/// after getting first update of the reachability (if it's unreachable).
|
|
/// - Posts `networkHostReachable` when the host becomes reachable after
|
|
/// being unreachable
|
|
func startObserving() {
|
|
dispatchPrecondition(condition: .onQueue(.main))
|
|
|
|
// create target
|
|
stopObserving()
|
|
target = SCNetworkReachabilityCreateWithName(nil, host)
|
|
guard let target = target else {
|
|
logError()
|
|
return
|
|
}
|
|
|
|
// schedule on the main thread's run loop
|
|
let scheduleSuccess = SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
|
|
guard scheduleSuccess else {
|
|
logError()
|
|
return
|
|
}
|
|
|
|
// wrap pointer to self into context info in order to get
|
|
// reference to `self` from the C callback closure
|
|
let info = UnsafeMutableRawPointer(Unmanaged.passRetained(self).toOpaque())
|
|
var context = SCNetworkReachabilityContext(version: 0, info: info, retain: nil, release: nil, copyDescription: nil)
|
|
|
|
let callbackSuccess = SCNetworkReachabilitySetCallback(target, { (_, flags, context) in
|
|
// unwrap self from context info
|
|
guard let ctx = context else { return }
|
|
let observer = Unmanaged<NetworkHostStatusObserver>.fromOpaque(ctx).takeUnretainedValue()
|
|
|
|
observer.updateStatus(flags: flags)
|
|
}, &context)
|
|
|
|
guard callbackSuccess else {
|
|
logError()
|
|
return
|
|
}
|
|
}
|
|
|
|
private func updateStatus(flags: SCNetworkReachabilityFlags) {
|
|
let oldStatus = status
|
|
let newStatus = Status.from(reachabilityFlags: flags)
|
|
status = newStatus
|
|
|
|
// Notify listeners
|
|
switch (oldStatus, newStatus) {
|
|
case (.unknown, .offline), (.online, .offline):
|
|
NotificationCenter.default.post(name: .networkHostUnreachable, object: self, userInfo: ["host": host])
|
|
case (.offline, .online):
|
|
NotificationCenter.default.post(name: .networkHostReachable, object: self, userInfo: ["host": host])
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
private func logError(line: UInt = #line, file: StaticString = #file) {
|
|
let code = SCError()
|
|
let message = SCErrorString(code)
|
|
LogService.shared.error("\(file):\(line): Network reachability failure: '\(message)', Code \(code)")
|
|
}
|
|
|
|
/// Stops observing network host reachability
|
|
func stopObserving() {
|
|
dispatchPrecondition(condition: .onQueue(.main))
|
|
|
|
guard let target = target else { return }
|
|
// delete the callback
|
|
SCNetworkReachabilitySetCallback(target, nil, nil)
|
|
|
|
// unschedule from run loop
|
|
SCNetworkReachabilityUnscheduleFromRunLoop(target, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
|
|
self.target = nil
|
|
assert(self.target == nil)
|
|
}
|
|
|
|
/// Gets current reachability status without updating the object's status
|
|
func getStatus() -> Status? {
|
|
guard let target = SCNetworkReachabilityCreateWithName(nil, host) else {
|
|
logError()
|
|
return nil
|
|
}
|
|
var outFlags: SCNetworkReachabilityFlags = []
|
|
SCNetworkReachabilityGetFlags(target, &outFlags)
|
|
let status = Status.from(reachabilityFlags: outFlags)
|
|
return status
|
|
}
|
|
}
|