Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2023-03-03 21:32:51 +04:00
commit 4c794a0a91
13 changed files with 874 additions and 478 deletions

View File

@ -600,7 +600,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
var text = ""
if let timestamp = item.timestamp {
let dateText = humanReadableStringForTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: timestamp, alwaysShowTime: false, allowYesterday: true, format: HumanReadableStringFormat(
let dateText = humanReadableStringForTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: timestamp, alwaysShowTime: true, allowYesterday: true, format: HumanReadableStringFormat(
dateFormatString: { value in
return PresentationStrings.FormattedString(string: presentationData.strings.Chat_MessageSeenTimestamp_Date(value).string, ranges: [])
},

View File

@ -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 {

View File

@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTNetworkUsageCalculationInfo.h>
#import <EncryptionProvider/EncryptionProvider.h>
@ -15,6 +16,34 @@
@class MTSignal;
@class MTQueue;
@protocol MTTcpConnectionInterface;
@protocol MTTcpConnectionInterfaceDelegate <NSObject>
- (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<NSObject>
- (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 <NSObject>
@optional
@ -51,6 +80,8 @@
@property (nonatomic, readonly) bool useTempAuthKeys;
@property (nonatomic) int32_t tempKeyExpiration;
@property (nonatomic, copy) id<MTTcpConnectionInterface> _Nonnull (^ _Nullable makeTcpConnectionInterface)(id<MTTcpConnectionInterfaceDelegate> _Nonnull delegate, dispatch_queue_t _Nonnull delegateQueue);
+ (int32_t)fixedTimeDifference;
+ (void)setFixedTimeDifference:(int32_t)fixedTimeDifference;

View File

@ -1,5 +1,3 @@
#import <MtProtoKit/MTTransport.h>
@interface MTTcpTransport : MTTransport

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -606,33 +606,6 @@ struct ctr_state {
@end
@protocol MTTcpConnectionInterface;
@protocol MTTcpConnectionInterfaceDelegate <NSObject>
- (void)connectionInterface:(id<MTTcpConnectionInterface>)connectionInterface didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- (void)connectionInterface:(id<MTTcpConnectionInterface>)connectionInterface didReadData:(NSData *)rawData withTag:(long)tag;
- (void)connectionInterface:(id<MTTcpConnectionInterface>)connectionInterface didConnectToHost:(NSString *)host port:(uint16_t)port;
- (void)connectionInterfaceDidDisconnect:(id<MTTcpConnectionInterface>)connectionInterface withError:(NSError *)error;
@end
@protocol MTTcpConnectionInterface<NSObject>
- (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<MTTcpConnectionInterface, GCDAsyncSocketDelegate> {
GCDAsyncSocket *_socket;
__weak id<MTTcpConnectionInterfaceDelegate> _delegate;
@ -687,28 +660,28 @@ struct ctr_state {
- (void)socket:(GCDAsyncSocket *)socket didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
id<MTTcpConnectionInterfaceDelegate> 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<MTTcpConnectionInterfaceDelegate> 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<MTTcpConnectionInterfaceDelegate> delegate = _delegate;
if (delegate) {
[delegate connectionInterface:self didConnectToHost:host port:port];
[delegate connectionInterfaceDidConnect];
}
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)socket withError:(NSError *)error {
id<MTTcpConnectionInterfaceDelegate> 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<MTTcpConnectionInterface> _Nonnull (^ _Nullable makeTcpConnectionInterface)(id<MTTcpConnectionInterfaceDelegate> _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<MTTcpConnectionInterface>)__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<MTTcpConnectionInterface>)__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<MTTcpConnectionInterface>)__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<MTTcpConnectionInterface>)__unused connectionInterface withError:(NSError *)error
- (void)connectionInterfaceDidDisconnectWithError:(NSError *)error
{
if (error != nil) {
if (MTLogEnabled()) {

View File

@ -3913,8 +3913,13 @@ public class Postbox {
}
public func setCanBeginTransactions(_ value: Bool, afterTransactionIfRunning: @escaping () -> Void = {}) {
let storageBox = self.mediaBox.storageBox
self.impl.with { impl in
impl.setCanBeginTransactions(value, afterTransactionIfRunning: afterTransactionIfRunning)
impl.setCanBeginTransactions(value, afterTransactionIfRunning: {
storageBox.setCanBeginTransactions(value, afterTransactionIfRunning: {
afterTransactionIfRunning()
})
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 {

View File

@ -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<Impl>
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()
}
}
}

View File

@ -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")
}
}