Current network type detection

Small changes in Postbox API
This commit is contained in:
Peter
2018-08-07 14:02:38 +03:00
parent 4a80fec8b0
commit da464a3286
8 changed files with 698 additions and 2 deletions

View File

@@ -397,6 +397,12 @@
D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */; };
D08984F22114B97400918162 /* ClearCloudDrafts.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F12114B97400918162 /* ClearCloudDrafts.swift */; };
D08984F32114B97400918162 /* ClearCloudDrafts.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F12114B97400918162 /* ClearCloudDrafts.swift */; };
D08984F521187ECA00918162 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F421187ECA00918162 /* NetworkType.swift */; };
D08984F621187ECA00918162 /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08984F421187ECA00918162 /* NetworkType.swift */; };
D08984F92118816A00918162 /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = D08984F72118816900918162 /* Reachability.h */; };
D08984FA2118816A00918162 /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = D08984F72118816900918162 /* Reachability.h */; };
D08984FB2118816A00918162 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = D08984F82118816A00918162 /* Reachability.m */; };
D08984FC2118816A00918162 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = D08984F82118816A00918162 /* Reachability.m */; };
D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; };
D08CAA7E1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */; };
D08CAA801ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */; };
@@ -950,6 +956,9 @@
D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedGlobalNotificationSettings.swift; sourceTree = "<group>"; };
D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalNotificationSettings.swift; sourceTree = "<group>"; };
D08984F12114B97400918162 /* ClearCloudDrafts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearCloudDrafts.swift; sourceTree = "<group>"; };
D08984F421187ECA00918162 /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = "<group>"; };
D08984F72118816900918162 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
D08984F82118816A00918162 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
D08CAA7C1ED77EE90000FDA8 /* LocalizationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationSettings.swift; sourceTree = "<group>"; };
D08CAA7F1ED80ED20000FDA8 /* SuggestedLocalizationEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuggestedLocalizationEntry.swift; sourceTree = "<group>"; };
D08CAA831ED8164B0000FDA8 /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = "<group>"; };
@@ -1489,6 +1498,7 @@
D03B0D591D631A6900955575 /* Serialization.swift */,
D06AFE8820BF66BF00EA5124 /* DeserializeFunctionResponse.swift */,
D0F19F6520E6620D00EEC860 /* MultiplexedRequestManager.swift */,
D08984F421187ECA00918162 /* NetworkType.swift */,
);
name = Network;
sourceTree = "<group>";
@@ -1564,6 +1574,8 @@
D053B3FA1F1651FA00E2D58A /* MonotonicTime.m */,
D02609BB20C6EB97006C34AC /* Crypto.h */,
D02609BE20C6EC08006C34AC /* Crypto.m */,
D08984F72118816900918162 /* Reachability.h */,
D08984F82118816A00918162 /* Reachability.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -1878,6 +1890,7 @@
D0B843B41DA7FF30005F29E1 /* NBMetadataCore.h in Headers */,
D0B843C41DA7FF30005F29E1 /* NBPhoneNumber.h in Headers */,
D0B843B31DA7FF30005F29E1 /* NBAsYouTypeFormatter.h in Headers */,
D08984F92118816A00918162 /* Reachability.h in Headers */,
D053B3FB1F1651FA00E2D58A /* MonotonicTime.h in Headers */,
D0B843C81DA7FF30005F29E1 /* NBPhoneNumberDesc.h in Headers */,
D0B843CA1DA7FF30005F29E1 /* NBPhoneNumberUtil.h in Headers */,
@@ -1907,6 +1920,7 @@
D050F2571E4A5AC500988324 /* NBMetadataCoreTestMapper.h in Headers */,
D050F2591E4A5AC500988324 /* NBNumberFormat.h in Headers */,
D050F25D1E4A5AC500988324 /* NBPhoneNumberDefines.h in Headers */,
D08984FA2118816A00918162 /* Reachability.h in Headers */,
D050F25B1E4A5AC500988324 /* NBPhoneMetaDataGenerator.h in Headers */,
D050F2581E4A5AC500988324 /* NBMetadataHelper.h in Headers */,
);
@@ -2169,6 +2183,7 @@
D053B3FE1F16534400E2D58A /* MonotonicTime.swift in Sources */,
D0C50E341E93A86600F62E39 /* CallSessionManager.swift in Sources */,
D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */,
D08984FB2118816A00918162 /* Reachability.m in Sources */,
D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */,
D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */,
C23BC3871E9BE3CA00D79F92 /* ImportContact.swift in Sources */,
@@ -2381,6 +2396,7 @@
D0B843C51DA7FF30005F29E1 /* NBPhoneNumber.m in Sources */,
D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */,
D03B0D081D62255C00955575 /* ChannelState.swift in Sources */,
D08984F521187ECA00918162 /* NetworkType.swift in Sources */,
C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */,
D07047BA1F3DF75500F6A8D4 /* ConsumePersonalMessageAction.swift in Sources */,
D07E413F208A769D00FCA8F0 /* ProxyServersStatuses.swift in Sources */,
@@ -2424,6 +2440,7 @@
D033FEB11E61EB0200644997 /* PeerReportStatus.swift in Sources */,
D0458C891E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */,
D050F26C1E4A5B6D00988324 /* UpdatePeers.swift in Sources */,
D08984F621187ECA00918162 /* NetworkType.swift in Sources */,
D050F26D1E4A5B6D00988324 /* CreateGroup.swift in Sources */,
D0575AF51E9FFDDE006F2541 /* ManagedSynchronizeSavedGifsOperations.swift in Sources */,
D00D34461E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */,
@@ -2653,6 +2670,7 @@
D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */,
D0AD02E41FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */,
D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */,
D08984FC2118816A00918162 /* Reachability.m in Sources */,
D0B844471DAB91FD005F29E1 /* ManagedServiceViews.swift in Sources */,
D0F3A8A91E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */,
D00D343A1E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */,

View File

@@ -791,6 +791,11 @@ public class Account {
return self.networkStateValue.get()
}
private let networkTypeValue = Promise<NetworkType>()
public var networkType: Signal<NetworkType, NoError> {
return self.networkTypeValue.get()
}
private let _loggedOut = ValuePromise<Bool>(false, ignoreRepeated: true)
public var loggedOut: Signal<Bool, NoError> {
return self._loggedOut.get()
@@ -901,6 +906,8 @@ public class Account {
}
self.networkStateValue.set(networkStateSignal |> distinctUntilChanged)
self.networkTypeValue.set(currentNetworkType())
let appliedNotificationToken = self.notificationToken.get()
|> distinctUntilChanged
|> mapToSignal { token -> Signal<Void, NoError> in

View File

@@ -205,7 +205,7 @@ func accountStateReset(postbox: Postbox, network: Network) -> Signal<Void, NoErr
for (_, messageId) in topMesageIds {
if messageId.id > 1 {
var skipHole = false
if let localTopId = transaction.getTopMesssageIndex(peerId: messageId.peerId, namespace: messageId.namespace)?.id {
if let localTopId = transaction.getTopPeerMessageIndex(peerId: messageId.peerId, namespace: messageId.namespace)?.id {
if localTopId >= messageId {
skipHole = true
}

View File

@@ -61,7 +61,7 @@ public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signa
return postbox.transaction { transaction -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
var topTimestamp: Int32?
if let topIndex = transaction.getTopMesssageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
topTimestamp = topIndex.timestamp
}
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil)

View File

@@ -0,0 +1,254 @@
import Foundation
#if os(macOS)
import SwiftSignalKitMac
#else
import SwiftSignalKit
import CoreTelephony
#endif
import TelegramCorePrivateModule
#if os(iOS)
public enum CellularNetworkType {
case unknown
case gprs
case edge
case thirdG
case lte
}
extension CellularNetworkType {
init(accessTechnology: String) {
switch accessTechnology {
case CTRadioAccessTechnologyGPRS:
self = .gprs
case CTRadioAccessTechnologyEdge, CTRadioAccessTechnologyCDMA1x:
self = .edge
case CTRadioAccessTechnologyLTE:
self = .lte
case CTRadioAccessTechnologyWCDMA, CTRadioAccessTechnologyHSDPA, CTRadioAccessTechnologyHSUPA, CTRadioAccessTechnologyCDMAEVDORev0, CTRadioAccessTechnologyCDMAEVDORevA, CTRadioAccessTechnologyCDMAEVDORevB, CTRadioAccessTechnologyeHRPD:
self = .thirdG
default:
self = .unknown
}
}
}
#endif
enum InternalNetworkType: Equatable {
case none
case wifi
case cellular
}
public enum NetworkType: Equatable {
case none
case wifi
#if os(iOS)
case cellular(CellularNetworkType)
#endif
}
extension NetworkType {
#if os(iOS)
init(internalType: InternalNetworkType, cellularType: CellularNetworkType) {
switch internalType {
case .none:
self = .none
case .wifi:
self = .wifi
case .cellular:
self = .cellular(cellularType)
}
}
#else
init(internalType: InternalNetworkType) {
switch internalType {
case .none:
self = .none
case .wifi, .cellular:
self = .wifi
}
}
#endif
}
private final class WrappedReachability: NSObject {
@objc private static func threadImpl() {
while true {
RunLoop.current.run(until: .distantFuture)
}
}
static let thread: Thread = {
let thread = Thread(target: WrappedReachability.self, selector: #selector(WrappedReachability.threadImpl), object: nil)
thread.start()
return thread
}()
@objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) {
f()
}
private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) {
WrappedReachability.perform(#selector(WrappedReachability.dispatchOnThreadImpl(_:)), on: WrappedReachability.thread, with: f, waitUntilDone: false)
}
private let reachability: Reachability
let value: ValuePromise<InternalNetworkType>
override init() {
assert(Thread.current === WrappedReachability.thread)
self.reachability = Reachability.forInternetConnection()
let type: InternalNetworkType
switch self.reachability.currentReachabilityStatus() {
case NotReachable:
type = .none
case ReachableViaWiFi:
type = .wifi
case ReachableViaWWAN:
type = .cellular
default:
type = .none
}
self.value = ValuePromise<InternalNetworkType>(type)
super.init()
self.reachability.reachabilityChanged = { [weak self] status in
WrappedReachability.dispatchOnThread {
guard let strongSelf = self else {
return
}
let internalNetworkType: InternalNetworkType
switch status {
case NotReachable:
internalNetworkType = .none
case ReachableViaWiFi:
internalNetworkType = .wifi
case ReachableViaWWAN:
internalNetworkType = .cellular
default:
internalNetworkType = .none
}
strongSelf.value.set(internalNetworkType)
}
}
self.reachability.startNotifier()
}
static var valueRef: Unmanaged<WrappedReachability>?
static func withInstance(_ f: @escaping (WrappedReachability) -> Void) {
WrappedReachability.dispatchOnThread {
if self.valueRef == nil {
self.valueRef = Unmanaged.passRetained(WrappedReachability())
}
if let valueRef = self.valueRef {
let value = valueRef.takeUnretainedValue()
f(value)
}
}
}
}
private final class NetworkTypeManagerImpl {
let queue: Queue
let updated: (NetworkType) -> Void
var networkTypeDisposable: Disposable?
var currentNetworkType: InternalNetworkType?
var networkType: NetworkType?
#if os(iOS)
var currentCellularType: CellularNetworkType
var cellularTypeObserver: NSObjectProtocol?
#endif
init(queue: Queue, updated: @escaping (NetworkType) -> Void) {
self.queue = queue
self.updated = updated
#if os(iOS)
let telephonyInfo = CTTelephonyNetworkInfo()
let accessTechnology = telephonyInfo.currentRadioAccessTechnology ?? ""
self.currentCellularType = CellularNetworkType(accessTechnology: accessTechnology)
self.cellularTypeObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.CTRadioAccessTechnologyDidChange, object: nil, queue: nil, using: { [weak self] notification in
queue.async {
guard let strongSelf = self else {
return
}
let accessTechnology = telephonyInfo.currentRadioAccessTechnology ?? ""
let cellularType = CellularNetworkType(accessTechnology: accessTechnology)
if strongSelf.currentCellularType != cellularType {
strongSelf.currentCellularType = cellularType
if let currentNetworkType = strongSelf.currentNetworkType {
let networkType = NetworkType(internalType: currentNetworkType, cellularType: cellularType)
if strongSelf.networkType != networkType {
strongSelf.networkType = networkType
strongSelf.updated(networkType)
}
}
}
}
})
#endif
let networkTypeDisposable = MetaDisposable()
self.networkTypeDisposable = networkTypeDisposable
WrappedReachability.withInstance({ [weak self] impl in
networkTypeDisposable.set((impl.value.get()
|> deliverOn(queue)).start(next: { networkStatus in
guard let strongSelf = self else {
return
}
if strongSelf.currentNetworkType != networkStatus {
strongSelf.currentNetworkType = networkStatus
let networkType: NetworkType
#if os(iOS)
networkType = NetworkType(internalType: networkStatus, cellularType: strongSelf.currentCellularType)
#else
networkType = NetworkType(internalType: networkStatus)
#endif
if strongSelf.networkType != networkType {
strongSelf.networkType = networkType
updated(networkType)
}
}
}))
})
}
func stop() {
self.networkTypeDisposable?.dispose()
#if os(iOS)
if let observer = self.cellularTypeObserver {
NotificationCenter.default.removeObserver(observer, name: NSNotification.Name.CTRadioAccessTechnologyDidChange, object: nil)
}
#endif
}
}
func currentNetworkType() -> Signal<NetworkType, NoError> {
return Signal { subscriber in
let queue = Queue()
let disposable = MetaDisposable()
queue.async {
let impl = QueueLocalObject(queue: queue, generate: {
return NetworkTypeManagerImpl(queue: queue, updated: { value in
subscriber.putNext(value)
})
})
disposable.set(ActionDisposable {
impl.with({ impl in
impl.stop()
})
})
}
return disposable
}
}

View File

@@ -0,0 +1,66 @@
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
*/
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
#pragma mark IPv6 Support
//Reachability fully support IPv6. For full details, see ReadMe.md.
extern NSString *kReachabilityChangedNotification;
@interface Reachability : NSObject
@property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status);
/*!
* Use to check the reachability of a given host name.
*/
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
/*!
* Use to check the reachability of a given IP address.
*/
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
/*!
* Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
*/
+ (instancetype)reachabilityForInternetConnection;
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi;
/*!
* Start listening for reachability notifications on the current run loop.
*/
- (BOOL)startNotifier;
- (void)stopNotifier;
- (NetworkStatus)currentReachabilityStatus;
/*!
* WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
*/
- (BOOL)connectionRequired;
@end

350
TelegramCore/Reachability.m Normal file
View File

@@ -0,0 +1,350 @@
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
*/
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <CoreFoundation/CoreFoundation.h>
#import "Reachability.h"
#import <pthread.h>
#import <libkern/OSAtomic.h>
#pragma mark IPv6 Support
//Reachability fully support IPv6. For full details, see ReadMe.md.
NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
#pragma mark - Supporting functions
#define kShouldPrintReachabilityFlags 1
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
@interface ReachabilityAtomic : NSObject
{
pthread_mutex_t _lock;
pthread_mutexattr_t _attr;
id _value;
}
@end
@implementation ReachabilityAtomic
- (instancetype)initWithValue:(id)value {
self = [super init];
if (self != nil) {
pthread_mutex_init(&_lock, NULL);
_value = value;
}
return self;
}
- (void)dealloc {
pthread_mutex_destroy(&_lock);
}
- (id)swap:(id)newValue {
id previousValue = nil;
pthread_mutex_lock(&_lock);
previousValue = _value;
_value = newValue;
pthread_mutex_unlock(&_lock);
return previousValue;
}
- (id)value {
id previousValue = nil;
pthread_mutex_lock(&_lock);
previousValue = _value;
pthread_mutex_unlock(&_lock);
return previousValue;
}
- (id)modify:(id (^)(id))f {
id newValue = nil;
pthread_mutex_lock(&_lock);
newValue = f(_value);
_value = newValue;
pthread_mutex_unlock(&_lock);
return newValue;
}
- (id)with:(id (^)(id))f {
id result = nil;
pthread_mutex_lock(&_lock);
result = f(_value);
pthread_mutex_unlock(&_lock);
return result;
}
@end
static int32_t nextKey = 1;
static ReachabilityAtomic *contexts() {
static ReachabilityAtomic *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[ReachabilityAtomic alloc] initWithValue:@{}];
});
return instance;
}
static void withContext(int32_t key, void (^f)(Reachability *)) {
Reachability *reachability = [contexts() with:^id(NSDictionary *dict) {
return dict[@(key)];
}];
f(reachability);
}
static int32_t addContext(Reachability *context) {
int32_t key = OSAtomicIncrement32(&nextKey);
[contexts() modify:^id(NSMutableDictionary *dict) {
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
updatedDict[@(key)] = context;
return updatedDict;
}];
return key;
}
static void removeContext(int32_t key) {
[contexts() modify:^id(NSMutableDictionary *dict) {
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
[updatedDict removeObjectForKey:@(key)];
return updatedDict;
}];
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
//NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
//NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
int32_t key = (int32_t)((intptr_t)info);
withContext(key, ^(Reachability *context) {
if ([context isKindOfClass:[Reachability class]] && context.reachabilityChanged != nil)
context.reachabilityChanged(context.currentReachabilityStatus);
});
}
#pragma mark - Reachability implementation
@implementation Reachability
{
int32_t _key;
SCNetworkReachabilityRef _reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
Reachability* returnValue = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if (reachability != NULL)
{
returnValue= [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
}
else {
CFRelease(reachability);
}
}
if (returnValue) {
returnValue->_key = addContext(returnValue);
}
return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
Reachability* returnValue = NULL;
if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
}
else {
CFRelease(reachability);
}
}
if (returnValue) {
returnValue->_key = addContext(returnValue);
}
return returnValue;
}
+ (instancetype)reachabilityForInternetConnection
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}
#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi
#pragma mark - Start and stop notifier
- (BOOL)startNotifier
{
BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (void *)((intptr_t)_key), NULL, NULL, NULL};
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
{
if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
returnValue = YES;
}
}
return returnValue;
}
- (void)stopNotifier
{
if (_reachabilityRef != NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void)dealloc
{
removeContext(_key);
[self stopNotifier];
if (_reachabilityRef != NULL)
{
CFRelease(_reachabilityRef);
}
}
#pragma mark - Network Flag Handling
- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// The target host is not reachable.
return NotReachable;
}
NetworkStatus returnValue = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
/*
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
*/
returnValue = ReachableViaWiFi;
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
/*
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
*/
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
/*
... and no [user] intervention is needed...
*/
returnValue = ReachableViaWiFi;
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
returnValue = ReachableViaWWAN;
}
return returnValue;
}
- (BOOL)connectionRequired
{
NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
NetworkStatus returnValue = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
returnValue = [self networkStatusForFlags:flags];
}
return returnValue;
}
@end

View File

@@ -2,5 +2,6 @@
#define TelegramCoreIncludes_h
#import "Crypto.h"
#import "Reachability.h"
#endif