mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
4c794a0a91
@ -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: [])
|
||||||
},
|
},
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
#import <MtProtoKit/MTTransport.h>
|
#import <MtProtoKit/MTTransport.h>
|
||||||
|
|
||||||
@interface MTTcpTransport : MTTransport
|
@interface MTTcpTransport : MTTransport
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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()) {
|
||||||
|
@ -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()
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user