no message

This commit is contained in:
Peter 2018-06-19 14:12:45 +01:00
parent 760861b8d2
commit fbe8936d6f
15 changed files with 459 additions and 53 deletions

View File

@ -258,6 +258,10 @@
D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */; };
D0458C881E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */; };
D0458C891E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */; };
D0467D0B20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */; };
D0467D0C20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */; };
D0467D1520D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */; };
D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */; };
D048B4AC20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */; };
D048B4AD20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */; };
D049EAD51E43D98500A2CD3A /* RecentMediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */; };
@ -875,6 +879,8 @@
D0448CA11E291B14005A61A7 /* FetchSecretFileResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchSecretFileResource.swift; sourceTree = "<group>"; };
D0448CA41E29215A005A61A7 /* MediaResourceApiUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResourceApiUtils.swift; sourceTree = "<group>"; };
D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingContentInfoMessageAttribute.swift; sourceTree = "<group>"; };
D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizeMarkAllUnseenPersonalMessagesOperation.swift; sourceTree = "<group>"; };
D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift; sourceTree = "<group>"; };
D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedProxyInfoUpdates.swift; sourceTree = "<group>"; };
D049EAD41E43D98500A2CD3A /* RecentMediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentMediaItem.swift; sourceTree = "<group>"; };
D049EAD71E43DAD200A2CD3A /* ManagedRecentStickers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedRecentStickers.swift; sourceTree = "<group>"; };
@ -1419,6 +1425,8 @@
D0C26D7A1FE31DAC004ABF18 /* ManagedGroupFeedReadStateSyncOperations.swift */,
D0380DB9204EF306000414AB /* MessageMediaPreuploadManager.swift */,
D048B4AB20A5DA4300C79D31 /* ManagedProxyInfoUpdates.swift */,
D0467D0A20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift */,
D0467D1420D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift */,
);
name = State;
sourceTree = "<group>";
@ -2089,6 +2097,7 @@
D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */,
D093D7F920641AA500BC3599 /* SecureIdEmailValue.swift in Sources */,
D0C44B611FC616E200227BE0 /* SearchGroupMembers.swift in Sources */,
D0467D1520D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */,
D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */,
D018D3371E648ACF00C5E089 /* CreateChannel.swift in Sources */,
D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */,
@ -2267,6 +2276,7 @@
D0561DEA1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */,
D099D7461EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */,
D0E412DC206A99AE00BEE4A2 /* SecureIdValueAccessContext.swift in Sources */,
D0467D0B20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */,
D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */,
D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */,
D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */,
@ -2468,6 +2478,7 @@
D03C536A1DAD5CA9004C17B3 /* TelegramUser.swift in Sources */,
D001F3EA1E128A1C007A8C60 /* TelegramPeerNotificationSettings.swift in Sources */,
D0E412F5206B9BDC00BEE4A2 /* SecureIdVerificationDocumentReference.swift in Sources */,
D0467D0C20D7F1E60055C28F /* SynchronizeMarkAllUnseenPersonalMessagesOperation.swift in Sources */,
D0FA8BA81E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */,
C23BC3881E9BE3CB00D79F92 /* ImportContact.swift in Sources */,
D0B85AC61F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */,
@ -2689,6 +2700,7 @@
D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */,
D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */,
D049EAF61E44DF3300A2CD3A /* AccountState.swift in Sources */,
D0467D1620D7F2C90055C28F /* ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift in Sources */,
D041E3F61E535464008C24B4 /* AddPeerMember.swift in Sources */,
D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */,
D0E305A81E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */,

View File

@ -260,6 +260,8 @@ private var declaredEncodables: Void = {
declareEncodable(SecureFileMediaResource.self, f: { SecureFileMediaResource(decoder: $0) })
declareEncodable(CachedStickerQueryResult.self, f: { CachedStickerQueryResult(decoder: $0) })
declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) })
declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) })
declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) })
return
}()
@ -780,6 +782,8 @@ public class Account {
self.managedOperationsDisposable.add(managedSynchronizeConsumeMessageContentOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
self.managedOperationsDisposable.add(managedConsumePersonalMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
self.managedOperationsDisposable.add(managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = [
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
self.pendingMessageManager.hasPendingMessages |> map { $0 ? AccountRunningImportantTasks.pendingMessages : [] }

View File

@ -749,7 +749,13 @@ private func finalStateWithUpdatesAndServerTime(account: Account, state: Account
if let message = StoreMessage(apiMessage: apiMessage) {
if let previousState = updatedState.chatStates[message.id.peerId] as? ChannelState {
if previousState.pts >= pts {
Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) skip old message \(message.id) (\(message.text))")
let messageText: String
if Logger.shared.redactSensitiveData {
messageText = "[[redacted]]"
} else {
messageText = message.text
}
Logger.shared.log("State", "channel \(message.id.peerId) (\((updatedState.peers[message.id.peerId] as? TelegramChannel)?.title ?? "nil")) skip old message \(message.id) (\(messageText))")
} else if previousState.pts + ptsCount == pts {
if let preCachedResources = apiMessage.preCachedResources {
for (resource, data) in preCachedResources {

View File

@ -457,6 +457,26 @@ public final class AccountViewTracker {
}
}
public func updateMarkAllMentionsSeen(peerId: PeerId) {
self.queue.async {
guard let account = self.account else {
return
}
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, tag: .unseenPersonalMessage).map({ $0.id }))
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
transaction.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: 0, maxId: summary.range.maxId)
addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: transaction, peerId: peerId, maxId: summary.range.maxId)
}
return ids
}
|> deliverOn(self.queue)).start(next: { [weak self] messageIds in
//self?.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
})
}
}
public func updateMarkMentionsSeenForMessageIds(messageIds: Set<MessageId>) {
self.queue.async {
var addedMessageIds: [MessageId] = []

View File

@ -643,6 +643,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-74070332] = { return Api.InputPhoto.parse_inputPhoto($0) }
dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) }
dict[1891070632] = { return Api.contacts.TopPeers.parse_topPeers($0) }
dict[-1255369827] = { return Api.contacts.TopPeers.parse_topPeersDisabled($0) }
dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) }
dict[-1073693790] = { return Api.auth.SentCodeType.parse_sentCodeTypeSms($0) }
dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) }

View File

@ -1257,6 +1257,7 @@ struct contacts {
enum TopPeers: TypeConstructorDescription {
case topPeersNotModified
case topPeers(categories: [Api.TopPeerCategoryPeers], chats: [Api.Chat], users: [Api.User])
case topPeersDisabled
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -1285,6 +1286,12 @@ struct contacts {
for item in users {
item.serialize(buffer, true)
}
break
case .topPeersDisabled:
if boxed {
buffer.appendInt32(-1255369827)
}
break
}
}
@ -1295,6 +1302,8 @@ struct contacts {
return ("topPeersNotModified", [])
case .topPeers(let categories, let chats, let users):
return ("topPeers", [("categories", categories), ("chats", chats), ("users", users)])
case .topPeersDisabled:
return ("topPeersDisabled", [])
}
}
@ -1324,6 +1333,9 @@ struct contacts {
return nil
}
}
static func parse_topPeersDisabled(_ reader: BufferReader) -> TopPeers? {
return Api.contacts.TopPeers.topPeersDisabled
}
}
}

View File

@ -3892,6 +3892,20 @@ extension Api {
return result
})
}
static func toggleTopPeers(enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-2062238246)
enabled.serialize(buffer, true)
return (FunctionDescription(name: "contacts.toggleTopPeers", parameters: [("enabled", enabled)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
struct help {
static func getConfig() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Config>) {

View File

@ -114,7 +114,7 @@ func applySecretOutgoingMessageReadActions(transaction: Transaction, id: Message
}
}
public func togglePeerUnreadMarkInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> {
public func togglePeerUnreadMarkInteractively(postbox: Postbox, viewTracker: AccountViewTracker, peerId: PeerId) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Void in
let namespace: MessageId.Namespace
if peerId.namespace == Namespaces.Peer.SecretChat {
@ -129,6 +129,7 @@ public func togglePeerUnreadMarkInteractively(postbox: Postbox, peerId: PeerId)
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: namespace) {
let _ = transaction.applyInteractiveReadMaxIndex(index)
}
viewTracker.updateMarkAllMentionsSeen(peerId: peerId)
} else {
transaction.applyMarkUnread(peerId: peerId, namespace: namespace, value: true, interactive: true)
}

View File

@ -70,6 +70,7 @@ public final class Logger {
public var logToFile: Bool = true
public var logToConsole: Bool = true
public var redactSensitiveData: Bool = true
public static func setSharedLogger(_ logger: Logger) {
sharedLogger = logger

View File

@ -12,42 +12,42 @@ import Foundation
public final class LoggingSettings: PreferencesEntry, Equatable {
public let logToFile: Bool
public let logToConsole: Bool
public let redactSensitiveData: Bool
#if DEBUG
public static var defaultSettings = LoggingSettings(logToFile: true, logToConsole: true)
public static var defaultSettings = LoggingSettings(logToFile: true, logToConsole: true, redactSensitiveData: true)
#else
public static var defaultSettings = LoggingSettings(logToFile: false, logToConsole: false)
public static var defaultSettings = LoggingSettings(logToFile: false, logToConsole: false, redactSensitiveData: true)
#endif
public init(logToFile: Bool, logToConsole: Bool) {
public init(logToFile: Bool, logToConsole: Bool, redactSensitiveData: Bool) {
self.logToFile = logToFile
self.logToConsole = logToConsole
self.redactSensitiveData = redactSensitiveData
}
public init(decoder: PostboxDecoder) {
self.logToFile = decoder.decodeInt32ForKey("logToFile", orElse: 0) != 0
self.logToConsole = decoder.decodeInt32ForKey("logToConsole", orElse: 0) != 0
self.redactSensitiveData = decoder.decodeInt32ForKey("redactSensitiveData", orElse: 1) != 0
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.logToFile ? 1 : 0, forKey: "logToFile")
encoder.encodeInt32(self.logToConsole ? 1 : 0, forKey: "logToConsole")
encoder.encodeInt32(self.redactSensitiveData ? 1 : 0, forKey: "redactSensitiveData")
}
public func withUpdatedLogToFile(_ logToFile: Bool) -> LoggingSettings {
return LoggingSettings(logToFile: logToFile, logToConsole: self.logToConsole)
return LoggingSettings(logToFile: logToFile, logToConsole: self.logToConsole, redactSensitiveData: self.redactSensitiveData)
}
public func withUpdatedLogToConsole(_ logToConsole: Bool) -> LoggingSettings {
return LoggingSettings(logToFile: self.logToFile, logToConsole: logToConsole)
return LoggingSettings(logToFile: self.logToFile, logToConsole: logToConsole, redactSensitiveData: self.redactSensitiveData)
}
public func isEqual(to: PreferencesEntry) -> Bool {
guard let to = to as? LoggingSettings else {
return false
}
return self == to
public func withUpdatedRedactSensitiveData(_ redactSensitiveData: Bool) -> LoggingSettings {
return LoggingSettings(logToFile: self.logToFile, logToConsole: self.logToConsole, redactSensitiveData: redactSensitiveData)
}
public static func ==(lhs: LoggingSettings, rhs: LoggingSettings) -> Bool {
@ -57,8 +57,19 @@ public final class LoggingSettings: PreferencesEntry, Equatable {
if lhs.logToConsole != rhs.logToConsole {
return false
}
if lhs.redactSensitiveData != rhs.redactSensitiveData {
return false
}
return true
}
public func isEqual(to: PreferencesEntry) -> Bool {
guard let to = to as? LoggingSettings else {
return false
}
return self == to
}
}
public func updateLoggingSettings(postbox: Postbox, _ f: @escaping (LoggingSettings) -> LoggingSettings) -> Signal<Void, NoError> {
@ -77,6 +88,7 @@ public func updateLoggingSettings(postbox: Postbox, _ f: @escaping (LoggingSetti
if let updated = updated {
Logger.shared.logToFile = updated.logToFile
Logger.shared.logToConsole = updated.logToConsole
Logger.shared.redactSensitiveData = updated.redactSensitiveData
}
}
}

View File

@ -0,0 +1,186 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
private final class ManagedSynchronizeMarkAllUnseenPersonalMessagesOperationsHelper {
var operationDisposables: [Int32: Disposable] = [:]
func update(_ entries: [PeerMergedOperationLogEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) {
var disposeOperations: [Disposable] = []
var beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)] = []
var hasRunningOperationForPeerId = Set<PeerId>()
var validMergedIndices = Set<Int32>()
for entry in entries {
if !hasRunningOperationForPeerId.contains(entry.peerId) {
hasRunningOperationForPeerId.insert(entry.peerId)
validMergedIndices.insert(entry.mergedIndex)
if self.operationDisposables[entry.mergedIndex] == nil {
let disposable = MetaDisposable()
beginOperations.append((entry, disposable))
self.operationDisposables[entry.mergedIndex] = disposable
}
}
}
var removeMergedIndices: [Int32] = []
for (mergedIndex, disposable) in self.operationDisposables {
if !validMergedIndices.contains(mergedIndex) {
removeMergedIndices.append(mergedIndex)
disposeOperations.append(disposable)
}
}
for mergedIndex in removeMergedIndices {
self.operationDisposables.removeValue(forKey: mergedIndex)
}
return (disposeOperations, beginOperations)
}
func reset() -> [Disposable] {
let disposables = Array(self.operationDisposables.values)
self.operationDisposables.removeAll()
return disposables
}
}
private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal<Void, NoError>) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in
var result: PeerMergedOperationLogEntry?
transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in
if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeMarkAllUnseenPersonalMessagesOperation {
result = entry.mergedEntry!
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
} else {
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
}
})
return f(transaction, result)
} |> switchToLatest
}
func managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkAllUnseenPersonalMessages
let helper = Atomic<ManagedSynchronizeMarkAllUnseenPersonalMessagesOperationsHelper>(value: ManagedSynchronizeMarkAllUnseenPersonalMessagesOperationsHelper())
let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in
let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in
return helper.update(view.entries)
}
for disposable in disposeOperations {
disposable.dispose()
}
for (entry, disposable) in beginOperations {
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? SynchronizeMarkAllUnseenPersonalMessagesOperation {
return synchronizeMarkAllUnseen(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, peerId: entry.peerId, operation: operation)
} else {
assertionFailure()
}
}
return .complete()
})
|> then(postbox.transaction { transaction -> Void in
let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex)
})
disposable.set(signal.start())
}
})
return ActionDisposable {
let disposables = helper.with { helper -> [Disposable] in
return helper.reset()
}
for disposable in disposables {
disposable.dispose()
}
disposable.dispose()
}
}
}
private enum GetUnseenIdsError {
case done
case error(MTRpcError)
}
private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, operation: SynchronizeMarkAllUnseenPersonalMessagesOperation) -> Signal<Void, NoError> {
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else {
return .complete()
}
let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel)
let oneOperation: Signal<Bool, MTRpcError> = network.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: 0, addOffset: 0, limit: 100, maxId: 0, minId: 0))
|> mapToSignal { result -> Signal<[MessageId], MTRpcError> in
switch result {
case let .messages(messages, _, _):
return .single(messages.compactMap({ $0.id }))
case let .channelMessages(channelMessages):
return .single(channelMessages.messages.compactMap({ $0.id }))
case .messagesNotModified:
return .single([])
case let .messagesSlice(messagesSlice):
return .single(messagesSlice.messages.compactMap({ $0.id }))
}
}
|> mapToSignal { ids -> Signal<Bool, MTRpcError> in
if peerId.namespace == Namespaces.Peer.CloudChannel {
guard let inputChannel = inputChannel else {
return .single(true)
}
return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: ids.map { $0.id }))
|> mapToSignal { result -> Signal<Bool, MTRpcError> in
return .single(true)
}
} else {
return network.request(Api.functions.messages.readMessageContents(id: ids.map { $0.id }))
|> mapToSignal { result -> Signal<Bool, MTRpcError> in
switch result {
case let .affectedMessages(pts, ptsCount):
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
}
return .single(true)
}
}
}
let loopOperations: Signal<Void, GetUnseenIdsError> = (
(oneOperation
|> `catch` { error -> Signal<Bool, GetUnseenIdsError> in
return .fail(.error(error))
}
)
|> mapToSignal { result -> Signal<Void, GetUnseenIdsError> in
if result {
return .fail(.done)
} else {
return .complete()
}
}
|> `catch` { error -> Signal<Void, GetUnseenIdsError> in
switch error {
case .done, .error:
return .fail(error)
}
}
|> restart
)
return loopOperations
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}
}

View File

@ -123,6 +123,7 @@ struct OperationLogTags {
static let SynchronizeLocalizationUpdates = PeerOperationLogTag(value: 13)
static let SynchronizeSavedStickers = PeerOperationLogTag(value: 14)
static let SynchronizeGroupedPeers = PeerOperationLogTag(value: 15)
static let SynchronizeMarkAllUnseenPersonalMessages = PeerOperationLogTag(value: 16)
}
private enum PreferencesKeyValues: Int32 {

View File

@ -7,13 +7,86 @@ import Foundation
import SwiftSignalKit
#endif
public func recentPeers(account: Account) -> Signal<[Peer], NoError> {
let cachedPeers = account.postbox.recentPeers()
|> take(1)
public enum RecentPeers {
case peers([Peer])
case disabled
}
final class CachedRecentPeers: PostboxCoding {
let enabled: Bool
let ids: [PeerId]
let remotePeers = account.network.request(Api.functions.contacts.getTopPeers(flags: 1 << 0, offset: 0, limit: 16, hash: 0))
|> retryRequest
|> map { result -> ([Peer], [PeerId: PeerPresence])? in
init(enabled: Bool, ids: [PeerId]) {
self.enabled = enabled
self.ids = ids
}
init(decoder: PostboxDecoder) {
self.enabled = decoder.decodeInt32ForKey("enabled", orElse: 0) != 0
self.ids = decoder.decodeInt64ArrayForKey("ids").map(PeerId.init)
}
func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "enabled")
encoder.encodeInt64Array(self.ids.map({ $0.toInt64() }), forKey: "ids")
}
static func cacheKey() -> ValueBoxKey {
let key = ValueBoxKey(length: 0)
return key
}
}
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)
private func cachedRecentPeersEntryId() -> ItemCacheEntryId {
return ItemCacheEntryId(collectionId: 101, key: CachedRecentPeers.cacheKey())
}
public func recentPeers(account: Account) -> Signal<RecentPeers, NoError> {
let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId())
return account.postbox.combinedView(keys: [key])
|> mapToSignal { views -> Signal<RecentPeers, NoError> in
if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers {
if value.enabled {
return account.postbox.multiplePeersView(value.ids)
|> map { view -> RecentPeers in
var peers: [Peer] = []
for id in value.ids {
if let peer = view.peers[id], id != account.peerId {
peers.append(peer)
}
}
return .peers(peers)
}
} else {
return .single(.disabled)
}
} else {
return .single(.peers([]))
}
}
}
public func managedUpdatedRecentPeers(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId())
let peersEnabled = postbox.combinedView(keys: [key])
|> map { views -> Bool in
if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers {
return value.enabled
} else {
return true
}
}
|> distinctUntilChanged
let updateOnce =
network.request(Api.functions.contacts.getTopPeers(flags: 1 << 0, offset: 0, limit: 16, hash: 0))
|> `catch` { _ -> Signal<Api.contacts.TopPeers, NoError> in
return .complete()
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
switch result {
case let .topPeers(_, _, users):
var peers: [Peer] = []
@ -25,39 +98,33 @@ public func recentPeers(account: Account) -> Signal<[Peer], NoError> {
peerPresences[telegramUser.id] = presence
}
}
return (peers, peerPresences)
case .topPeersNotModified:
break
}
return ([], [:])
}
let updatedRemotePeers = remotePeers
|> mapToSignal { peersAndPresences -> Signal<[Peer], NoError> in
if let (peers, peerPresences) = peersAndPresences {
return account.postbox.transaction { transaction -> [Peer] in
updatePeers(transaction: transaction, peers: peers, update: { return $1 })
transaction.updatePeerPresences(peerPresences)
transaction.replaceRecentPeerIds(peers.map({ $0.id }))
return peers
}
} else {
return .complete()
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: peers.map { $0.id }), collectionSpec: collectionSpec)
case .topPeersNotModified:
break
case .topPeersDisabled:
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec)
}
}
return cachedPeers
|> then(updatedRemotePeers |> filter({ !$0.isEmpty }))
|> map { peers -> [Peer] in
return peers.filter { $0.id != account.peerId }
}
}
return peersEnabled |> mapToSignal { _ -> Signal<Void, NoError> in
return updateOnce
}
}
public func removeRecentPeer(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
var peerIds = transaction.getRecentPeerIds()
if let index = peerIds.index(of: peerId) {
peerIds.remove(at: index)
transaction.replaceRecentPeerIds(peerIds)
guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers else {
return .complete()
}
if let index = entry.ids.index(of: peerId) {
var updatedIds = entry.ids
updatedIds.remove(at: index)
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: entry.enabled, ids: updatedIds), collectionSpec: collectionSpec)
}
if let peer = transaction.getPeer(peerId), let apiPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.contacts.resetTopPeerRating(category: .topPeerCategoryCorrespondents, peer: apiPeer))
@ -73,11 +140,39 @@ public func removeRecentPeer(account: Account, peerId: PeerId) -> Signal<Void, N
} |> switchToLatest
}
public func updateRecentPeersEnabled(postbox: Postbox, network: Network, enabled: Bool) -> Signal<Void, NoError> {
return postbox.transaction { transaction -> Signal<Void, NoError> in
var currentValue = true
if let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers {
currentValue = entry.enabled
if !enabled {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec)
} else {
transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: entry.ids), collectionSpec: collectionSpec)
}
}
if currentValue == enabled {
return .complete()
}
return network.request(Api.functions.contacts.toggleTopPeers(enabled: currentValue ? .boolTrue : .boolFalse))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
} |> switchToLatest
}
public func managedRecentlyUsedInlineBots(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let remotePeers = network.request(Api.functions.contacts.getTopPeers(flags: 1 << 2, offset: 0, limit: 16, hash: 0))
|> retryRequest
|> map { result -> ([Peer], [PeerId: PeerPresence], [(PeerId, Double)])? in
switch result {
case .topPeersDisabled:
break
case let .topPeers(categories, _, users):
var peers: [Peer] = []
var peerPresences: [PeerId: PeerPresence] = [:]

View File

@ -48,10 +48,10 @@ func apiFunctionDescription(of desc: FunctionDescription) -> String {
redactParam = redactParams.contains(param.0)
}
if redactParam {
if redactParam, Logger.shared.redactSensitiveData {
result.append("[[redacted]]")
} else {
result.append(recursiveDescription(redact: true, of: param.1))
result.append(recursiveDescription(redact: Logger.shared.redactSensitiveData, of: param.1))
}
}
result.append(")")
@ -195,13 +195,7 @@ public class BoxedMessage: NSObject {
override public var description: String {
get {
let redact: Bool
#if DEBUG
redact = true
#else
redact = true
#endif
return recursiveDescription(redact: redact, of: self.body)
return recursiveDescription(redact: Logger.shared.redactSensitiveData, of: self.body)
}
}
}

View File

@ -0,0 +1,47 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
#else
import Postbox
import SwiftSignalKit
#endif
final class SynchronizeMarkAllUnseenPersonalMessagesOperation: PostboxCoding {
let maxId: MessageId.Id
init(maxId: MessageId.Id) {
self.maxId = maxId
}
init(decoder: PostboxDecoder) {
self.maxId = decoder.decodeInt32ForKey("maxId", orElse: Int32.min + 1)
}
func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.maxId, forKey: "maxId")
}
}
func addSynchronizeMarkAllUnseenPersonalMessagesOperation(transaction: Transaction, peerId: PeerId, maxId: MessageId.Id) {
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeMarkAllUnseenPersonalMessages
var topLocalIndex: Int32?
var currentMaxId: MessageId.Id?
transaction.operationLogEnumerateEntries(peerId: peerId, tag: tag, { entry in
topLocalIndex = entry.tagLocalIndex
if let operation = entry.contents as? SynchronizeMarkAllUnseenPersonalMessagesOperation {
currentMaxId = operation.maxId
}
return false
})
if let topLocalIndex = topLocalIndex {
if let currentMaxId = currentMaxId, currentMaxId >= maxId {
return
}
let _ = transaction.operationLogRemoveEntry(peerId: peerId, tag: tag, tagLocalIndex: topLocalIndex)
}
transaction.operationLogAddEntry(peerId: peerId, tag: tag, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SynchronizeMarkAllUnseenPersonalMessagesOperation(maxId: maxId))
}