mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
no message
This commit is contained in:
@@ -3527,6 +3527,128 @@
|
||||
};
|
||||
name = "Release AppStore";
|
||||
};
|
||||
D0CE6EF5213DC30700BCD44B /* Release AppStore LLC */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = "Release AppStore LLC";
|
||||
};
|
||||
D0CE6EF6213DC30700BCD44B /* Release AppStore LLC */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = X834Q8SBVP;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = TelegramCore/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/third-party/FFmpeg-iOS/lib",
|
||||
"$(PROJECT_DIR)/third-party/libwebp/lib",
|
||||
);
|
||||
MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private.modulemap";
|
||||
OTHER_LDFLAGS = "-Wl,-dead_strip";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramCore;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_REFLECTION_METADATA_LEVEL = none;
|
||||
SWIFT_VERSION = 4.0;
|
||||
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/third-party/FFmpeg-iOS/include";
|
||||
};
|
||||
name = "Release AppStore LLC";
|
||||
};
|
||||
D0CE6EF7213DC30700BCD44B /* Release AppStore LLC */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = TelegramCoreTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = "Release AppStore LLC";
|
||||
};
|
||||
D0CE6EF8213DC30700BCD44B /* Release AppStore LLC */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D03B0E591D63215200955575 /* TelegramCore.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = TelegramCoreMac/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MODULEMAP_PRIVATE_FILE = "$(SRCROOT)/TelegramCore/module.private-mac.modulemap";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.Telegram.TelegramCoreMac;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = "Release AppStore LLC";
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@@ -3539,6 +3661,7 @@
|
||||
C22069BE1E8EB4A200E82730 /* Release Hockeyapp */,
|
||||
D0924FE81FE52C12003F693F /* Release Hockeyapp Internal */,
|
||||
D06706551D51162400DED3E3 /* Release AppStore */,
|
||||
D0CE6EF5213DC30700BCD44B /* Release AppStore LLC */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "Debug AppStore";
|
||||
@@ -3552,6 +3675,7 @@
|
||||
C22069BF1E8EB4A200E82730 /* Release Hockeyapp */,
|
||||
D0924FE91FE52C12003F693F /* Release Hockeyapp Internal */,
|
||||
D06706561D51162400DED3E3 /* Release AppStore */,
|
||||
D0CE6EF6213DC30700BCD44B /* Release AppStore LLC */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "Debug AppStore";
|
||||
@@ -3565,6 +3689,7 @@
|
||||
C22069C01E8EB4A200E82730 /* Release Hockeyapp */,
|
||||
D0924FEA1FE52C12003F693F /* Release Hockeyapp Internal */,
|
||||
D06706571D51162400DED3E3 /* Release AppStore */,
|
||||
D0CE6EF7213DC30700BCD44B /* Release AppStore LLC */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "Debug AppStore";
|
||||
@@ -3578,6 +3703,7 @@
|
||||
C22069C11E8EB4A200E82730 /* Release Hockeyapp */,
|
||||
D0924FEB1FE52C12003F693F /* Release Hockeyapp Internal */,
|
||||
D0B4186F1D7E03D5004562A4 /* Release AppStore */,
|
||||
D0CE6EF8213DC30700BCD44B /* Release AppStore LLC */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = "Debug AppStore";
|
||||
|
||||
@@ -850,7 +850,7 @@ public class Account {
|
||||
private let serviceQueue = Queue()
|
||||
|
||||
public private(set) var stateManager: AccountStateManager!
|
||||
private var contactSyncManager: ContactSyncManager!
|
||||
private(set) var contactSyncManager: ContactSyncManager!
|
||||
public private(set) var callSessionManager: CallSessionManager!
|
||||
public private(set) var viewTracker: AccountViewTracker!
|
||||
public private(set) var pendingMessageManager: PendingMessageManager!
|
||||
@@ -1183,6 +1183,7 @@ public class Account {
|
||||
public func resetStateManagement() {
|
||||
self.stateManager.reset()
|
||||
self.contactSyncManager.beginSync(importableContacts: self.importableContacts.get())
|
||||
self.managedStickerPacksDisposable.set(manageStickerPacks(network: self.network, postbox: self.postbox).start())
|
||||
}
|
||||
|
||||
public func peerInputActivities(peerId: PeerId) -> Signal<[(PeerId, PeerInputActivity)], NoError> {
|
||||
@@ -1246,5 +1247,4 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation:
|
||||
|
||||
account.transformOutgoingMessageMedia = transformOutgoingMessageMedia
|
||||
account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia
|
||||
account.managedStickerPacksDisposable.set(manageStickerPacks(network: account.network, postbox: account.postbox).start())
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings)
|
||||
case MergeApiChats([Api.Chat])
|
||||
case UpdatePeer(PeerId, (Peer?) -> Peer?)
|
||||
case UpdateIsContact(PeerId, Bool)
|
||||
case UpdateCachedPeerData(PeerId, (CachedPeerData?) -> CachedPeerData?)
|
||||
case MergeApiUsers([Api.User])
|
||||
case MergePeerPresences([PeerId: PeerPresence])
|
||||
@@ -246,6 +247,10 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdatePeer(id, f))
|
||||
}
|
||||
|
||||
mutating func updatePeerIsContact(_ id: PeerId, isContact: Bool) {
|
||||
self.addOperation(.UpdateIsContact(id, isContact))
|
||||
}
|
||||
|
||||
mutating func updateCachedPeerData(_ id: PeerId, _ f: @escaping (CachedPeerData?) -> CachedPeerData?) {
|
||||
self.addOperation(.UpdateCachedPeerData(id, f))
|
||||
}
|
||||
@@ -328,7 +333,7 @@ struct AccountMutableState {
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact:
|
||||
break
|
||||
case let .AddMessages(messages, _):
|
||||
for message in messages {
|
||||
@@ -399,6 +404,7 @@ struct AccountReplayedFinalState {
|
||||
let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]]
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let delayNotificatonsUntil: Int32?
|
||||
}
|
||||
|
||||
@@ -407,11 +413,12 @@ struct AccountFinalStateEvents {
|
||||
let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]]
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let displayAlerts: [String]
|
||||
let delayNotificatonsUntil: Int32?
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil
|
||||
return self.addedIncomingMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil
|
||||
}
|
||||
|
||||
init() {
|
||||
@@ -419,15 +426,17 @@ struct AccountFinalStateEvents {
|
||||
self.updatedTypingActivities = [:]
|
||||
self.updatedWebpages = [:]
|
||||
self.updatedCalls = []
|
||||
self.isContactUpdates = []
|
||||
self.displayAlerts = []
|
||||
self.delayNotificatonsUntil = nil
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId], updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]], updatedWebpages: [MediaId: TelegramMediaWebpage], updatedCalls: [Api.PhoneCall], displayAlerts: [String], delayNotificatonsUntil: Int32?) {
|
||||
init(addedIncomingMessageIds: [MessageId], updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]], updatedWebpages: [MediaId: TelegramMediaWebpage], updatedCalls: [Api.PhoneCall], isContactUpdates: [(PeerId, Bool)], displayAlerts: [String], delayNotificatonsUntil: Int32?) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.updatedTypingActivities = updatedTypingActivities
|
||||
self.updatedWebpages = updatedWebpages
|
||||
self.updatedCalls = updatedCalls
|
||||
self.isContactUpdates = isContactUpdates
|
||||
self.displayAlerts = displayAlerts
|
||||
self.delayNotificatonsUntil = delayNotificatonsUntil
|
||||
}
|
||||
@@ -437,6 +446,7 @@ struct AccountFinalStateEvents {
|
||||
self.updatedTypingActivities = state.updatedTypingActivities
|
||||
self.updatedWebpages = state.updatedWebpages
|
||||
self.updatedCalls = state.updatedCalls
|
||||
self.isContactUpdates = state.isContactUpdates
|
||||
self.displayAlerts = state.state.state.displayAlerts
|
||||
self.delayNotificatonsUntil = state.delayNotificatonsUntil
|
||||
}
|
||||
@@ -448,6 +458,6 @@ struct AccountFinalStateEvents {
|
||||
delayNotificatonsUntil = other
|
||||
}
|
||||
}
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil)
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1081,6 +1081,15 @@ private func finalStateWithUpdatesAndServerTime(account: Account, state: Account
|
||||
return peer
|
||||
}
|
||||
})
|
||||
case let .updateContactLink(userId, myLink, _):
|
||||
let isContact: Bool
|
||||
switch myLink {
|
||||
case .contactLinkContact:
|
||||
isContact = true
|
||||
default:
|
||||
isContact = false
|
||||
}
|
||||
updatedState.updatePeerIsContact(PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), isContact: isContact)
|
||||
case let .updateEncryption(chat, date):
|
||||
updatedState.updateSecretChat(chat: chat, timestamp: date)
|
||||
case let .updateNewEncryptedMessage(message, _):
|
||||
@@ -1813,7 +1822,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@@ -1864,6 +1873,7 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, transaction: Tr
|
||||
var updatedSecretChatTypingActivities = Set<PeerId>()
|
||||
var updatedWebpages: [MediaId: TelegramMediaWebpage] = [:]
|
||||
var updatedCalls: [Api.PhoneCall] = []
|
||||
var isContactUpdates: [(PeerId, Bool)] = []
|
||||
var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = []
|
||||
var recentlyUsedStickers: [MediaId: (MessageIndex, TelegramMediaFile)] = [:]
|
||||
var recentlyUsedGifs: [MediaId: (MessageIndex, TelegramMediaFile)] = [:]
|
||||
@@ -2221,6 +2231,8 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, transaction: Tr
|
||||
} else {
|
||||
pollLangPack = true
|
||||
}
|
||||
case let .UpdateIsContact(peerId, value):
|
||||
isContactUpdates.append((peerId, value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2445,5 +2457,5 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, transaction: Tr
|
||||
|
||||
addedIncomingMessageIds.append(contentsOf: addedSecretMessageIds)
|
||||
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, delayNotificatonsUntil: delayNotificatonsUntil)
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import Foundation
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
|
||||
private enum AccountStateManagerOperation {
|
||||
private enum AccountStateManagerOperationContent {
|
||||
case pollDifference(AccountFinalStateEvents)
|
||||
case collectUpdateGroups([UpdateGroup], Double)
|
||||
case processUpdateGroups([UpdateGroup])
|
||||
@@ -19,6 +19,20 @@ private enum AccountStateManagerOperation {
|
||||
case replayAsynchronouslyBuiltFinalState(AccountFinalState, () -> Void)
|
||||
}
|
||||
|
||||
private final class AccountStateManagerOperation {
|
||||
var isRunning: Bool = false
|
||||
let content: AccountStateManagerOperationContent
|
||||
|
||||
init(content: AccountStateManagerOperationContent) {
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
private enum AccountStateManagerAddOperationPosition {
|
||||
case first
|
||||
case last
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private typealias SignalKitTimer = SwiftSignalKitMac.Timer
|
||||
#else
|
||||
@@ -137,22 +151,17 @@ public final class AccountStateManager {
|
||||
func addUpdateGroups(_ groups: [UpdateGroup]) {
|
||||
self.queue.async {
|
||||
if let last = self.operations.last {
|
||||
switch last {
|
||||
switch last.content {
|
||||
case .pollDifference, .processUpdateGroups, .custom, .pollCompletion, .processEvents, .replayAsynchronouslyBuiltFinalState:
|
||||
self.operations.append(.collectUpdateGroups(groups, 0.0))
|
||||
self.addOperation(.collectUpdateGroups(groups, 0.0), position: .last)
|
||||
case let .collectUpdateGroups(currentGroups, timeout):
|
||||
if timeout.isEqual(to: 0.0) {
|
||||
self.operations[self.operations.count - 1] = .collectUpdateGroups(currentGroups + groups, timeout)
|
||||
} else {
|
||||
self.operations[self.operations.count - 1] = .processUpdateGroups(currentGroups + groups)
|
||||
if self.operations.count == 1 {
|
||||
self.startFirstOperation()
|
||||
}
|
||||
}
|
||||
let operation = AccountStateManagerOperation(content: .collectUpdateGroups(currentGroups + groups, timeout))
|
||||
operation.isRunning = last.isRunning
|
||||
self.operations[self.operations.count - 1] = operation
|
||||
self.startFirstOperation()
|
||||
}
|
||||
} else {
|
||||
self.operations.append(.collectUpdateGroups(groups, 0.0))
|
||||
self.startFirstOperation()
|
||||
self.addOperation(.collectUpdateGroups(groups, 0.0), position: .last)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,14 +169,10 @@ public final class AccountStateManager {
|
||||
func addReplayAsynchronouslyBuiltFinalState(_ finalState: AccountFinalState) -> Signal<Bool, NoError> {
|
||||
return Signal { subscriber in
|
||||
self.queue.async {
|
||||
let begin = self.operations.isEmpty
|
||||
self.operations.append(.replayAsynchronouslyBuiltFinalState(finalState, {
|
||||
self.addOperation(.replayAsynchronouslyBuiltFinalState(finalState, {
|
||||
subscriber.putNext(true)
|
||||
subscriber.putCompletion()
|
||||
}))
|
||||
if begin {
|
||||
self.startFirstOperation()
|
||||
}
|
||||
}), position: .last)
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
@@ -199,60 +204,78 @@ public final class AccountStateManager {
|
||||
})
|
||||
}
|
||||
|
||||
self.addOperation(.custom(self.getNextId(), signal))
|
||||
self.addOperation(.custom(self.getNextId(), signal), position: .last)
|
||||
|
||||
return disposable
|
||||
} |> runOn(self.queue)
|
||||
}
|
||||
|
||||
private func replaceOperations(with operation: AccountStateManagerOperation) {
|
||||
var collectedProcessUpdateGroups: [(AccountStateManagerOperation, Bool)] = []
|
||||
private func replaceOperations(with content: AccountStateManagerOperationContent) {
|
||||
var collectedProcessUpdateGroups: [AccountStateManagerOperationContent] = []
|
||||
var collectedMessageIds: [MessageId] = []
|
||||
var collectedPollCompletionSubscribers: [(Int32, ([MessageId]) -> Void)] = []
|
||||
var collectedReplayAsynchronouslyBuiltFinalState: [(AccountFinalState, () -> Void)] = []
|
||||
var processEvents: [(Int32, AccountFinalStateEvents)] = []
|
||||
|
||||
var replacedOperations: [AccountStateManagerOperation] = []
|
||||
|
||||
for i in 0 ..< self.operations.count {
|
||||
switch self.operations[i] {
|
||||
case .processUpdateGroups:
|
||||
collectedProcessUpdateGroups.append((self.operations[i], i == 0))
|
||||
case let .pollCompletion(_, messageIds, subscribers):
|
||||
collectedMessageIds.append(contentsOf: messageIds)
|
||||
collectedPollCompletionSubscribers.append(contentsOf: subscribers)
|
||||
case let .replayAsynchronouslyBuiltFinalState(finalState, completion):
|
||||
collectedReplayAsynchronouslyBuiltFinalState.append((finalState, completion))
|
||||
case let .processEvents(operationId, events):
|
||||
processEvents.append((operationId, events))
|
||||
default:
|
||||
break
|
||||
if self.operations[i].isRunning {
|
||||
replacedOperations.append(self.operations[i])
|
||||
} else {
|
||||
switch self.operations[i].content {
|
||||
case .processUpdateGroups:
|
||||
collectedProcessUpdateGroups.append(self.operations[i].content)
|
||||
case let .pollCompletion(_, messageIds, subscribers):
|
||||
collectedMessageIds.append(contentsOf: messageIds)
|
||||
collectedPollCompletionSubscribers.append(contentsOf: subscribers)
|
||||
case let .replayAsynchronouslyBuiltFinalState(finalState, completion):
|
||||
collectedReplayAsynchronouslyBuiltFinalState.append((finalState, completion))
|
||||
case let .processEvents(operationId, events):
|
||||
processEvents.append((operationId, events))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.operations.removeAll()
|
||||
replacedOperations.append(contentsOf: collectedProcessUpdateGroups.map { AccountStateManagerOperation(content: $0) })
|
||||
|
||||
self.operations.append(contentsOf: collectedProcessUpdateGroups.map { $0.0 })
|
||||
|
||||
self.operations.append(operation)
|
||||
replacedOperations.append(AccountStateManagerOperation(content: content))
|
||||
|
||||
if !collectedPollCompletionSubscribers.isEmpty || !collectedMessageIds.isEmpty {
|
||||
self.operations.append(.pollCompletion(self.getNextId(), collectedMessageIds, collectedPollCompletionSubscribers))
|
||||
replacedOperations.append(AccountStateManagerOperation(content: .pollCompletion(self.getNextId(), collectedMessageIds, collectedPollCompletionSubscribers)))
|
||||
}
|
||||
|
||||
for (finalState, completion) in collectedReplayAsynchronouslyBuiltFinalState {
|
||||
self.operations.append(.replayAsynchronouslyBuiltFinalState(finalState, completion))
|
||||
replacedOperations.append(AccountStateManagerOperation(content: .replayAsynchronouslyBuiltFinalState(finalState, completion)))
|
||||
}
|
||||
|
||||
for (operationId, events) in processEvents {
|
||||
self.operations.append(.processEvents(operationId, events))
|
||||
replacedOperations.append(AccountStateManagerOperation(content: .processEvents(operationId, events)))
|
||||
}
|
||||
|
||||
self.operations.removeAll()
|
||||
self.operations.append(contentsOf: replacedOperations)
|
||||
}
|
||||
|
||||
private func addOperation(_ operation: AccountStateManagerOperation) {
|
||||
private func addOperation(_ content: AccountStateManagerOperationContent, position: AccountStateManagerAddOperationPosition) {
|
||||
self.queue.async {
|
||||
let begin = self.operations.isEmpty
|
||||
self.operations.append(operation)
|
||||
if begin {
|
||||
self.startFirstOperation()
|
||||
let operation = AccountStateManagerOperation(content: content)
|
||||
switch position {
|
||||
case .first:
|
||||
if self.operations.isEmpty || !self.operations[0].isRunning {
|
||||
self.operations.insert(operation, at: 0)
|
||||
self.startFirstOperation()
|
||||
} else {
|
||||
self.operations.insert(operation, at: 1)
|
||||
}
|
||||
case .last:
|
||||
let begin = self.operations.isEmpty
|
||||
self.operations.append(operation)
|
||||
if begin {
|
||||
self.startFirstOperation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +284,11 @@ public final class AccountStateManager {
|
||||
guard let operation = self.operations.first else {
|
||||
return
|
||||
}
|
||||
switch operation {
|
||||
guard !operation.isRunning else {
|
||||
return
|
||||
}
|
||||
operation.isRunning = true
|
||||
switch operation.content {
|
||||
case let .pollDifference(currentEvents):
|
||||
self.operationTimer?.invalidate()
|
||||
self.currentIsUpdatingValue = true
|
||||
@@ -270,71 +297,73 @@ public final class AccountStateManager {
|
||||
let accountPeerId = account.peerId
|
||||
let auxiliaryMethods = self.auxiliaryMethods
|
||||
let signal = account.postbox.stateView()
|
||||
|> mapToSignal { view -> Signal<AuthorizedAccountState, NoError> in
|
||||
if let state = view.state as? AuthorizedAccountState {
|
||||
return .single(state)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { view -> Signal<AuthorizedAccountState, NoError> in
|
||||
if let state = view.state as? AuthorizedAccountState {
|
||||
return .single(state)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|> take(1)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if let authorizedState = state.state {
|
||||
let request = account.network.request(Api.functions.updates.getDifference(flags: 1 << 0, pts: authorizedState.pts, ptsTotalLimit: 1000, date: authorizedState.date, qts: authorizedState.qts))
|
||||
|> retryRequest
|
||||
return request |> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
switch difference {
|
||||
case .differenceTooLong:
|
||||
return accountStateReset(postbox: account.postbox, network: account.network) |> mapToSignal { _ -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
return .complete()
|
||||
} |> then(.single((nil, nil)))
|
||||
default:
|
||||
return initialStateWithDifference(account, difference: difference)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if state.initialState.state != authorizedState {
|
||||
Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)")
|
||||
return .single((nil, nil))
|
||||
} else {
|
||||
return finalStateWithDifference(account: account, state: state, difference: difference)
|
||||
|> mapToSignal { finalState -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
return account.postbox.transaction { transaction -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let replayedState = replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) {
|
||||
return (difference, replayedState)
|
||||
} else {
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if let authorizedState = state.state {
|
||||
let request = account.network.request(Api.functions.updates.getDifference(flags: 1 << 0, pts: authorizedState.pts, ptsTotalLimit: 1000, date: authorizedState.date, qts: authorizedState.qts))
|
||||
|> retryRequest
|
||||
|
||||
return request
|
||||
|> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
switch difference {
|
||||
case .differenceTooLong:
|
||||
return accountStateReset(postbox: account.postbox, network: account.network) |> mapToSignal { _ -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
return .complete()
|
||||
} |> then(.single((nil, nil)))
|
||||
default:
|
||||
return initialStateWithDifference(account, difference: difference)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if state.initialState.state != authorizedState {
|
||||
Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)")
|
||||
return .single((nil, nil))
|
||||
} else {
|
||||
return finalStateWithDifference(account: account, state: state, difference: difference)
|
||||
|> mapToSignal { finalState -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
return account.postbox.transaction { transaction -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let replayedState = replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) {
|
||||
return (difference, replayedState)
|
||||
} else {
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let appliedState = account.network.request(Api.functions.updates.getState())
|
||||
|> retryRequest
|
||||
|> mapToSignal { state in
|
||||
return account.postbox.transaction { transaction -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let currentState = transaction.getState() as? AuthorizedAccountState {
|
||||
switch state {
|
||||
case let .state(pts, qts, date, seq, _):
|
||||
transaction.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq)))
|
||||
}
|
||||
}
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
return appliedState
|
||||
}
|
||||
} else {
|
||||
let appliedState = account.network.request(Api.functions.updates.getState())
|
||||
|> retryRequest
|
||||
|> mapToSignal { state in
|
||||
return account.postbox.transaction { transaction -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let currentState = transaction.getState() as? AuthorizedAccountState {
|
||||
switch state {
|
||||
case let .state(pts, qts, date, seq, _):
|
||||
transaction.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq)))
|
||||
}
|
||||
}
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
return appliedState
|
||||
}
|
||||
|> deliverOn(self.queue)
|
||||
}
|
||||
|> deliverOn(self.queue)
|
||||
let _ = signal.start(next: { [weak self] difference, finalState in
|
||||
if let strongSelf = self {
|
||||
if case .pollDifference = strongSelf.operations.removeFirst() {
|
||||
if case .pollDifference = strongSelf.operations.removeFirst().content {
|
||||
let events: AccountFinalStateEvents
|
||||
if let finalState = finalState {
|
||||
events = currentEvents.union(with: AccountFinalStateEvents(state: finalState))
|
||||
@@ -344,7 +373,7 @@ public final class AccountStateManager {
|
||||
if let difference = difference {
|
||||
switch difference {
|
||||
case .differenceSlice:
|
||||
strongSelf.operations.insert(.pollDifference(events), at: 0)
|
||||
strongSelf.addOperation(.pollDifference(events), position: .first)
|
||||
default:
|
||||
if !events.isEmpty {
|
||||
strongSelf.insertProcessEvents(events)
|
||||
@@ -370,9 +399,10 @@ public final class AccountStateManager {
|
||||
self.operationTimer?.invalidate()
|
||||
let operationTimer = SignalKitTimer(timeout: timeout, repeat: false, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let firstOperation = strongSelf.operations.first, case let .collectUpdateGroups(groups, _) = firstOperation {
|
||||
let firstOperation = strongSelf.operations.removeFirst()
|
||||
if case let .collectUpdateGroups(groups, _) = firstOperation.content {
|
||||
if timeout.isEqual(to: 0.0) {
|
||||
strongSelf.operations[0] = .processUpdateGroups(groups)
|
||||
strongSelf.addOperation(.processUpdateGroups(groups), position: .first)
|
||||
} else {
|
||||
Logger.shared.log("AccountStateManager", "timeout while waiting for updates")
|
||||
strongSelf.replaceOperations(with: .pollDifference(AccountFinalStateEvents()))
|
||||
@@ -393,32 +423,32 @@ public final class AccountStateManager {
|
||||
let mediaBox = account.postbox.mediaBox
|
||||
let queue = self.queue
|
||||
let signal = initialStateWithUpdateGroups(account, groups: groups)
|
||||
|> mapToSignal { state -> Signal<(AccountReplayedFinalState?, AccountFinalState), NoError> in
|
||||
return finalStateWithUpdateGroups(account, state: state, groups: groups)
|
||||
|> mapToSignal { finalState in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> AccountReplayedFinalState? in
|
||||
return replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState)
|
||||
}
|
||||
|> map({ ($0, finalState) })
|
||||
|> deliverOn(queue)
|
||||
|> mapToSignal { state -> Signal<(AccountReplayedFinalState?, AccountFinalState), NoError> in
|
||||
return finalStateWithUpdateGroups(account, state: state, groups: groups)
|
||||
|> mapToSignal { finalState in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> AccountReplayedFinalState? in
|
||||
return replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState)
|
||||
}
|
||||
|> map({ ($0, finalState) })
|
||||
|> deliverOn(queue)
|
||||
}
|
||||
}
|
||||
let _ = signal.start(next: { [weak self] replayedState, finalState in
|
||||
if let strongSelf = self {
|
||||
if case let .processUpdateGroups(groups) = strongSelf.operations.removeFirst() {
|
||||
if case let .processUpdateGroups(groups) = strongSelf.operations.removeFirst().content {
|
||||
if let replayedState = replayedState, !finalState.shouldPoll {
|
||||
let events = AccountFinalStateEvents(state: replayedState)
|
||||
if !events.isEmpty {
|
||||
strongSelf.insertProcessEvents(events)
|
||||
}
|
||||
if finalState.incomplete {
|
||||
strongSelf.operations.append(.collectUpdateGroups(groups, 2.0))
|
||||
strongSelf.addOperation(.collectUpdateGroups(groups, 2.0), position: .last)
|
||||
}
|
||||
} else {
|
||||
strongSelf.replaceOperations(with: .pollDifference(AccountFinalStateEvents()))
|
||||
@@ -436,8 +466,8 @@ public final class AccountStateManager {
|
||||
self.operationTimer?.invalidate()
|
||||
let completed: () -> Void = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let topOperation = strongSelf.operations.first, case .custom(operationId, _) = topOperation {
|
||||
strongSelf.operations.removeFirst()
|
||||
let topOperation = strongSelf.operations.removeFirst()
|
||||
if case .custom(operationId, _) = topOperation.content {
|
||||
strongSelf.startFirstOperation()
|
||||
} else {
|
||||
assertionFailure()
|
||||
@@ -453,7 +483,8 @@ public final class AccountStateManager {
|
||||
self.operationTimer?.invalidate()
|
||||
let completed: () -> Void = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let topOperation = strongSelf.operations.first, case .processEvents(operationId, _) = topOperation {
|
||||
let topOperation = strongSelf.operations.removeFirst()
|
||||
if case .processEvents(operationId, _) = topOperation.content {
|
||||
if !events.updatedTypingActivities.isEmpty {
|
||||
strongSelf.peerInputActivityManager.transaction { manager in
|
||||
for (chatPeerId, peerActivities) in events.updatedTypingActivities {
|
||||
@@ -475,14 +506,18 @@ public final class AccountStateManager {
|
||||
strongSelf.account.callSessionManager.updateSession(call)
|
||||
}
|
||||
}
|
||||
strongSelf.operations.removeFirst()
|
||||
if !events.isContactUpdates.isEmpty {
|
||||
strongSelf.account.contactSyncManager.addIsContactUpdates(events.isContactUpdates)
|
||||
}
|
||||
var pollCount = 0
|
||||
for i in 0 ..< strongSelf.operations.count {
|
||||
if case let .pollCompletion(pollId, messageIds, subscribers) = strongSelf.operations[i] {
|
||||
if case let .pollCompletion(pollId, messageIds, subscribers) = strongSelf.operations[i].content {
|
||||
pollCount += 1
|
||||
var updatedMessageIds = messageIds
|
||||
updatedMessageIds.append(contentsOf: events.addedIncomingMessageIds)
|
||||
strongSelf.operations[i] = .pollCompletion(pollId, updatedMessageIds, subscribers)
|
||||
let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, updatedMessageIds, subscribers))
|
||||
operation.isRunning = strongSelf.operations[i].isRunning
|
||||
strongSelf.operations[i] = operation
|
||||
}
|
||||
}
|
||||
assert(pollCount <= 1)
|
||||
@@ -508,7 +543,8 @@ public final class AccountStateManager {
|
||||
return messages
|
||||
}
|
||||
|
||||
let _ = (signal |> deliverOn(self.queue)).start(next: { [weak self] messages in
|
||||
let _ = (signal
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] messages in
|
||||
if let strongSelf = self {
|
||||
strongSelf.notificationMessagesPipe.putNext(messages)
|
||||
}
|
||||
@@ -529,13 +565,13 @@ public final class AccountStateManager {
|
||||
} else {
|
||||
self.operationTimer?.invalidate()
|
||||
let signal = self.account.network.request(Api.functions.help.test())
|
||||
|> deliverOn(self.queue)
|
||||
|> deliverOn(self.queue)
|
||||
let completed: () -> Void = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let topOperation = strongSelf.operations.first, case let .pollCompletion(topPollId, messageIds, subscribers) = topOperation {
|
||||
let topOperation = strongSelf.operations.removeFirst()
|
||||
if case let .pollCompletion(topPollId, messageIds, subscribers) = topOperation.content {
|
||||
assert(topPollId == pollId)
|
||||
|
||||
strongSelf.operations.removeFirst()
|
||||
if strongSelf.operations.isEmpty {
|
||||
for (_, f) in subscribers {
|
||||
f(messageIds)
|
||||
@@ -573,7 +609,7 @@ public final class AccountStateManager {
|
||||
|
||||
let _ = signal.start(next: { [weak self] replayedState, finalState in
|
||||
if let strongSelf = self {
|
||||
if case .replayAsynchronouslyBuiltFinalState = strongSelf.operations.removeFirst() {
|
||||
if case .replayAsynchronouslyBuiltFinalState = strongSelf.operations.removeFirst().content {
|
||||
if let replayedState = replayedState {
|
||||
let events = AccountFinalStateEvents(state: replayedState)
|
||||
if !events.isEmpty {
|
||||
@@ -596,21 +632,30 @@ public final class AccountStateManager {
|
||||
|
||||
private func insertProcessEvents(_ events: AccountFinalStateEvents) {
|
||||
if !events.isEmpty {
|
||||
var index = 0
|
||||
if !self.operations.isEmpty {
|
||||
while case .processEvents = self.operations[index] {
|
||||
index += 1
|
||||
let operation = AccountStateManagerOperation(content: .processEvents(self.getNextId(), events))
|
||||
var inserted = false
|
||||
for i in 0 ..< self.operations.count {
|
||||
if self.operations[i].isRunning {
|
||||
continue
|
||||
}
|
||||
if case .processEvents = self.operations[i].content {
|
||||
continue
|
||||
}
|
||||
self.operations.insert(operation, at: i)
|
||||
inserted = true
|
||||
break
|
||||
}
|
||||
if !inserted {
|
||||
self.operations.append(operation)
|
||||
}
|
||||
self.operations.insert(.processEvents(self.getNextId(), events), at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
private func postponePollCompletionOperation(messageIds: [MessageId], subscribers: [(Int32, ([MessageId]) -> Void)]) {
|
||||
self.operations.append(.pollCompletion(self.getNextId(), messageIds, subscribers))
|
||||
self.addOperation(.pollCompletion(self.getNextId(), messageIds, subscribers), position: .last)
|
||||
|
||||
for i in 0 ..< self.operations.count {
|
||||
if case .pollCompletion = self.operations[i] {
|
||||
if case .pollCompletion = self.operations[i].content {
|
||||
if i != self.operations.count - 1 {
|
||||
assertionFailure()
|
||||
}
|
||||
@@ -624,31 +669,32 @@ public final class AccountStateManager {
|
||||
let updatedId: Int32 = self.getNextId()
|
||||
|
||||
for i in 0 ..< self.operations.count {
|
||||
if case let .pollCompletion(pollId, messageIds, subscribers) = self.operations[i] {
|
||||
if case let .pollCompletion(pollId, messageIds, subscribers) = self.operations[i].content {
|
||||
var subscribers = subscribers
|
||||
subscribers.append((updatedId, f))
|
||||
self.operations[i] = .pollCompletion(pollId, messageIds, subscribers)
|
||||
let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, messageIds, subscribers))
|
||||
operation.isRunning = self.operations[i].isRunning
|
||||
self.operations[i] = operation
|
||||
return updatedId
|
||||
}
|
||||
}
|
||||
|
||||
let beginFirst = self.operations.isEmpty
|
||||
self.operations.append(.pollCompletion(self.getNextId(), [], [(updatedId, f)]))
|
||||
if beginFirst {
|
||||
self.startFirstOperation()
|
||||
}
|
||||
self.addOperation(.pollCompletion(self.getNextId(), [], [(updatedId, f)]), position: .last)
|
||||
|
||||
return updatedId
|
||||
}
|
||||
|
||||
private func removePollCompletion(_ id: Int32) {
|
||||
for i in 0 ..< self.operations.count {
|
||||
if case let .pollCompletion(pollId, messages, subscribers) = self.operations[i] {
|
||||
if case let .pollCompletion(pollId, messages, subscribers) = self.operations[i].content {
|
||||
for j in 0 ..< subscribers.count {
|
||||
if subscribers[j].0 == id {
|
||||
var subscribers = subscribers
|
||||
subscribers.remove(at: j)
|
||||
self.operations[i] = .pollCompletion(pollId, messages, subscribers)
|
||||
let operation = AccountStateManagerOperation(content: .pollCompletion(pollId, messages, subscribers))
|
||||
operation.isRunning = self.operations[i].isRunning
|
||||
self.operations[i] = operation
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,15 +37,15 @@ private func updatedRemoteContactPeers(network: Network, hash: Int32) -> Signal<
|
||||
}
|
||||
|
||||
private func hashForCountAndIds(count: Int32, ids: [Int32]) -> Int32 {
|
||||
var acc: UInt32 = 0
|
||||
var acc: Int64 = 0
|
||||
|
||||
acc = (acc &* 20261) &+ UInt32(bitPattern: count)
|
||||
acc = (acc &* 20261) &+ Int64(count)
|
||||
|
||||
for id in ids {
|
||||
let low = UInt32(bitPattern: id)
|
||||
acc = (acc &* 20261) &+ low
|
||||
acc = (acc &* 20261) &+ Int64(id)
|
||||
acc = acc & Int64(0x7FFFFFFF)
|
||||
}
|
||||
return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
|
||||
return Int32(acc & Int64(0x7FFFFFFF))
|
||||
}
|
||||
|
||||
func syncContactsOnce(network: Network, postbox: Postbox) -> Signal<Never, NoError> {
|
||||
|
||||
@@ -20,8 +20,9 @@ private final class ContactSyncOperation {
|
||||
}
|
||||
|
||||
private enum ContactSyncOperationContent {
|
||||
case waitForUpdatedState
|
||||
case sync(importableContacts: [DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData]?)
|
||||
case updateIsContact(peerId: PeerId, isContact: Bool)
|
||||
case updateIsContact([(PeerId, Bool)])
|
||||
}
|
||||
|
||||
private final class ContactSyncManagerImpl {
|
||||
@@ -53,15 +54,22 @@ private final class ContactSyncManagerImpl {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.addOperation(.waitForUpdatedState)
|
||||
strongSelf.addOperation(.sync(importableContacts: importableContacts))
|
||||
}))
|
||||
}
|
||||
|
||||
func addIsContactUpdates(_ updates: [(PeerId, Bool)]) {
|
||||
self.addOperation(.updateIsContact(updates))
|
||||
}
|
||||
|
||||
func addOperation(_ content: ContactSyncOperationContent) {
|
||||
let id = self.nextId
|
||||
self.nextId += 1
|
||||
let operation = ContactSyncOperation(id: id, content: content)
|
||||
switch content {
|
||||
case .waitForUpdatedState:
|
||||
self.operations.append(operation)
|
||||
case .sync:
|
||||
for i in (0 ..< self.operations.count).reversed() {
|
||||
if case .sync = self.operations[i].content {
|
||||
@@ -70,10 +78,28 @@ private final class ContactSyncManagerImpl {
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
self.operations.append(operation)
|
||||
case let .updateIsContact(updates):
|
||||
var mergedUpdates: [(PeerId, Bool)] = []
|
||||
var removeIndices: [Int] = []
|
||||
for i in 0 ..< self.operations.count {
|
||||
if case let .updateIsContact(operationUpdates) = self.operations[i].content {
|
||||
if !self.operations[i].isRunning {
|
||||
mergedUpdates.append(contentsOf: operationUpdates)
|
||||
removeIndices.append(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
mergedUpdates.append(contentsOf: updates)
|
||||
for index in removeIndices.reversed() {
|
||||
self.operations.remove(at: index)
|
||||
}
|
||||
if self.operations.isEmpty || !self.operations[0].isRunning {
|
||||
self.operations.insert(operation, at: 0)
|
||||
} else {
|
||||
self.operations.insert(operation, at: 1)
|
||||
}
|
||||
}
|
||||
self.operations.append(operation)
|
||||
self.updateOperations()
|
||||
}
|
||||
|
||||
@@ -100,6 +126,11 @@ private final class ContactSyncManagerImpl {
|
||||
|
||||
func startOperation(_ operation: ContactSyncOperationContent, disposable: DisposableSet, completion: @escaping () -> Void) {
|
||||
switch operation {
|
||||
case .waitForUpdatedState:
|
||||
disposable.add((self.stateManager.pollStateUpdateCompletion()
|
||||
|> deliverOn(self.queue)).start(next: { _ in
|
||||
completion()
|
||||
}))
|
||||
case let .sync(importableContacts):
|
||||
let importSignal: Signal<PushDeviceContactsResult, NoError>
|
||||
if let importableContacts = importableContacts {
|
||||
@@ -107,18 +138,14 @@ private final class ContactSyncManagerImpl {
|
||||
} else {
|
||||
importSignal = .single(PushDeviceContactsResult(addedReimportAttempts: [:]))
|
||||
}
|
||||
disposable.add((self.stateManager.pollStateUpdateCompletion()
|
||||
|> mapToSignal { _ -> Signal<PushDeviceContactsResult, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> then(
|
||||
syncContactsOnce(network: self.network, postbox: self.postbox)
|
||||
disposable.add(
|
||||
(syncContactsOnce(network: self.network, postbox: self.postbox)
|
||||
|> mapToSignal { _ -> Signal<PushDeviceContactsResult, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|> then(importSignal)
|
||||
)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] result in
|
||||
|> deliverOn(self.queue)
|
||||
).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@@ -128,17 +155,17 @@ private final class ContactSyncManagerImpl {
|
||||
|
||||
completion()
|
||||
}))
|
||||
case let .updateIsContact(peerId, isContact):
|
||||
case let .updateIsContact(updates):
|
||||
disposable.add((self.postbox.transaction { transaction -> Void in
|
||||
if transaction.isPeerContact(peerId: peerId) != isContact {
|
||||
var contactPeerIds = transaction.getContactPeerIds()
|
||||
var contactPeerIds = transaction.getContactPeerIds()
|
||||
for (peerId, isContact) in updates {
|
||||
if isContact {
|
||||
contactPeerIds.insert(peerId)
|
||||
} else {
|
||||
contactPeerIds.remove(peerId)
|
||||
}
|
||||
transaction.replaceContactPeerIds(contactPeerIds)
|
||||
}
|
||||
transaction.replaceContactPeerIds(contactPeerIds)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
completion()
|
||||
@@ -320,4 +347,10 @@ final class ContactSyncManager {
|
||||
impl.beginSync(importableContacts: importableContacts)
|
||||
}
|
||||
}
|
||||
|
||||
func addIsContactUpdates(_ updates: [(PeerId, Bool)]) {
|
||||
self.impl.with { impl in
|
||||
impl.addIsContactUpdates(updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public final class Localization: PostboxCoding, Equatable {
|
||||
public let version: Int32
|
||||
public let entries: [LocalizationEntry]
|
||||
|
||||
init(version: Int32, entries: [LocalizationEntry]) {
|
||||
public init(version: Int32, entries: [LocalizationEntry]) {
|
||||
self.version = version
|
||||
self.entries = entries
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ public final class LocalizationSettings: PreferencesEntry, Equatable {
|
||||
public let languageCode: String
|
||||
public let localization: Localization
|
||||
|
||||
init(languageCode: String, localization: Localization) {
|
||||
public init(languageCode: String, localization: Localization) {
|
||||
self.languageCode = languageCode
|
||||
self.localization = localization
|
||||
}
|
||||
|
||||
@@ -94,7 +94,13 @@ func managedSynchronizeInstalledStickerPacksOperations(postbox: Postbox, network
|
||||
let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal<Void, NoError> in
|
||||
if let entry = entry {
|
||||
if let operation = entry.contents as? SynchronizeInstalledStickerPacksOperation {
|
||||
return synchronizeInstalledStickerPacks(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, namespace: namespace, operation: operation)
|
||||
return stateManager.pollStateUpdateCompletion()
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
return synchronizeInstalledStickerPacks(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, namespace: namespace, operation: operation)
|
||||
}
|
||||
|> switchToLatest
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
|
||||
@@ -866,6 +866,7 @@ public final class PendingMessageManager {
|
||||
}
|
||||
|
||||
return sendMessageRequest
|
||||
|> deliverOn(queue)
|
||||
|> mapToSignal { result -> Signal<Void, MTRpcError> in
|
||||
if let strongSelf = self {
|
||||
return strongSelf.applySentMessage(postbox: postbox, stateManager: stateManager, message: message, result: result)
|
||||
|
||||
Reference in New Issue
Block a user