diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index 181060405a..7c0b2789ba 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -100,7 +100,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case voiceConference case preferredVideoCodec(Int, String, String?, Bool) case disableVideoAspectScaling(Bool) - case enableVoipTcp(Bool) + case enableNetworkFramework(Bool) case restorePurchases(PresentationTheme) case hostInfo(PresentationTheme, String) case versionInfo(PresentationTheme) @@ -121,7 +121,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.experiments.rawValue case .preferredVideoCodec: return DebugControllerSection.videoExperiments.rawValue - case .disableVideoAspectScaling, .enableVoipTcp: + case .disableVideoAspectScaling, .enableNetworkFramework: return DebugControllerSection.videoExperiments2.rawValue case .hostInfo, .versionInfo: return DebugControllerSection.info.rawValue @@ -224,7 +224,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 45 + index case .disableVideoAspectScaling: return 100 - case .enableVoipTcp: + case .enableNetworkFramework: return 101 case .hostInfo: return 102 @@ -1281,15 +1281,15 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) }).start() }) - case let .enableVoipTcp(value): - return ItemListSwitchItem(presentationData: presentationData, title: "Enable VoIP TCP", value: !value, sectionId: self.section, style: .blocks, updated: { value in - let _ = arguments.sharedContext.accountManager.transaction ({ transaction in - transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings - settings.enableVoipTcp = value - return PreferencesEntry(settings) - }) - }).start() + case let .enableNetworkFramework(value): + return ItemListSwitchItem(presentationData: presentationData, title: "Network X [Restart App]", value: value, sectionId: self.section, style: .blocks, updated: { value in + if let context = arguments.context { + let _ = updateNetworkSettingsInteractively(postbox: context.account.postbox, network: context.account.network, { settings in + var settings = settings + settings.useNetworkFramework = value + return settings + }).start() + } }) case .restorePurchases: return ItemListActionItem(presentationData: presentationData, title: "Restore Purchases", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { @@ -1397,7 +1397,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present if isMainApp { entries.append(.disableVideoAspectScaling(experimentalSettings.disableVideoAspectScaling)) - entries.append(.enableVoipTcp(experimentalSettings.enableVoipTcp)) + entries.append(.enableNetworkFramework(networkSettings?.useNetworkFramework ?? false)) } if let backupHostOverride = networkSettings?.backupHostOverride { diff --git a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTContext.h b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTContext.h index fb58f3638e..03c3202c86 100644 --- a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTContext.h +++ b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTContext.h @@ -1,6 +1,7 @@ #import #import +#import #import @@ -15,6 +16,34 @@ @class MTSignal; @class MTQueue; +@protocol MTTcpConnectionInterface; + +@protocol MTTcpConnectionInterfaceDelegate + +- (void)connectionInterfaceDidReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; +- (void)connectionInterfaceDidReadData:(NSData * _Nonnull)rawData withTag:(long)tag; +- (void)connectionInterfaceDidConnect; +- (void)connectionInterfaceDidDisconnectWithError:(NSError * _Nullable)error; + +@end + +@protocol MTTcpConnectionInterface + +- (void)setGetLogPrefix:(NSString * _Nonnull(^_Nullable)())getLogPrefix; +- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo * _Nullable)usageCalculationInfo; +- (bool)connectToHost:(NSString * _Nonnull)inHost + onPort:(uint16_t)port + viaInterface:(NSString * _Nullable)inInterface + withTimeout:(NSTimeInterval)timeout + error:(NSError * _Nullable * _Nullable)errPtr; +- (void)writeData:(NSData * _Nonnull)data; +- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; +- (void)disconnect; +- (void)resetDelegate; + +@end + + @protocol MTContextChangeListener @optional @@ -51,6 +80,8 @@ @property (nonatomic, readonly) bool useTempAuthKeys; @property (nonatomic) int32_t tempKeyExpiration; +@property (nonatomic, copy) id _Nonnull (^ _Nullable makeTcpConnectionInterface)(id _Nonnull delegate, dispatch_queue_t _Nonnull delegateQueue); + + (int32_t)fixedTimeDifference; + (void)setFixedTimeDifference:(int32_t)fixedTimeDifference; diff --git a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTTcpTransport.h b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTTcpTransport.h index c53639149d..e75e97ad14 100644 --- a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTTcpTransport.h +++ b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTTcpTransport.h @@ -1,5 +1,3 @@ - - #import @interface MTTcpTransport : MTTransport diff --git a/submodules/MtProtoKit/Sources/GCDAsyncSocket.m b/submodules/MtProtoKit/Sources/GCDAsyncSocket.m index 011885b457..470658d86e 100755 --- a/submodules/MtProtoKit/Sources/GCDAsyncSocket.m +++ b/submodules/MtProtoKit/Sources/GCDAsyncSocket.m @@ -2432,7 +2432,7 @@ enum GCDAsyncSocketConfig int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]); if (result == 0) { - bool isWifi = false; + bool isWifi = true; struct sockaddr_in addr; struct ifaddrs* ifaddr; diff --git a/submodules/MtProtoKit/Sources/MTBackupAddressSignals.m b/submodules/MtProtoKit/Sources/MTBackupAddressSignals.m index 0a30ef43cc..be7b1f7ab2 100644 --- a/submodules/MtProtoKit/Sources/MTBackupAddressSignals.m +++ b/submodules/MtProtoKit/Sources/MTBackupAddressSignals.m @@ -280,6 +280,8 @@ static NSString *makeRandomPadding() { MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization encryptionProvider:currentContext.encryptionProvider apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:false]; + context.makeTcpConnectionInterface = currentContext.makeTcpConnectionInterface; + NSInteger authTokenMasterDatacenterId = 0; NSNumber *requiredAuthToken = nil; bool allowUnboundEphemeralKeys = true; diff --git a/submodules/MtProtoKit/Sources/MTProxyConnectivity.m b/submodules/MtProtoKit/Sources/MTProxyConnectivity.m index 9a780104fa..80c1bef6d3 100644 --- a/submodules/MtProtoKit/Sources/MTProxyConnectivity.m +++ b/submodules/MtProtoKit/Sources/MTProxyConnectivity.m @@ -66,6 +66,8 @@ MTContext *proxyContext = [[MTContext alloc] initWithSerialization:context.serialization encryptionProvider:context.encryptionProvider apiEnvironment:[[context apiEnvironment] withUpdatedSocksProxySettings:settings] isTestingEnvironment:context.isTestingEnvironment useTempAuthKeys:false]; + proxyContext.makeTcpConnectionInterface = context.makeTcpConnectionInterface; + MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:proxyContext datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpConnection class] address:address media:false] interface:nil usageCalculationInfo:nil getLogPrefix:nil]; __weak MTTcpConnection *weakConnection = connection; __block NSTimeInterval startTime = CFAbsoluteTimeGetCurrent(); diff --git a/submodules/MtProtoKit/Sources/MTTcpConnection.m b/submodules/MtProtoKit/Sources/MTTcpConnection.m index 9cc61b7fcd..77819c28ec 100644 --- a/submodules/MtProtoKit/Sources/MTTcpConnection.m +++ b/submodules/MtProtoKit/Sources/MTTcpConnection.m @@ -606,33 +606,6 @@ struct ctr_state { @end -@protocol MTTcpConnectionInterface; - -@protocol MTTcpConnectionInterfaceDelegate - -- (void)connectionInterface:(id)connectionInterface didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; -- (void)connectionInterface:(id)connectionInterface didReadData:(NSData *)rawData withTag:(long)tag; -- (void)connectionInterface:(id)connectionInterface didConnectToHost:(NSString *)host port:(uint16_t)port; -- (void)connectionInterfaceDidDisconnect:(id)connectionInterface withError:(NSError *)error; - -@end - -@protocol MTTcpConnectionInterface - -- (void)setGetLogPrefix:(NSString *(^)())getLogPrefix; -- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo; -- (bool)connectToHost:(NSString *)inHost - onPort:(uint16_t)port - viaInterface:(NSString *)inInterface - withTimeout:(NSTimeInterval)timeout - error:(NSError **)errPtr; -- (void)writeData:(NSData *)data; -- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; -- (void)disconnect; -- (void)resetDelegate; - -@end - @interface MTGcdAsyncSocketTcpConnectionInterface: NSObject { GCDAsyncSocket *_socket; __weak id _delegate; @@ -687,28 +660,28 @@ struct ctr_state { - (void)socket:(GCDAsyncSocket *)socket didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag { id delegate = _delegate; if (delegate) { - [delegate connectionInterface:self didReadPartialDataOfLength:partialLength tag:tag]; + [delegate connectionInterfaceDidReadPartialDataOfLength:partialLength tag:tag]; } } - (void)socket:(GCDAsyncSocket *)socket didReadData:(NSData *)rawData withTag:(long)tag { id delegate = _delegate; if (delegate) { - [delegate connectionInterface:self didReadData:rawData withTag:tag]; + [delegate connectionInterfaceDidReadData:rawData withTag:tag]; } } - (void)socket:(GCDAsyncSocket *)socket didConnectToHost:(NSString *)host port:(uint16_t)port { id delegate = _delegate; if (delegate) { - [delegate connectionInterface:self didConnectToHost:host port:port]; + [delegate connectionInterfaceDidConnect]; } } - (void)socketDidDisconnect:(GCDAsyncSocket *)socket withError:(NSError *)error { id delegate = _delegate; if (delegate) { - [delegate connectionInterfaceDidDisconnect:self withError:error]; + [delegate connectionInterfaceDidDisconnectWithError:error]; } } @@ -791,6 +764,8 @@ struct ctr_state { @property (nonatomic) int64_t packetHeadDecodeToken; @property (nonatomic, strong) id packetProgressToken; +@property (nonatomic, copy) id _Nonnull (^ _Nullable makeTcpConnectionInterface)(id _Nonnull delegate, dispatch_queue_t _Nonnull delegateQueue); + @end @implementation MTTcpConnection @@ -826,6 +801,8 @@ struct ctr_state { _interface = interface; _usageCalculationInfo = usageCalculationInfo; + _makeTcpConnectionInterface = context.makeTcpConnectionInterface; + if (context.apiEnvironment.datacenterAddressOverrides[@(datacenterId)] != nil) { _firstPacketControlByte = [context.apiEnvironment tcpPayloadPrefix]; } @@ -917,7 +894,12 @@ struct ctr_state { { if (_socket == nil) { - _socket = [[MTGcdAsyncSocketTcpConnectionInterface alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]]; + if (_makeTcpConnectionInterface) { + _socket = _makeTcpConnectionInterface(self, [[MTTcpConnection tcpQueue] nativeQueue]); + } + if (_socket == nil) { + _socket = [[MTGcdAsyncSocketTcpConnectionInterface alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]]; + } [_socket setGetLogPrefix:_getLogPrefix]; [_socket setUsageCalculationInfo:_usageCalculationInfo]; @@ -1407,7 +1389,7 @@ struct ctr_state { [self closeAndNotifyWithError:true]; } -- (void)connectionInterface:(id)__unused connectionInterface didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)__unused tag +- (void)connectionInterfaceDidReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)__unused tag { if (_closed) return; @@ -1477,7 +1459,7 @@ struct ctr_state { [_socket readDataToLength:4 withTimeout:-1 tag:MTTcpSocksRequest]; } -- (void)connectionInterface:(id)__unused connectionInterface didReadData:(NSData *)rawData withTag:(long)tag +- (void)connectionInterfaceDidReadData:(NSData *)rawData withTag:(long)tag { if (_closed) return; @@ -2018,7 +2000,7 @@ struct ctr_state { } } -- (void)connectionInterface:(id)__unused connectionInterface didConnectToHost:(NSString *)__unused host port:(uint16_t)__unused port +- (void)connectionInterfaceDidConnect { if (_socksIp != nil) { @@ -2031,7 +2013,7 @@ struct ctr_state { } } -- (void)connectionInterfaceDidDisconnect:(id)__unused connectionInterface withError:(NSError *)error +- (void)connectionInterfaceDidDisconnectWithError:(NSError *)error { if (error != nil) { if (MTLogEnabled()) { diff --git a/submodules/TelegramCore/Sources/Network/Network.swift b/submodules/TelegramCore/Sources/Network/Network.swift index 8e7a4b2264..e00b8ccda4 100644 --- a/submodules/TelegramCore/Sources/Network/Network.swift +++ b/submodules/TelegramCore/Sources/Network/Network.swift @@ -494,6 +494,14 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa let context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys) + if let networkSettings = networkSettings, networkSettings.useNetworkFramework { + if #available(iOS 12.0, *) { + context.makeTcpConnectionInterface = { delegate, delegateQueue in + return NetworkFrameworkTcpConnectionInterface(delegate: delegate, delegateQueue: delegateQueue) + } + } + } + let seedAddressList: [Int: [String]] if testingEnvironment { diff --git a/submodules/TelegramCore/Sources/Network/NetworkFrameworkTcpConnectionInterface.swift b/submodules/TelegramCore/Sources/Network/NetworkFrameworkTcpConnectionInterface.swift new file mode 100644 index 0000000000..c2701924d8 --- /dev/null +++ b/submodules/TelegramCore/Sources/Network/NetworkFrameworkTcpConnectionInterface.swift @@ -0,0 +1,287 @@ +import Foundation +import Network + +import MtProtoKit +import SwiftSignalKit + +@available(iOS 12.0, *) +final class NetworkFrameworkTcpConnectionInterface: NSObject, MTTcpConnectionInterface { + private final class Impl { + private let queue: Queue + + private weak var delegate: MTTcpConnectionInterfaceDelegate? + private let delegateQueue: DispatchQueue + + private var connection: NWConnection? + private var reportedDisconnection: Bool = false + + private var currentInterfaceIsWifi: Bool = true + + private var connectTimeoutTimer: SwiftSignalKit.Timer? + + private var usageCalculationInfo: MTNetworkUsageCalculationInfo? + private var networkUsageManager: MTNetworkUsageManager? + + init( + queue: Queue, + delegate: MTTcpConnectionInterfaceDelegate, + delegateQueue: DispatchQueue + ) { + self.queue = queue + + self.delegate = delegate + self.delegateQueue = delegateQueue + } + + deinit { + } + + func setUsageCalculationInfo(_ usageCalculationInfo: MTNetworkUsageCalculationInfo?) { + if self.usageCalculationInfo !== usageCalculationInfo { + self.usageCalculationInfo = usageCalculationInfo + if let usageCalculationInfo = usageCalculationInfo { + self.networkUsageManager = MTNetworkUsageManager(info: usageCalculationInfo) + } else { + self.networkUsageManager = nil + } + } + } + + func connect(host: String, port: UInt16, timeout: Double) { + if self.connection != nil { + assertionFailure("A connection already exists") + return + } + + let host = NWEndpoint.Host(host) + let port = NWEndpoint.Port(rawValue: port)! + + let tcpOptions = NWProtocolTCP.Options() + tcpOptions.noDelay = true + tcpOptions.enableKeepalive = true + tcpOptions.keepaliveIdle = 5 + tcpOptions.keepaliveCount = 2 + tcpOptions.keepaliveInterval = 5 + tcpOptions.enableFastOpen = true + + let parameters = NWParameters(tls: nil, tcp: tcpOptions) + let connection = NWConnection(host: host, port: port, using: parameters) + self.connection = connection + + let queue = self.queue + connection.stateUpdateHandler = { [weak self] state in + queue.async { + self?.stateUpdated(state: state) + } + } + + connection.pathUpdateHandler = { [weak self] path in + queue.async { + guard let self = self else { + return + } + if path.usesInterfaceType(.cellular) { + self.currentInterfaceIsWifi = false + } else { + self.currentInterfaceIsWifi = true + } + } + } + + connection.viabilityUpdateHandler = { [weak self] isViable in + queue.async { + guard let self = self else { + return + } + if !isViable { + self.cancelWithError(error: nil) + } + } + } + + connection.betterPathUpdateHandler = { [weak self] hasBetterPath in + queue.async { + guard let self = self else { + return + } + if hasBetterPath { + self.cancelWithError(error: nil) + } + } + } + + self.connectTimeoutTimer = SwiftSignalKit.Timer(timeout: timeout, repeat: false, completion: { [weak self] in + guard let self = self else { + return + } + self.connectTimeoutTimer = nil + self.cancelWithError(error: nil) + }, queue: self.queue) + self.connectTimeoutTimer?.start() + + connection.start(queue: self.queue.queue) + } + + private func stateUpdated(state: NWConnection.State) { + switch state { + case .ready: + if let path = self.connection?.currentPath { + if path.usesInterfaceType(.cellular) { + self.currentInterfaceIsWifi = false + } else { + self.currentInterfaceIsWifi = true + } + } + + if let connectTimeoutTimer = connectTimeoutTimer { + self.connectTimeoutTimer = nil + connectTimeoutTimer.invalidate() + } + + weak var delegate = self.delegate + self.delegateQueue.async { + if let delegate = delegate { + delegate.connectionInterfaceDidConnect() + } + } + case let .failed(error): + self.cancelWithError(error: error) + default: + break + } + } + + func write(data: Data) { + guard let connection = self.connection else { + assertionFailure("Connection not ready") + return + } + + connection.send(content: data, completion: .contentProcessed({ _ in + })) + + self.networkUsageManager?.addOutgoingBytes(UInt(data.count), interface: self.currentInterfaceIsWifi ? MTNetworkUsageManagerInterfaceOther : MTNetworkUsageManagerInterfaceWWAN) + } + + func read(length: Int, timeout: Double, tag: Int) { + guard let connection = self.connection else { + print("Connection not ready") + return + } + + connection.receive(minimumIncompleteLength: length, maximumLength: length, completion: { [weak self] data, context, isComplete, error in + guard let self = self else { + return + } + if let data = data { + self.networkUsageManager?.addIncomingBytes(UInt(data.count), interface: self.currentInterfaceIsWifi ? MTNetworkUsageManagerInterfaceOther : MTNetworkUsageManagerInterfaceWWAN) + + if isComplete || data.count == length { + if data.count == length { + weak var delegate = self.delegate + self.delegateQueue.async { + if let delegate = delegate { + delegate.connectionInterfaceDidRead(data, withTag: tag) + } + } + } else { + self.cancelWithError(error: error) + } + } else { + weak var delegate = self.delegate + let dataCount = data.count + self.delegateQueue.async { + if let delegate = delegate { + delegate.connectionInterfaceDidReadPartialData(ofLength: UInt(dataCount), tag: tag) + } + } + } + } else { + self.cancelWithError(error: error) + } + }) + } + + private func cancelWithError(error: Error?) { + if let connectTimeoutTimer = self.connectTimeoutTimer { + self.connectTimeoutTimer = nil + connectTimeoutTimer.invalidate() + } + + if !self.reportedDisconnection { + self.reportedDisconnection = true + weak var delegate = self.delegate + self.delegateQueue.async { + if let delegate = delegate { + delegate.connectionInterfaceDidDisconnectWithError(error) + } + } + } + if let connection = self.connection { + self.connection = nil + connection.cancel() + } + } + + func disconnect() { + self.cancelWithError(error: nil) + } + + func resetDelegate() { + self.delegate = nil + } + } + + private static let sharedQueue = Queue(name: "NetworkFrameworkTcpConnectionInteface") + + private let queue: Queue + private let impl: QueueLocalObject + + init(delegate: MTTcpConnectionInterfaceDelegate, delegateQueue: DispatchQueue) { + let queue = NetworkFrameworkTcpConnectionInterface.sharedQueue + self.queue = queue + self.impl = QueueLocalObject(queue: queue, generate: { + return Impl(queue: queue, delegate: delegate, delegateQueue: delegateQueue) + }) + } + + func setGetLogPrefix(_ getLogPrefix: (() -> String)?) { + } + + func setUsageCalculationInfo(_ usageCalculationInfo: MTNetworkUsageCalculationInfo?) { + self.impl.with { impl in + impl.setUsageCalculationInfo(usageCalculationInfo) + } + } + + func connect(toHost inHost: String, onPort port: UInt16, viaInterface inInterface: String?, withTimeout timeout: TimeInterval, error errPtr: NSErrorPointer) -> Bool { + self.impl.with { impl in + impl.connect(host: inHost, port: port, timeout: timeout) + } + return true + } + + func write(_ data: Data) { + self.impl.with { impl in + impl.write(data: data) + } + } + + func readData(toLength length: UInt, withTimeout timeout: TimeInterval, tag: Int) { + self.impl.with { impl in + impl.read(length: Int(length), timeout: timeout, tag: tag) + } + } + + func disconnect() { + self.impl.with { impl in + impl.disconnect() + } + } + + func resetDelegate() { + self.impl.with { impl in + impl.resetDelegate() + } + } +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_NetworkSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_NetworkSettings.swift index 0936f36666..630685355e 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_NetworkSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_NetworkSettings.swift @@ -4,15 +4,17 @@ public struct NetworkSettings: Codable { public var reducedBackupDiscoveryTimeout: Bool public var applicationUpdateUrlPrefix: String? public var backupHostOverride: String? + public var useNetworkFramework: Bool public static var defaultSettings: NetworkSettings { - return NetworkSettings(reducedBackupDiscoveryTimeout: false, applicationUpdateUrlPrefix: nil, backupHostOverride: nil) + return NetworkSettings(reducedBackupDiscoveryTimeout: false, applicationUpdateUrlPrefix: nil, backupHostOverride: nil, useNetworkFramework: false) } - public init(reducedBackupDiscoveryTimeout: Bool, applicationUpdateUrlPrefix: String?, backupHostOverride: String?) { + public init(reducedBackupDiscoveryTimeout: Bool, applicationUpdateUrlPrefix: String?, backupHostOverride: String?, useNetworkFramework: Bool) { self.reducedBackupDiscoveryTimeout = reducedBackupDiscoveryTimeout self.applicationUpdateUrlPrefix = applicationUpdateUrlPrefix self.backupHostOverride = backupHostOverride + self.useNetworkFramework = useNetworkFramework } public init(from decoder: Decoder) throws { @@ -21,6 +23,7 @@ public struct NetworkSettings: Codable { self.reducedBackupDiscoveryTimeout = ((try? container.decode(Int32.self, forKey: "reducedBackupDiscoveryTimeout")) ?? 0) != 0 self.applicationUpdateUrlPrefix = try? container.decodeIfPresent(String.self, forKey: "applicationUpdateUrlPrefix") self.backupHostOverride = try? container.decodeIfPresent(String.self, forKey: "backupHostOverride") + self.useNetworkFramework = try container.decodeIfPresent(Bool.self, forKey: "useNetworkFramework") ?? NetworkSettings.defaultSettings.useNetworkFramework } public func encode(to encoder: Encoder) throws { @@ -29,5 +32,6 @@ public struct NetworkSettings: Codable { try container.encode((self.reducedBackupDiscoveryTimeout ? 1 : 0) as Int32, forKey: "reducedBackupDiscoveryTimeout") try container.encodeIfPresent(self.applicationUpdateUrlPrefix, forKey: "applicationUpdateUrlPrefix") try container.encodeIfPresent(self.backupHostOverride, forKey: "backupHostOverride") + try container.encode(self.useNetworkFramework, forKey: "useNetworkFramework") } }