This commit is contained in:
overtake 2019-05-14 19:30:30 +02:00
commit 67b6ac79c9
3 changed files with 175 additions and 113 deletions

View File

@ -350,7 +350,7 @@ public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encrypt
}
}
public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters)
@ -366,7 +366,18 @@ public func accountWithId(accountManager: AccountManager, networkArguments: Netw
}
|> mapToSignal { localizationSettings, proxySettings -> Signal<AccountResult, NoError> in
return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in
return (transaction.getState(), localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings)
var state = transaction.getState()
if state == nil, let backupData = backupData {
let backupState = AuthorizedAccountState(isTestingEnvironment: beginWithTestingEnvironment, masterDatacenterId: backupData.masterDatacenterId, peerId: PeerId(backupData.peerId), state: nil)
state = backupState
let dict = NSMutableDictionary()
dict.setObject(MTDatacenterAuthInfo(authKey: backupData.masterDatacenterKey, authKeyId: backupData.masterDatacenterKeyId, saltSet: [], authKeyAttributes: [:], mainTempAuthKey: nil, mediaTempAuthKey: nil), forKey: backupData.masterDatacenterId as NSNumber)
let data = NSKeyedArchiver.archivedData(withRootObject: dict)
transaction.setState(backupState)
transaction.setKeychainEntry(data, forKey: "persistent:datacenterAuthInfoById")
}
return (state, localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings)
}
|> mapToSignal { (accountState, localizationSettings, proxySettings, networkSettings) -> Signal<AccountResult, NoError> in
let keychain = makeExclusiveKeychain(id: id, postbox: postbox)
@ -911,6 +922,62 @@ public func decryptedNotificationPayload(account: Account, data: Data) -> Signal
}
}
public struct AccountBackupData: Codable, Equatable {
public var masterDatacenterId: Int32
public var peerId: Int64
public var masterDatacenterKey: Data
public var masterDatacenterKeyId: Int64
}
public final class AccountBackupDataAttribute: AccountRecordAttribute, Equatable {
public let data: AccountBackupData
public init(data: AccountBackupData) {
self.data = data
}
public init(decoder: PostboxDecoder) {
self.data = try! JSONDecoder().decode(AccountBackupData.self, from: decoder.decodeDataForKey("data")!)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeData(try! JSONEncoder().encode(self.data), forKey: "data")
}
public static func ==(lhs: AccountBackupDataAttribute, rhs: AccountBackupDataAttribute) -> Bool {
return lhs.data == rhs.data
}
public func isEqual(to: AccountRecordAttribute) -> Bool {
if let to = to as? AccountBackupDataAttribute {
return self == to
} else {
return false
}
}
}
public func accountBackupData(postbox: Postbox) -> Signal<AccountBackupData?, NoError> {
return postbox.transaction { transaction -> AccountBackupData? in
guard let state = transaction.getState() as? AuthorizedAccountState else {
return nil
}
guard let authInfoData = transaction.keychainEntryForKey("persistent:datacenterAuthInfoById") else {
return nil
}
guard let authInfo = NSKeyedUnarchiver.unarchiveObject(with: authInfoData) as? NSDictionary else {
return nil
}
guard let datacenterAuthInfo = authInfo.object(forKey: state.masterDatacenterId as NSNumber) as? MTDatacenterAuthInfo else {
return nil
}
guard let authKey = datacenterAuthInfo.authKey else {
return nil
}
return AccountBackupData(masterDatacenterId: state.masterDatacenterId, peerId: state.peerId.toInt64(), masterDatacenterKey: authKey, masterDatacenterKeyId: datacenterAuthInfo.authKeyId)
}
}
public class Account {
public let id: AccountRecordId
public let basePath: String

View File

@ -139,6 +139,7 @@ private var declaredEncodables: Void = {
declareEncodable(CloudDocumentSizeMediaResource.self, f: { CloudDocumentSizeMediaResource(decoder: $0) })
declareEncodable(CloudPeerPhotoSizeMediaResource.self, f: { CloudPeerPhotoSizeMediaResource(decoder: $0) })
declareEncodable(CloudStickerPackThumbnailMediaResource.self, f: { CloudStickerPackThumbnailMediaResource(decoder: $0) })
declareEncodable(AccountBackupDataAttribute.self, f: { AccountBackupDataAttribute(decoder: $0) })
return
}()
@ -219,7 +220,7 @@ public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkI
return false
}
})
return accountWithId(accountManager: manager, networkArguments: networkArguments, id: record.0, encryptionParameters: encryptionParameters, supplementary: supplementary, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, auxiliaryMethods: auxiliaryMethods)
return accountWithId(accountManager: manager, networkArguments: networkArguments, id: record.0, encryptionParameters: encryptionParameters, supplementary: supplementary, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, backupData: nil, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { accountResult -> Signal<AccountResult?, NoError> in
let postbox: Postbox
let initialKind: AccountKind
@ -385,7 +386,7 @@ private func cleanupAccount(networkArguments: NetworkInitializationArguments, ac
return false
}
})
return accountWithId(accountManager: accountManager, networkArguments: networkArguments, id: id, encryptionParameters: encryptionParameters, supplementary: true, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, auxiliaryMethods: auxiliaryMethods)
return accountWithId(accountManager: accountManager, networkArguments: networkArguments, id: id, encryptionParameters: encryptionParameters, supplementary: true, rootPath: rootPath, beginWithTestingEnvironment: beginWithTestingEnvironment, backupData: nil, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Void, NoError> in
switch account {
case .upgrading:

View File

@ -316,6 +316,7 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
switch historyState {
case let .channel(peerId, _):
let hash = hashForMessages(previousMessages, withChannelIds: false)
Logger.shared.log("HistoryValidation", "validate batch for \(peerId): \(previousMessages.map({ $0.id }))")
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
let requestSignal: Signal<Api.messages.Messages, MTRpcError>
if let tag = tag {
@ -358,34 +359,6 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
} else {
return .complete()
}
/*case let .group(groupId, _):
signal = .single(.notModified)
let hash = hashForMessages(previousMessages, withChannelIds: true)
let upperIndex = MessageIndex(previousMessages[previousMessages.count - 1])
let minIndex = MessageIndex(previousMessages[0]).predecessor()
let upperInputPeer: Api.Peer = groupBoundaryPeer(upperIndex.id.peerId, accountPeerId: accountPeerId)
let lowerInputPeer: Api.Peer = groupBoundaryPeer(minIndex.id.peerId, accountPeerId: accountPeerId)
var flags: Int32 = 0
flags |= (1 << 0)
let offsetPosition: Api.FeedPosition = .feedPosition(date: upperIndex.timestamp, peer: upperInputPeer, id: upperIndex.id.id)
let addOffset: Int32 = -1
let minPosition: Api.FeedPosition = .feedPosition(date: minIndex.timestamp, peer: lowerInputPeer, id: minIndex.id.id)
flags |= (1 << 0)
flags |= (1 << 2)
signal = network.request(Api.functions.channels.getFeed(flags: flags, feedId: groupId.rawValue, offsetPosition: offsetPosition, addOffset: addOffset, limit: 200, maxPosition: nil, minPosition: minPosition, hash: hash))
|> map { result -> ValidatedMessages in
switch result {
case let .feedMessages(_, _, _, _, messages, chats, users):
return .messages(messages, chats, users, nil)
case .feedMessagesNotModified:
return .notModified
}
}*/
}
return signal
@ -394,37 +367,81 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
return .single(nil)
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
if let result = result {
switch result {
case let .messages(messages, chats, users, channelPts):
var storeMessages: [StoreMessage] = []
guard let result = result else {
return .complete()
}
switch result {
case let .messages(messages, chats, users, channelPts):
var storeMessages: [StoreMessage] = []
for message in messages {
if let storeMessage = StoreMessage(apiMessage: message) {
var attributes = storeMessage.attributes
for message in messages {
if let storeMessage = StoreMessage(apiMessage: message) {
var attributes = storeMessage.attributes
if let channelPts = channelPts {
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
}
switch historyState {
case .channel:
break
/*case let .group(_, groupState):
attributes.append(PeerGroupMessageStateVersionAttribute(stateIndex: groupState.stateIndex))*/
}
storeMessages.append(storeMessage.withUpdatedAttributes(attributes))
}
if let channelPts = channelPts {
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
}
/*if case .group = historyState {
let prevHash = hashForMessages(previousMessages, withChannelIds: true)
let updatedHash = hashForMessages(storeMessages, withChannelIds: true)
print("\(updatedHash) != \(prevHash)")
}*/
storeMessages.append(storeMessage.withUpdatedAttributes(attributes))
}
}
var validMessageIds = Set<MessageId>()
for message in storeMessages {
if case let .Id(id) = message.id {
validMessageIds.insert(id)
}
}
var maybeRemovedMessageIds: [MessageId] = []
for id in previous.keys {
if !validMessageIds.contains(id) {
maybeRemovedMessageIds.append(id)
}
}
let actuallyRemovedMessagesSignal: Signal<Set<MessageId>, NoError>
if maybeRemovedMessageIds.isEmpty {
actuallyRemovedMessagesSignal = .single(Set())
} else {
actuallyRemovedMessagesSignal = postbox.transaction { transaction -> Signal<Set<MessageId>, NoError> in
switch historyState {
case let .channel(peerId, _):
if let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) {
return network.request(Api.functions.channels.getMessages(channel: inputChannel, id: maybeRemovedMessageIds.map({ Api.InputMessage.inputMessageID(id: $0.id) })))
|> map { result -> Set<MessageId> in
let apiMessages: [Api.Message]
switch result {
case let .channelMessages(_, _, _, messages, _, _):
apiMessages = messages
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, messages, _, _):
apiMessages = messages
case .messagesNotModified:
return Set()
}
var ids = Set<MessageId>()
for message in apiMessages {
if let id = message.id {
ids.insert(id)
}
}
return ids
}
|> `catch` { _ -> Signal<Set<MessageId>, NoError> in
return .single(Set(maybeRemovedMessageIds))
}
}
}
return .single(Set(maybeRemovedMessageIds))
}
|> switchToLatest
}
return actuallyRemovedMessagesSignal
|> mapToSignal { removedMessageIds -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
var validMessageIds = Set<MessageId>()
for message in storeMessages {
if case let .Id(id) = message.id {
@ -470,22 +487,7 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts))
}
switch historyState {
case .channel:
break
/*case let .group(_, groupState):
for i in (0 ..< attributes.count).reversed() {
if let _ = attributes[i] as? PeerGroupMessageStateVersionAttribute {
attributes.remove(at: i)
}
}
attributes.append(PeerGroupMessageStateVersionAttribute(stateIndex: groupState.stateIndex))*/
}
var updatedFlags = StoreMessageFlags(currentMessage.flags)
/*if case .group = historyState {
updatedFlags.insert(.CanBeGroupedIntoFeed)
}*/
let updatedFlags = StoreMessageFlags(currentMessage.flags)
return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: updatedFlags, tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
}
@ -493,17 +495,14 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
if previous[id] == nil {
print("\(id) missing")
/*if case let .group(groupId, _) = historyState {
let _ = transaction.addMessagesToGroupFeedIndex(groupId: groupId, ids: [id])
}*/
}
} else {
let _ = transaction.addMessages([message], location: .Random)
}
}
}
for id in previous.keys {
for id in removedMessageIds {
if !validMessageIds.contains(id) {
if let tag = tag {
transaction.updateMessage(id, update: { currentMessage in
@ -519,43 +518,38 @@ private func validateBatch(postbox: Postbox, network: Network, accountPeerId: Pe
switch historyState {
case .channel:
deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: [id])
/*case let .group(groupId, _):
transaction.removeMessagesFromGroupFeedIndex(groupId: groupId, ids: [id])*/
Logger.shared.log("HistoryValidation", "deleting message \(id) in \(id.peerId)")
}
}
}
}
case .notModified:
for id in previous.keys {
transaction.updateMessage(id, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature)
}
var attributes = currentMessage.attributes
for i in (0 ..< attributes.count).reversed() {
switch historyState {
case .channel:
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
attributes.remove(at: i)
}
/*case .group:
if let _ = attributes[i] as? PeerGroupMessageStateVersionAttribute {
attributes.remove(at: i)
}*/
}
}
switch historyState {
case let .channel(_, channelState):
attributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts))
/*case let .group(_, groupState):
attributes.append(PeerGroupMessageStateVersionAttribute(stateIndex: groupState.stateIndex))*/
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
}
}
}
case .notModified:
return postbox.transaction { transaction -> Void in
for id in previous.keys {
transaction.updateMessage(id, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature)
}
var attributes = currentMessage.attributes
for i in (0 ..< attributes.count).reversed() {
switch historyState {
case .channel:
if let _ = attributes[i] as? ChannelMessageStateVersionAttribute {
attributes.remove(at: i)
}
}
}
switch historyState {
case let .channel(_, channelState):
attributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts))
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
}
}
}
}
}
} |> switchToLatest