Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "Reachability",
module_name = "Reachability",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Reachability/LegacyReachability:LegacyReachability",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
],
visibility = [
"//visibility:public",
],
)
@@ -0,0 +1,22 @@
objc_library(
name = "LegacyReachability",
enable_modules = True,
module_name = "LegacyReachability",
srcs = glob([
"Sources/*.m",
]),
hdrs = glob([
"PublicHeaders/**/*.h",
]),
includes = [
"PublicHeaders",
],
sdk_frameworks = [
"Foundation",
"SystemConfiguration",
],
visibility = [
"//visibility:public",
],
)
@@ -0,0 +1,32 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "LegacyReachability",
platforms: [.macOS(.v10_13)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "LegacyReachability",
targets: ["LegacyReachability"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "LegacyReachability",
dependencies: [],
path: ".",
exclude: ["BUILD"],
publicHeadersPath: "PublicHeaders",
cSettings: [
.headerSearchPath("PublicHeaders")
]),
]
)
@@ -0,0 +1,58 @@
#ifndef LegacyReachability_h
#define LegacyReachability_h
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
struct sockaddr;
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
extern NSString *kReachabilityChangedNotification;
@interface LegacyReachability : 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
#endif
@@ -0,0 +1,359 @@
/*
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 <LegacyReachability/LegacyReachability.h>
#import <pthread.h>
#import <os/lock.h>
#import <libkern/OSAtomic.h>
#import <stdatomic.h>
#pragma mark IPv6 Support
//Reachability fully support IPv6. For full details, see ReadMe.md.
NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
#pragma mark - Supporting functions
#define kShouldPrintReachabilityFlags 0
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",
#if TARGET_OS_IPHONE
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-'
#else
'-'
#endif
,
(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 _Atomic 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)(LegacyReachability *)) {
LegacyReachability *reachability = [contexts() with:^id(NSDictionary *dict) {
return dict[@(key)];
}];
f(reachability);
}
static int32_t addContext(LegacyReachability *context) {
int32_t key = atomic_fetch_add_explicit(&nextKey, 1, memory_order_relaxed);
[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: [LegacyReachability class]], @"info was wrong class in ReachabilityCallback");
int32_t key = (int32_t)((intptr_t)info);
withContext(key, ^(LegacyReachability *context) {
if ([context isKindOfClass:[LegacyReachability class]] && context.reachabilityChanged != nil)
context.reachabilityChanged(context.currentReachabilityStatus);
});
}
#pragma mark - LegacyReachability implementation
@implementation LegacyReachability
{
int32_t _key;
SCNetworkReachabilityRef _reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
LegacyReachability* 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);
LegacyReachability* 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 TARGET_OS_IPHONE
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
returnValue = ReachableViaWWAN;
}
#endif
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
+30
View File
@@ -0,0 +1,30 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Reachability",
platforms: [.macOS(.v10_13)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Reachability",
targets: ["Reachability"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "LegacyReachability", path: "LegacyReachability"),
.package(name: "SSignalKit", path: "../SSignalKit"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Reachability",
dependencies: [.product(name: "LegacyReachability", package: "LegacyReachability", condition: nil),
.product(name: "SwiftSignalKit", package: "SSignalKit", condition: nil)],
path: "Sources"),
]
)
@@ -0,0 +1,180 @@
import Foundation
import SwiftSignalKit
import LegacyReachability
import Network
private final class WrappedLegacyReachability: NSObject {
@objc private static func threadImpl() {
while true {
RunLoop.current.run(until: .distantFuture)
}
}
private static let thread: Thread = {
let thread = Thread(target: WrappedLegacyReachability.self, selector: #selector(WrappedLegacyReachability.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) {
WrappedLegacyReachability.perform(#selector(WrappedLegacyReachability.dispatchOnThreadImpl(_:)), on: WrappedLegacyReachability.thread, with: f, waitUntilDone: false)
}
private let reachability: LegacyReachability
let value: ValuePromise<Reachability.NetworkType>
override init() {
assert(Thread.current === WrappedLegacyReachability.thread)
self.reachability = LegacyReachability.forInternetConnection()
let type: Reachability.NetworkType
switch self.reachability.currentReachabilityStatus() {
case NotReachable:
type = .none
case ReachableViaWiFi:
type = .wifi
case ReachableViaWWAN:
type = .cellular
default:
type = .none
}
self.value = ValuePromise<Reachability.NetworkType>(type)
super.init()
self.reachability.reachabilityChanged = { [weak self] status in
WrappedLegacyReachability.dispatchOnThread {
guard let strongSelf = self else {
return
}
let internalNetworkType: Reachability.NetworkType
switch status {
case NotReachable:
internalNetworkType = .none
case ReachableViaWiFi:
internalNetworkType = .wifi
case ReachableViaWWAN:
internalNetworkType = .cellular
default:
internalNetworkType = .none
}
strongSelf.value.set(internalNetworkType)
}
}
self.reachability.startNotifier()
}
private static var valueRef: Unmanaged<WrappedLegacyReachability>?
static func withInstance(_ f: @escaping (WrappedLegacyReachability) -> Void) {
WrappedLegacyReachability.dispatchOnThread {
if self.valueRef == nil {
self.valueRef = Unmanaged.passRetained(WrappedLegacyReachability())
}
if let valueRef = self.valueRef {
let value = valueRef.takeUnretainedValue()
f(value)
}
}
}
}
@available(iOSApplicationExtension 12.0, iOS 12.0, macOS 14.0, *)
private final class PathMonitor {
private let queue: Queue
private let monitor: NWPathMonitor
let networkType = Promise<Reachability.NetworkType>()
init(queue: Queue) {
self.queue = queue
self.monitor = NWPathMonitor()
self.monitor.pathUpdateHandler = { [weak self] path in
queue.async {
guard let strongSelf = self else {
return
}
let networkType: Reachability.NetworkType
if path.status == .satisfied {
if path.usesInterfaceType(.cellular) {
networkType = .cellular
} else {
networkType = .wifi
}
} else {
networkType = .none
}
strongSelf.networkType.set(.single(networkType))
}
}
self.monitor.start(queue: self.queue.queue)
let networkType: Reachability.NetworkType
let path = self.monitor.currentPath
if path.status == .satisfied {
if path.usesInterfaceType(.cellular) {
networkType = .cellular
} else {
networkType = .wifi
}
} else {
networkType = .none
}
self.networkType.set(.single(networkType))
}
}
@available(iOSApplicationExtension 12.0, iOS 12.0, macOS 14.0, *)
private final class SharedPathMonitor {
static let queue = Queue()
static let impl = QueueLocalObject<PathMonitor>(queue: queue, generate: {
return PathMonitor(queue: queue)
})
}
public enum Reachability {
public enum NetworkType: Equatable {
case none
case wifi
case cellular
}
public static var networkType: Signal<NetworkType, NoError> {
if #available(iOSApplicationExtension 12.0, iOS 12.0, macOS 14.0, *) {
return Signal { subscriber in
let disposable = MetaDisposable()
SharedPathMonitor.impl.with { impl in
disposable.set(impl.networkType.get().start(next: { value in
subscriber.putNext(value)
}))
}
return disposable
}
|> distinctUntilChanged
} else {
return Signal { subscriber in
let disposable = MetaDisposable()
WrappedLegacyReachability.withInstance({ impl in
disposable.set(impl.value.get().start(next: { next in
subscriber.putNext(next)
}))
})
return disposable
}
|> distinctUntilChanged
}
}
}