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 = "" var text = ""
if let timestamp = item.timestamp { 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 dateFormatString: { value in
return PresentationStrings.FormattedString(string: presentationData.strings.Chat_MessageSeenTimestamp_Date(value).string, ranges: []) 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 voiceConference
case preferredVideoCodec(Int, String, String?, Bool) case preferredVideoCodec(Int, String, String?, Bool)
case disableVideoAspectScaling(Bool) case disableVideoAspectScaling(Bool)
case enableVoipTcp(Bool) case enableNetworkFramework(Bool)
case restorePurchases(PresentationTheme) case restorePurchases(PresentationTheme)
case hostInfo(PresentationTheme, String) case hostInfo(PresentationTheme, String)
case versionInfo(PresentationTheme) case versionInfo(PresentationTheme)
@ -121,7 +121,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.experiments.rawValue return DebugControllerSection.experiments.rawValue
case .preferredVideoCodec: case .preferredVideoCodec:
return DebugControllerSection.videoExperiments.rawValue return DebugControllerSection.videoExperiments.rawValue
case .disableVideoAspectScaling, .enableVoipTcp: case .disableVideoAspectScaling, .enableNetworkFramework:
return DebugControllerSection.videoExperiments2.rawValue return DebugControllerSection.videoExperiments2.rawValue
case .hostInfo, .versionInfo: case .hostInfo, .versionInfo:
return DebugControllerSection.info.rawValue return DebugControllerSection.info.rawValue
@ -224,7 +224,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 45 + index return 45 + index
case .disableVideoAspectScaling: case .disableVideoAspectScaling:
return 100 return 100
case .enableVoipTcp: case .enableNetworkFramework:
return 101 return 101
case .hostInfo: case .hostInfo:
return 102 return 102
@ -1281,15 +1281,15 @@ private enum DebugControllerEntry: ItemListNodeEntry {
}) })
}).start() }).start()
}) })
case let .enableVoipTcp(value): case let .enableNetworkFramework(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Enable VoIP TCP", value: !value, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: "Network X [Restart App]", value: value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in if let context = arguments.context {
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in let _ = updateNetworkSettingsInteractively(postbox: context.account.postbox, network: context.account.network, { settings in
var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings var settings = settings
settings.enableVoipTcp = value settings.useNetworkFramework = value
return PreferencesEntry(settings) return settings
})
}).start() }).start()
}
}) })
case .restorePurchases: case .restorePurchases:
return ItemListActionItem(presentationData: presentationData, title: "Restore Purchases", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { 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 { if isMainApp {
entries.append(.disableVideoAspectScaling(experimentalSettings.disableVideoAspectScaling)) entries.append(.disableVideoAspectScaling(experimentalSettings.disableVideoAspectScaling))
entries.append(.enableVoipTcp(experimentalSettings.enableVoipTcp)) entries.append(.enableNetworkFramework(networkSettings?.useNetworkFramework ?? false))
} }
if let backupHostOverride = networkSettings?.backupHostOverride { if let backupHostOverride = networkSettings?.backupHostOverride {

View File

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

View File

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

View File

@ -2432,7 +2432,7 @@ enum GCDAsyncSocketConfig
int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]); int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]);
if (result == 0) if (result == 0)
{ {
bool isWifi = false; bool isWifi = true;
struct sockaddr_in addr; struct sockaddr_in addr;
struct ifaddrs* ifaddr; 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]; MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization encryptionProvider:currentContext.encryptionProvider apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:false];
context.makeTcpConnectionInterface = currentContext.makeTcpConnectionInterface;
NSInteger authTokenMasterDatacenterId = 0; NSInteger authTokenMasterDatacenterId = 0;
NSNumber *requiredAuthToken = nil; NSNumber *requiredAuthToken = nil;
bool allowUnboundEphemeralKeys = true; 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]; 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]; 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; __weak MTTcpConnection *weakConnection = connection;
__block NSTimeInterval startTime = CFAbsoluteTimeGetCurrent(); __block NSTimeInterval startTime = CFAbsoluteTimeGetCurrent();

View File

@ -606,33 +606,6 @@ struct ctr_state {
@end @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> { @interface MTGcdAsyncSocketTcpConnectionInterface: NSObject<MTTcpConnectionInterface, GCDAsyncSocketDelegate> {
GCDAsyncSocket *_socket; GCDAsyncSocket *_socket;
__weak id<MTTcpConnectionInterfaceDelegate> _delegate; __weak id<MTTcpConnectionInterfaceDelegate> _delegate;
@ -687,28 +660,28 @@ struct ctr_state {
- (void)socket:(GCDAsyncSocket *)socket didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag { - (void)socket:(GCDAsyncSocket *)socket didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
id<MTTcpConnectionInterfaceDelegate> delegate = _delegate; id<MTTcpConnectionInterfaceDelegate> delegate = _delegate;
if (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 { - (void)socket:(GCDAsyncSocket *)socket didReadData:(NSData *)rawData withTag:(long)tag {
id<MTTcpConnectionInterfaceDelegate> delegate = _delegate; id<MTTcpConnectionInterfaceDelegate> delegate = _delegate;
if (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 { - (void)socket:(GCDAsyncSocket *)socket didConnectToHost:(NSString *)host port:(uint16_t)port {
id<MTTcpConnectionInterfaceDelegate> delegate = _delegate; id<MTTcpConnectionInterfaceDelegate> delegate = _delegate;
if (delegate) { if (delegate) {
[delegate connectionInterface:self didConnectToHost:host port:port]; [delegate connectionInterfaceDidConnect];
} }
} }
- (void)socketDidDisconnect:(GCDAsyncSocket *)socket withError:(NSError *)error { - (void)socketDidDisconnect:(GCDAsyncSocket *)socket withError:(NSError *)error {
id<MTTcpConnectionInterfaceDelegate> delegate = _delegate; id<MTTcpConnectionInterfaceDelegate> delegate = _delegate;
if (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) int64_t packetHeadDecodeToken;
@property (nonatomic, strong) id packetProgressToken; @property (nonatomic, strong) id packetProgressToken;
@property (nonatomic, copy) id<MTTcpConnectionInterface> _Nonnull (^ _Nullable makeTcpConnectionInterface)(id<MTTcpConnectionInterfaceDelegate> _Nonnull delegate, dispatch_queue_t _Nonnull delegateQueue);
@end @end
@implementation MTTcpConnection @implementation MTTcpConnection
@ -826,6 +801,8 @@ struct ctr_state {
_interface = interface; _interface = interface;
_usageCalculationInfo = usageCalculationInfo; _usageCalculationInfo = usageCalculationInfo;
_makeTcpConnectionInterface = context.makeTcpConnectionInterface;
if (context.apiEnvironment.datacenterAddressOverrides[@(datacenterId)] != nil) { if (context.apiEnvironment.datacenterAddressOverrides[@(datacenterId)] != nil) {
_firstPacketControlByte = [context.apiEnvironment tcpPayloadPrefix]; _firstPacketControlByte = [context.apiEnvironment tcpPayloadPrefix];
} }
@ -917,7 +894,12 @@ struct ctr_state {
{ {
if (_socket == nil) if (_socket == nil)
{ {
if (_makeTcpConnectionInterface) {
_socket = _makeTcpConnectionInterface(self, [[MTTcpConnection tcpQueue] nativeQueue]);
}
if (_socket == nil) {
_socket = [[MTGcdAsyncSocketTcpConnectionInterface alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]]; _socket = [[MTGcdAsyncSocketTcpConnectionInterface alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]];
}
[_socket setGetLogPrefix:_getLogPrefix]; [_socket setGetLogPrefix:_getLogPrefix];
[_socket setUsageCalculationInfo:_usageCalculationInfo]; [_socket setUsageCalculationInfo:_usageCalculationInfo];
@ -1407,7 +1389,7 @@ struct ctr_state {
[self closeAndNotifyWithError:true]; [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) if (_closed)
return; return;
@ -1477,7 +1459,7 @@ struct ctr_state {
[_socket readDataToLength:4 withTimeout:-1 tag:MTTcpSocksRequest]; [_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) if (_closed)
return; 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) { 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 (error != nil) {
if (MTLogEnabled()) { if (MTLogEnabled()) {

View File

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

View File

@ -161,6 +161,8 @@ public final class StorageBox {
let totalSizeSubscribers = Bag<(Int64) -> Void>() let totalSizeSubscribers = Bag<(Int64) -> Void>()
private var totalSize: Int64 = 0 private var totalSize: Int64 = 0
private var queuedInternalTransactions = Atomic<[() -> Void]>(value: [])
init(queue: Queue, logger: StorageBox.Logger, basePath: String) { init(queue: Queue, logger: StorageBox.Logger, basePath: String) {
self.queue = queue self.queue = queue
self.logger = logger self.logger = logger
@ -191,6 +193,7 @@ public final class StorageBox {
} }
private func performUpdatesIfNeeded() { private func performUpdatesIfNeeded() {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let mainMetadataKey = ValueBoxKey(length: 2) let mainMetadataKey = ValueBoxKey(length: 2)
@ -215,6 +218,7 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
} }
}
private func reindexPeerStats() { private func reindexPeerStats() {
self.valueBox.removeAllFromTable(self.peerContentTypeStatsTable) self.valueBox.removeAllFromTable(self.peerContentTypeStatsTable)
@ -236,6 +240,7 @@ public final class StorageBox {
} }
func updateTotalSize() { func updateTotalSize() {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
var totalSize: Int64 = 0 var totalSize: Int64 = 0
@ -257,6 +262,7 @@ public final class StorageBox {
} }
} }
} }
}
func incrementalUpdateTotalSize() { func incrementalUpdateTotalSize() {
for f in self.totalSizeSubscribers.copyItems() { for f in self.totalSizeSubscribers.copyItems() {
@ -265,6 +271,7 @@ public final class StorageBox {
} }
func reset() { func reset() {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
self.valueBox.removeAllFromTable(self.hashIdToInfoTable) self.valueBox.removeAllFromTable(self.hashIdToInfoTable)
@ -278,6 +285,7 @@ public final class StorageBox {
self.updateTotalSize() self.updateTotalSize()
} }
}
private func internalAddSize(contentType: UInt8, delta: Int64) { private func internalAddSize(contentType: UInt8, delta: Int64) {
let key = ValueBoxKey(length: 1) let key = ValueBoxKey(length: 1)
@ -413,14 +421,17 @@ public final class StorageBox {
} }
func add(reference: Reference, to id: Data, contentType: UInt8, size: Int64?) { func add(reference: Reference, to id: Data, contentType: UInt8, size: Int64?) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
self.internalAdd(reference: reference, to: id, contentType: contentType, size: size) self.internalAdd(reference: reference, to: id, contentType: contentType, size: size)
self.valueBox.commit() self.valueBox.commit()
} }
}
func batchAdd(items: [(reference: Reference, id: Data, contentType: UInt8, size: Int64)]) { func batchAdd(items: [(reference: Reference, id: Data, contentType: UInt8, size: Int64)]) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
for (reference, id, contentType, size) in items { for (reference, id, contentType, size) in items {
@ -431,6 +442,7 @@ public final class StorageBox {
self.incrementalUpdateTotalSize() self.incrementalUpdateTotalSize()
} }
}
private func peerIdsReferencing(hashId: HashId) -> Set<Int64> { private func peerIdsReferencing(hashId: HashId) -> Set<Int64> {
let mainKey = ValueBoxKey(length: 16) let mainKey = ValueBoxKey(length: 16)
@ -447,6 +459,7 @@ public final class StorageBox {
} }
func update(id: Data, size: Int64) { func update(id: Data, size: Int64) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let hashId = md5Hash(id) let hashId = md5Hash(id)
@ -480,8 +493,10 @@ public final class StorageBox {
self.incrementalUpdateTotalSize() self.incrementalUpdateTotalSize()
} }
}
func addEmptyReferencesIfNotReferenced(ids: [(id: Data, size: Int64)], contentType: UInt8) -> Int { func addEmptyReferencesIfNotReferenced(ids: [(id: Data, size: Int64)], contentType: UInt8, completion: @escaping (Int) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let mainKey = ValueBoxKey(length: 16) let mainKey = ValueBoxKey(length: 16)
@ -500,7 +515,8 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
return addedCount completion(addedCount)
}
} }
private func internalRemove(hashId: Data) { private func internalRemove(hashId: Data) {
@ -545,6 +561,7 @@ public final class StorageBox {
} }
func remove(ids: [Data]) { func remove(ids: [Data]) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
for id in ids { for id in ids {
@ -555,8 +572,10 @@ public final class StorageBox {
self.incrementalUpdateTotalSize() self.incrementalUpdateTotalSize()
} }
}
func allPeerIds() -> [PeerId] { func allPeerIds(completion: @escaping([PeerId]) -> Void) {
self.beginInternalTransaction {
var result: [PeerId] = [] var result: [PeerId] = []
self.valueBox.begin() self.valueBox.begin()
@ -588,7 +607,8 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
return result completion(result)
}
} }
private func allInternal(peerId: PeerId) -> [Data] { private func allInternal(peerId: PeerId) -> [Data] {
@ -613,17 +633,20 @@ public final class StorageBox {
return result return result
} }
func all(peerId: PeerId) -> [Data] { func all(peerId: PeerId, completion: @escaping ([Data]) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let result = self.allInternal(peerId: peerId) let result = self.allInternal(peerId: peerId)
self.valueBox.commit() self.valueBox.commit()
return result completion(result)
}
} }
func enumerateItems(startingWith startId: Data?, limit: Int) -> (ids: [Data], nextStartId: Data?) { func enumerateItems(startingWith startId: Data?, limit: Int, completion: @escaping ((ids: [Data], nextStartId: Data?)) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let startKey: ValueBoxKey let startKey: ValueBoxKey
@ -658,7 +681,8 @@ public final class StorageBox {
nextId = nil nextId = nil
} }
return (ids, nextId) completion((ids, nextId))
}
} }
func subscribeTotalSize(next: @escaping (Int64) -> Void) -> Disposable { func subscribeTotalSize(next: @escaping (Int64) -> Void) -> Disposable {
@ -677,7 +701,8 @@ public final class StorageBox {
} }
} }
func all() -> [Entry] { func all(completion: @escaping ([Entry]) -> Void) {
self.beginInternalTransaction {
var result: [Entry] = [] var result: [Entry] = []
self.valueBox.begin() self.valueBox.begin()
@ -716,10 +741,12 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
return result completion(result)
}
} }
func get(ids: [Data]) -> [Entry] { func get(ids: [Data], completion: @escaping ([Entry]) -> Void) {
self.beginInternalTransaction {
var result: [Entry] = [] var result: [Entry] = []
self.valueBox.begin() self.valueBox.begin()
@ -748,10 +775,12 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
return result completion(result)
}
} }
func getAllStats() -> AllStats { func getAllStats(completion: @escaping (AllStats) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin() self.valueBox.begin()
let allStats = AllStats(total: StorageBox.Stats(contentTypes: [:]), peers: [:]) let allStats = AllStats(total: StorageBox.Stats(contentTypes: [:]), peers: [:])
@ -825,10 +854,12 @@ public final class StorageBox {
self.valueBox.commit() self.valueBox.commit()
return allStats completion(allStats)
}
} }
func remove(peerId: Int64?, contentTypes: [UInt8], includeIds: [Data], excludeIds: [Data]) -> [Data] { func remove(peerId: Int64?, contentTypes: [UInt8], includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) {
self.beginInternalTransaction {
var resultIds: [Data] = [] var resultIds: [Data] = []
self.valueBox.begin() self.valueBox.begin()
@ -889,10 +920,12 @@ public final class StorageBox {
self.incrementalUpdateTotalSize() self.incrementalUpdateTotalSize()
return Array(resultIds) completion(Array(resultIds))
}
} }
func remove(peerIds: Set<PeerId>, includeIds: [Data], excludeIds: [Data]) -> [Data] { func remove(peerIds: Set<PeerId>, includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) {
self.beginInternalTransaction {
var resultIds: [Data] = [] var resultIds: [Data] = []
self.valueBox.begin() self.valueBox.begin()
@ -920,7 +953,33 @@ public final class StorageBox {
self.incrementalUpdateTotalSize() self.incrementalUpdateTotalSize()
return Array(resultIds) completion(Array(resultIds))
}
}
private func beginInternalTransaction(ignoreDisabled: Bool = false, _ f: @escaping () -> Void) {
assert(self.queue.isCurrent())
if ignoreDisabled || self.canBeginTransactionsValue.with({ $0 }) {
f()
} else {
let _ = self.queuedInternalTransactions.modify { fs in
var fs = fs
fs.append(f)
return fs
}
}
}
let canBeginTransactionsValue = Atomic<Bool>(value: true)
func setCanBeginTransactions(_ value: Bool, afterTransactionIfRunning: @escaping () -> Void) {
let previous = self.canBeginTransactionsValue.swap(value)
if previous != value && value {
let fs = self.queuedInternalTransactions.swap([])
for f in fs {
f()
}
}
afterTransactionIfRunning()
} }
} }
@ -950,9 +1009,7 @@ public final class StorageBox {
public func addEmptyReferencesIfNotReferenced(ids: [(id: Data, size: Int64)], contentType: UInt8, completion: @escaping (Int) -> Void) { public func addEmptyReferencesIfNotReferenced(ids: [(id: Data, size: Int64)], contentType: UInt8, completion: @escaping (Int) -> Void) {
self.impl.with { impl in self.impl.with { impl in
let addedCount = impl.addEmptyReferencesIfNotReferenced(ids: ids, contentType: contentType) impl.addEmptyReferencesIfNotReferenced(ids: ids, contentType: contentType, completion: completion)
completion(addedCount)
} }
} }
@ -970,8 +1027,10 @@ public final class StorageBox {
public func all() -> Signal<[Entry], NoError> { public func all() -> Signal<[Entry], NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.all()) impl.all(completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -979,8 +1038,10 @@ public final class StorageBox {
public func allPeerIds() -> Signal<[PeerId], NoError> { public func allPeerIds() -> Signal<[PeerId], NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.allPeerIds()) impl.allPeerIds(completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -988,8 +1049,10 @@ public final class StorageBox {
public func all(peerId: PeerId) -> Signal<[Data], NoError> { public func all(peerId: PeerId) -> Signal<[Data], NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.all(peerId: peerId)) impl.all(peerId: peerId, completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -997,8 +1060,10 @@ public final class StorageBox {
public func get(ids: [Data]) -> Signal<[Entry], NoError> { public func get(ids: [Data]) -> Signal<[Entry], NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.get(ids: ids)) impl.get(ids: ids, completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -1006,8 +1071,10 @@ public final class StorageBox {
public func getAllStats() -> Signal<AllStats, NoError> { public func getAllStats() -> Signal<AllStats, NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.getAllStats()) impl.getAllStats(completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -1015,15 +1082,17 @@ public final class StorageBox {
public func remove(peerId: PeerId?, contentTypes: [UInt8], includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) { public func remove(peerId: PeerId?, contentTypes: [UInt8], includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) {
self.impl.with { impl in self.impl.with { impl in
let ids = impl.remove(peerId: peerId?.toInt64(), contentTypes: contentTypes, includeIds: includeIds, excludeIds: excludeIds) impl.remove(peerId: peerId?.toInt64(), contentTypes: contentTypes, includeIds: includeIds, excludeIds: excludeIds, completion: { result in
completion(ids) completion(result)
})
} }
} }
public func remove(peerIds: Set<PeerId>, includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) { public func remove(peerIds: Set<PeerId>, includeIds: [Data], excludeIds: [Data], completion: @escaping ([Data]) -> Void) {
self.impl.with { impl in self.impl.with { impl in
let ids = impl.remove(peerIds: peerIds, includeIds: includeIds, excludeIds: excludeIds) impl.remove(peerIds: peerIds, includeIds: includeIds, excludeIds: excludeIds, completion: { result in
completion(ids) completion(result)
})
} }
} }
@ -1035,8 +1104,10 @@ public final class StorageBox {
public func enumerateItems(startingWith startId: Data?, limit: Int) -> Signal<(ids: [Data], nextStartId: Data?), NoError> { public func enumerateItems(startingWith startId: Data?, limit: Int) -> Signal<(ids: [Data], nextStartId: Data?), NoError> {
return self.impl.signalWith { impl, subscriber in return self.impl.signalWith { impl, subscriber in
subscriber.putNext(impl.enumerateItems(startingWith: startId, limit: limit)) impl.enumerateItems(startingWith: startId, limit: limit, completion: { result in
subscriber.putNext(result)
subscriber.putCompletion() subscriber.putCompletion()
})
return EmptyDisposable return EmptyDisposable
} }
@ -1049,4 +1120,10 @@ public final class StorageBox {
}) })
} }
} }
public func setCanBeginTransactions(_ value: Bool, afterTransactionIfRunning: @escaping () -> Void) {
self.impl.with { impl in
impl.setCanBeginTransactions(value, afterTransactionIfRunning: afterTransactionIfRunning)
}
}
} }

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) 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]] let seedAddressList: [Int: [String]]
if testingEnvironment { 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 reducedBackupDiscoveryTimeout: Bool
public var applicationUpdateUrlPrefix: String? public var applicationUpdateUrlPrefix: String?
public var backupHostOverride: String? public var backupHostOverride: String?
public var useNetworkFramework: Bool
public static var defaultSettings: NetworkSettings { 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.reducedBackupDiscoveryTimeout = reducedBackupDiscoveryTimeout
self.applicationUpdateUrlPrefix = applicationUpdateUrlPrefix self.applicationUpdateUrlPrefix = applicationUpdateUrlPrefix
self.backupHostOverride = backupHostOverride self.backupHostOverride = backupHostOverride
self.useNetworkFramework = useNetworkFramework
} }
public init(from decoder: Decoder) throws { 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.reducedBackupDiscoveryTimeout = ((try? container.decode(Int32.self, forKey: "reducedBackupDiscoveryTimeout")) ?? 0) != 0
self.applicationUpdateUrlPrefix = try? container.decodeIfPresent(String.self, forKey: "applicationUpdateUrlPrefix") self.applicationUpdateUrlPrefix = try? container.decodeIfPresent(String.self, forKey: "applicationUpdateUrlPrefix")
self.backupHostOverride = try? container.decodeIfPresent(String.self, forKey: "backupHostOverride") 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 { 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.encode((self.reducedBackupDiscoveryTimeout ? 1 : 0) as Int32, forKey: "reducedBackupDiscoveryTimeout")
try container.encodeIfPresent(self.applicationUpdateUrlPrefix, forKey: "applicationUpdateUrlPrefix") try container.encodeIfPresent(self.applicationUpdateUrlPrefix, forKey: "applicationUpdateUrlPrefix")
try container.encodeIfPresent(self.backupHostOverride, forKey: "backupHostOverride") try container.encodeIfPresent(self.backupHostOverride, forKey: "backupHostOverride")
try container.encode(self.useNetworkFramework, forKey: "useNetworkFramework")
} }
} }