no message

This commit is contained in:
Peter 2017-03-07 15:58:35 +03:00
parent d57b82cc15
commit 9af14df09e
14 changed files with 509 additions and 115 deletions

View File

@ -53,6 +53,16 @@
D00C7CE11E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */; };
D00C7CEB1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */; };
D00C7CEC1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */; };
D00D34391E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */; };
D00D343A1E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */; };
D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */; };
D00D343D1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */; };
D00D343F1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */; };
D00D34401E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */; };
D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */; };
D00D34431E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */; };
D00D34451E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */; };
D00D34461E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */; };
D00D97C71E32901700E5C2B6 /* PeerInputActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */; };
D00D97C81E32901700E5C2B6 /* PeerInputActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */; };
D00D97CA1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */; };
@ -457,6 +467,11 @@
D00C7CCE1E3628180080C3D5 /* UpdateCachedChannelParticipants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateCachedChannelParticipants.swift; sourceTree = "<group>"; };
D00C7CDF1E3785700080C3D5 /* MarkMessageContentAsConsumedInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarkMessageContentAsConsumedInteractively.swift; sourceTree = "<group>"; };
D00C7CEA1E37A8540080C3D5 /* SetSecretChatMessageAutoremoveTimeoutInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetSecretChatMessageAutoremoveTimeoutInteractively.swift; sourceTree = "<group>"; };
D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TeleramMediaUnsupported.swift; sourceTree = "<group>"; };
D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaGame.swift; sourceTree = "<group>"; };
D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsumableContentMessageAttribute.swift; sourceTree = "<group>"; };
D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeConsumeMessageContentsOperations.swift; sourceTree = "<group>"; };
D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeConsumeMessageContentsOperation.swift; sourceTree = "<group>"; };
D00D97C61E32901700E5C2B6 /* PeerInputActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerInputActivity.swift; sourceTree = "<group>"; };
D00D97C91E32917C00E5C2B6 /* PeerInputActivityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerInputActivityManager.swift; sourceTree = "<group>"; };
D00DBBD61E64E41100DB5485 /* CreateSecretChat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateSecretChat.swift; sourceTree = "<group>"; };
@ -866,6 +881,7 @@
D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */,
D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */,
D0458C871E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift */,
D00D343E1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift */,
);
name = Attributes;
sourceTree = "<group>";
@ -873,12 +889,14 @@
D03B0CDD1D62247D00955575 /* Media */ = {
isa = PBXGroup;
children = (
D00D34381E6EC9520057B307 /* TeleramMediaUnsupported.swift */,
D03B0CEC1D62250800955575 /* TelegramMediaAction.swift */,
D03B0CED1D62250800955575 /* TelegramMediaContact.swift */,
D03B0CEE1D62250800955575 /* TelegramMediaFile.swift */,
D03B0CEF1D62250800955575 /* TelegramMediaImage.swift */,
D03B0CF11D62250800955575 /* TelegramMediaMap.swift */,
D03B0CF31D62250800955575 /* TelegramMediaWebpage.swift */,
D00D343B1E6EC9770057B307 /* TelegramMediaGame.swift */,
D07827CA1E02F5B200071108 /* RichText.swift */,
D07827C81E02F59C00071108 /* InstantPage.swift */,
);
@ -911,6 +929,8 @@
D0BC38781E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift */,
D0BC38761E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift */,
D00DBBD91E64E67E00DB5485 /* UpdateSecretChat.swift */,
D00D34441E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift */,
D00D34411E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift */,
);
name = State;
sourceTree = "<group>";
@ -1357,12 +1377,15 @@
D03229F41E6B39700000AF9C /* ImportAccount.swift in Sources */,
D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */,
D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */,
D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */,
D033FEB01E61EB0200644997 /* PeerReportStatus.swift in Sources */,
D050F2511E4A59C200988324 /* JoinLink.swift in Sources */,
D07827C91E02F59C00071108 /* InstantPage.swift in Sources */,
D0458C881E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */,
D07827CB1E02F5B200071108 /* RichText.swift in Sources */,
D0613FD71E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */,
D00D34451E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */,
D00D343F1E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */,
D03B0CE01D62249100955575 /* StoreMessage_Telegram.swift in Sources */,
D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */,
D00C7CCF1E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */,
@ -1420,6 +1443,7 @@
D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */,
D0B843811DA6EDAE005F29E1 /* CachedUserData.swift in Sources */,
D049EAD51E43D98500A2CD3A /* RecentMediaItem.swift in Sources */,
D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */,
D03B0D0A1D62255C00955575 /* Holes.swift in Sources */,
D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */,
D03B0D5E1D631A6900955575 /* Network.swift in Sources */,
@ -1490,6 +1514,7 @@
D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */,
D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */,
D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */,
D00D34391E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */,
D00D97CA1E32917C00E5C2B6 /* PeerInputActivityManager.swift in Sources */,
C2FD33E11E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */,
D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */,
@ -1563,12 +1588,15 @@
D03229F51E6B39700000AF9C /* ImportAccount.swift in Sources */,
C239BE981E62F0D200C2C453 /* LoadMessagesIfNecessary.swift in Sources */,
C26A37EF1E5E0C41006977AC /* ChannelParticipants.swift in Sources */,
D00D343D1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */,
D050F26A1E4A5B6D00988324 /* ManagedGlobalNotificationSettings.swift in Sources */,
D050F26B1E4A5B6D00988324 /* ApplyMaxReadIndexInteractively.swift in Sources */,
D033FEB11E61EB0200644997 /* PeerReportStatus.swift in Sources */,
D0458C891E69B4AB00FB34C1 /* OutgoingContentInfoMessageAttribute.swift in Sources */,
D050F26C1E4A5B6D00988324 /* UpdatePeers.swift in Sources */,
D050F26D1E4A5B6D00988324 /* CreateGroup.swift in Sources */,
D00D34461E6EDD420057B307 /* SynchronizeConsumeMessageContentsOperation.swift in Sources */,
D00D34401E6ED6E50057B307 /* ConsumableContentMessageAttribute.swift in Sources */,
D050F26E1E4A5B6D00988324 /* RemovePeerChat.swift in Sources */,
D0613FD81E606B3B00202CDB /* ConvertGroupToSupergroup.swift in Sources */,
D01D6BFA1E42A718006151C6 /* SearchStickers.swift in Sources */,
@ -1626,6 +1654,7 @@
D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */,
D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */,
D00C7CD01E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */,
D00D34431E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */,
D049EAE91E44B67100A2CD3A /* RecentPeerItem.swift in Sources */,
D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */,
D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */,
@ -1696,6 +1725,7 @@
D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */,
D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */,
D0B844471DAB91FD005F29E1 /* ManagedServiceViews.swift in Sources */,
D00D343A1E6EC9520057B307 /* TeleramMediaUnsupported.swift in Sources */,
D03C53691DAD5CA9004C17B3 /* PeerAccessRestrictionInfo.swift in Sources */,
C2FD33E21E680E9E008D13D4 /* RequestUserPhotos.swift in Sources */,
D0B8440E1DAB91CD005F29E1 /* MessageUtils.swift in Sources */,

View File

@ -209,6 +209,7 @@ private var declaredEncodables: Void = {
declareEncodable(LoggedOutAccountAttribute.self, f: { LoggedOutAccountAttribute(decoder: $0) })
declareEncodable(CloudChatClearHistoryOperation.self, f: { CloudChatClearHistoryOperation(decoder: $0) })
declareEncodable(OutgoingContentInfoMessageAttribute.self, f: { OutgoingContentInfoMessageAttribute(decoder: $0) })
declareEncodable(ConsumableContentMessageAttribute.self, f: { ConsumableContentMessageAttribute(decoder: $0) })
return
}()

View File

@ -0,0 +1,22 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
public class ConsumableContentMessageAttribute: MessageAttribute {
public let consumed: Bool
public init(consumed: Bool) {
self.consumed = consumed
}
required public init(decoder: Decoder) {
self.consumed = (decoder.decodeInt32ForKey("c") as Int32) != 0
}
public func encode(_ encoder: Encoder) {
encoder.encodeInt32(self.consumed ? 1 : 0, forKey: "c")
}
}

View File

@ -139,7 +139,13 @@ private func removeMessages(postbox: Postbox, network: Network, stateManager: Ac
|> `catch` { _ in
return .single(nil)
}
|> mapToSignal { _ in
|> mapToSignal { result in
if let result = result {
switch result {
case let .affectedMessages(pts, ptsCount):
stateManager.addUpdateGroups([.updateChannelPts(channelId: peer.id.id, pts: pts, ptsCount: ptsCount)])
}
}
return .complete()
}
} else {

View File

@ -0,0 +1,135 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
private final class ManagedSynchronizeConsumeMessageContentsOperationHelper {
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, tagLocalIndex: Int32, _ f: @escaping (Modifier, PeerMergedOperationLogEntry?) -> Signal<Void, NoError>) -> Signal<Void, NoError> {
return postbox.modify { modifier -> Signal<Void, NoError> in
var result: PeerMergedOperationLogEntry?
modifier.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: tagLocalIndex, { entry in
if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizeConsumeMessageContentsOperation {
result = entry.mergedEntry!
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
} else {
return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none)
}
})
return f(modifier, result)
} |> switchToLatest
}
func managedSynchronizeConsumeMessageContentOperations(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in
let helper = Atomic<ManagedSynchronizeConsumeMessageContentsOperationHelper>(value: ManagedSynchronizeConsumeMessageContentsOperationHelper())
let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.SynchronizeConsumeMessageContents, 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, tagLocalIndex: entry.tagLocalIndex, { modifier, entry -> Signal<Void, NoError> in
if let entry = entry {
if let operation = entry.contents as? SynchronizeConsumeMessageContentsOperation {
return synchronizeConsumeMessageContents(network: network, stateManager: stateManager, peerId: entry.peerId, operation: operation)
} else {
assertionFailure()
}
}
return .complete()
})
|> then(postbox.modify { modifier -> Void in
let _ = modifier.operationLogRemoveEntry(peerId: entry.peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, 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 func synchronizeConsumeMessageContents(network: Network, stateManager: AccountStateManager, peerId: PeerId, operation: SynchronizeConsumeMessageContentsOperation) -> Signal<Void, NoError> {
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup {
return network.request(Api.functions.messages.readMessageContents(id: operation.messageIds.map { $0.id }))
|> map { Optional($0) }
|> `catch` { _ -> Signal<Api.messages.AffectedMessages?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<Void, NoError> in
if let result = result {
switch result {
case let .affectedMessages(pts, ptsCount):
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
}
}
return .complete()
}
} else {
return .complete()
}
}

View File

@ -123,7 +123,6 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
$0.namespace != Namespaces.Peer.SecretChat
}
//messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs;
return network.request(Api.functions.messages.getPinnedDialogs())
|> retryRequest
|> mapToSignal { dialogs -> Signal<Void, NoError> in
@ -217,6 +216,9 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
updatePeers(modifier: modifier, peers: peers, update: { _, updated -> Peer in
return updated
})
modifier.setPinnedPeerIds(resultingPeerIds)
modifier.updatePeerPresences(peerPresences)
modifier.updatePeerNotificationSettings(notificationSettings)
@ -251,26 +253,9 @@ private func synchronizePinnedChats(modifier: Modifier, postbox: Postbox, networ
}
|> mapToSignal { result -> Signal<Void, NoError> in
return postbox.modify { modifier -> Void in
modifier.setPinnedPeerIds(resultingPeerIds)
}
}
}
} |> switchToLatest
}
/*var inputPeers: [Api.InputPeer] = []
for peerId in peerIds {
if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
inputPeers.append(inputPeer)
}
}
return network.request(Api.functions.messages.reorderPinnedDialogs(flags: 1 << 0, order: inputPeers))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(Api.Bool.boolFalse)
}
|> mapToSignal { result -> Signal<Void, NoError> in
return .complete()
}*/
}

View File

@ -10,37 +10,41 @@ import Foundation
public func markMessageContentAsConsumedInteractively(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<Void, NoError> {
return postbox.modify { modifier -> Void in
if let message = modifier.getMessage(messageId), message.flags.contains(.Incoming) {
var updateMessage = false
var updatedAttributes = message.attributes
for i in 0 ..< updatedAttributes.count {
if let attribute = updatedAttributes[i] as? ConsumableContentMessageAttribute {
if !attribute.consumed {
updatedAttributes[i] = ConsumableContentMessageAttribute(consumed: true)
updateMessage = true
addSynchronizeConsumeMessageContentsOperation(modifier: modifier, messageIds: [message.id])
}
break
}
}
if messageId.peerId.namespace == Namespaces.Peer.SecretChat {
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
for attribute in message.attributes {
if let attribute = attribute as? AutoremoveTimeoutMessageAttribute {
for i in 0 ..< updatedAttributes.count {
if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute {
if attribute.countdownBeginTime == nil && message.containsSecretMedia {
modifier.updateMessage(message.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)
}
let updatedAttributes = currentMessage.attributes.map({ currentAttribute -> MessageAttribute in
if let currentAttribute = currentAttribute as? AutoremoveTimeoutMessageAttribute {
return AutoremoveTimeoutMessageAttribute(timeout: currentAttribute.timeout, countdownBeginTime: timestamp)
} else {
return currentAttribute
}
})
return StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)
})
updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp)
updateMessage = true
modifier.addTimestampBasedMessageAttribute(tag: 0, timestamp: timestamp + attribute.timeout, messageId: messageId)
var layer: SecretChatLayer?
var state = modifier.getPeerChatState(message.id.peerId) as? SecretChatState
let state = modifier.getPeerChatState(message.id.peerId) as? SecretChatState
if let state = state {
switch state.embeddedState {
case .terminated, .handshake:
break
case .basicLayer:
layer = .layer8
case let .sequenceBasedLayer(sequenceState):
layer = SecretChatLayer(rawValue: sequenceState.layerNegotiationState.activeLayer)
case .terminated, .handshake:
break
case .basicLayer:
layer = .layer8
case let .sequenceBasedLayer(sequenceState):
layer = SecretChatLayer(rawValue: sequenceState.layerNegotiationState.activeLayer)
}
}
@ -55,6 +59,16 @@ public func markMessageContentAsConsumedInteractively(postbox: Postbox, network:
}
}
}
if updateMessage {
modifier.updateMessage(message.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)
}
return StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media)
})
}
}
}
}

View File

@ -24,6 +24,7 @@ public struct Namespaces {
public static let LocalFile: Int32 = 8
public static let CloudSecretImage: Int32 = 9
public static let CloudSecretFile: Int32 = 10
public static let CloudGame: Int32 = 11
}
public struct Peer {
@ -71,6 +72,7 @@ struct OperationLogTags {
static let SynchronizePinnedCloudChats = PeerOperationLogTag(value: 4)
static let AutoremoveMessages = PeerOperationLogTag(value: 5)
static let SynchronizePinnedChats = PeerOperationLogTag(value: 6)
static let SynchronizeConsumeMessageContents = PeerOperationLogTag(value: 7)
}
private enum PreferencesKeyValues: Int32 {

View File

@ -229,11 +229,11 @@ func textAndMediaFromApiMedia(_ media: Api.MessageMedia?) -> (String?, Media?) {
return (nil, mediaWebpage)
}
case .messageMediaUnsupported:
break
return (nil, TelegramMediaUnsupported())
case .messageMediaEmpty:
break
case .messageMediaGame:
break
case let .messageMediaGame(game):
return (nil, TelegramMediaGame(apiGame: game))
}
}
@ -345,6 +345,14 @@ extension StoreMessage {
}
}
if let file = media as? TelegramMediaFile {
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup {
if file.isVoice {
attributes.append(ConsumableContentMessageAttribute(consumed: (flags & (1 << 5)) != 0))
}
}
}
if let viaBotId = viaBotId {
attributes.append(InlineBotMessageAttribute(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: viaBotId)))
}

View File

@ -0,0 +1,39 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
final class SynchronizeConsumeMessageContentsOperation: Coding {
let messageIds: [MessageId]
init(messageIds: [MessageId]) {
self.messageIds = messageIds
}
init(decoder: Decoder) {
self.messageIds = MessageId.decodeArrayFromBuffer(decoder.decodeBytesForKeyNoCopy("i")!)
}
func encode(_ encoder: Encoder) {
let buffer = WriteBuffer()
MessageId.encodeArrayToBuffer(self.messageIds, buffer: buffer)
encoder.encodeBytes(buffer, forKey: "i")
}
}
func addSynchronizeConsumeMessageContentsOperation(modifier: Modifier, messageIds: [MessageId]) {
for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(messageIds)) {
var updateLocalIndex: Int32?
/*modifier.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, { entry in
updateLocalIndex = entry.tagLocalIndex
return false
})*/
let operationContents = SynchronizeConsumeMessageContentsOperation(messageIds: messageIds)
if let updateLocalIndex = updateLocalIndex {
let _ = modifier.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: updateLocalIndex)
}
modifier.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents)
}
}

View File

@ -5,6 +5,13 @@ import Foundation
import Postbox
#endif
public enum PhoneCallDiscardReason: Int32 {
case missed = 0
case disconnect = 1
case hangup = 2
case busy = 3
}
public enum TelegramMediaActionType: Coding, Equatable {
case unknown
case groupCreated(title: String)
@ -19,6 +26,8 @@ public enum TelegramMediaActionType: Coding, Equatable {
case historyCleared
case historyScreenshot
case messageAutoremoveTimeoutUpdated(Int32)
case gameScore(gameId: Int64, score: Int32)
case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?)
public init(decoder: Decoder) {
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue")
@ -47,6 +56,14 @@ public enum TelegramMediaActionType: Coding, Equatable {
self = .historyScreenshot
case 12:
self = .messageAutoremoveTimeoutUpdated(decoder.decodeInt32ForKey("t"))
case 13:
self = .gameScore(gameId: decoder.decodeInt64ForKey("i"), score: decoder.decodeInt32ForKey("s"))
case 14:
var discardReason: PhoneCallDiscardReason?
if let value = (decoder.decodeInt32ForKey("dr") as Int32?) {
discardReason = PhoneCallDiscardReason(rawValue: value)
}
self = .phoneCall(callId: decoder.decodeInt64ForKey("i"), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d"))
default:
self = .unknown
}
@ -96,6 +113,23 @@ public enum TelegramMediaActionType: Coding, Equatable {
case let .messageAutoremoveTimeoutUpdated(timeout):
encoder.encodeInt32(12, forKey: "_rawValue")
encoder.encodeInt32(timeout, forKey: "t")
case let .gameScore(gameId, score):
encoder.encodeInt32(13, forKey: "_rawValue")
encoder.encodeInt64(gameId, forKey: "i")
encoder.encodeInt32(score, forKey: "s")
case let .phoneCall(callId, discardReason, duration):
encoder.encodeInt32(14, forKey: "_rawValue")
encoder.encodeInt64(callId, forKey: "i")
if let discardReason = discardReason {
encoder.encodeInt32(discardReason.rawValue, forKey: "dr")
} else {
encoder.encodeNil(forKey: "dr")
}
if let duration = duration {
encoder.encodeInt32(duration, forKey: "d")
} else {
encoder.encodeNil(forKey: "d")
}
}
}
@ -197,6 +231,18 @@ public func ==(lhs: TelegramMediaActionType, rhs: TelegramMediaActionType) -> Bo
} else {
return false
}
case let .gameScore(gameId, score):
if case .gameScore(gameId, score) = rhs {
return true
} else {
return false
}
case let .phoneCall(lhsCallId, lhsDiscardReason, lhsDuration):
if case let .phoneCall(rhsCallId, rhsDiscardReason, rhsDuration) = rhs, lhsCallId == rhsCallId && lhsDiscardReason == rhsDiscardReason && lhsDuration == rhsDuration {
return true
} else {
return false
}
}
return false
}
@ -255,7 +301,30 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .historyCleared)
case .messageActionPinMessage:
return TelegramMediaAction(action: .pinnedMessageUpdated)
default:
case let .messageActionGameScore(gameId, score):
return TelegramMediaAction(action: .gameScore(gameId: gameId, score: score))
case let .messageActionPhoneCall(_, callId, reason, duration):
var discardReason: PhoneCallDiscardReason?
if let reason = reason {
discardReason = PhoneCallDiscardReason(apiReason: reason)
}
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration))
case .messageActionEmpty:
return nil
}
}
extension PhoneCallDiscardReason {
init(apiReason: Api.PhoneCallDiscardReason) {
switch apiReason {
case .phoneCallDiscardReasonBusy:
self = .busy
case .phoneCallDiscardReasonDisconnect:
self = .disconnect
case .phoneCallDiscardReasonHangup:
self = .hangup
case .phoneCallDiscardReasonMissed:
self = .missed
}
}
}

View File

@ -0,0 +1,116 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
public final class TelegramMediaGame: Media {
public let gameId: Int64
public let accessHash: Int64
public let name: String
public let title: String
public let description: String
public let image: TelegramMediaImage?
public let file: TelegramMediaFile?
public var id: MediaId? {
return MediaId(namespace: Namespaces.Media.CloudGame, id: self.gameId)
}
public let peerIds: [PeerId] = []
init(gameId: Int64, accessHash: Int64, name: String, title: String, description: String, image: TelegramMediaImage?, file: TelegramMediaFile?) {
self.gameId = gameId
self.accessHash = accessHash
self.name = name
self.title = title
self.description = description
self.image = image
self.file = file
}
public init(decoder: Decoder) {
self.gameId = decoder.decodeInt64ForKey("i")
self.accessHash = decoder.decodeInt64ForKey("h")
self.name = decoder.decodeStringForKey("n")
self.title = decoder.decodeStringForKey("t")
self.description = decoder.decodeStringForKey("d")
self.image = decoder.decodeObjectForKey("p") as? TelegramMediaImage
self.file = decoder.decodeObjectForKey("f") as? TelegramMediaFile
}
public func encode(_ encoder: Encoder) {
encoder.encodeInt64(self.gameId, forKey: "i")
encoder.encodeInt64(self.accessHash, forKey: "h")
encoder.encodeString(self.name, forKey: "n")
encoder.encodeString(self.title, forKey: "t")
encoder.encodeString(self.description, forKey: "d")
if let image = self.image {
encoder.encodeObject(image, forKey: "p")
} else {
encoder.encodeNil(forKey: "p")
}
if let file = self.file {
encoder.encodeObject(file, forKey: "f")
} else {
encoder.encodeNil(forKey: "f")
}
}
public func isEqual(_ other: Media) -> Bool {
guard let other = other as? TelegramMediaGame else {
return false
}
if self.gameId != other.gameId {
return false
}
if self.accessHash != other.accessHash {
return false
}
if self.name != other.name {
return false
}
if self.title != other.title {
return false
}
if self.description != other.description {
return false
}
if let lhsImage = self.image, let rhsImage = other.image {
if !lhsImage.isEqual(rhsImage) {
return false
}
} else if (self.image != nil) != (other.image != nil) {
return false
}
if let lhsFile = self.file, let rhsFile = other.file {
if !lhsFile.isEqual(rhsFile) {
return false
}
} else if (self.file != nil) != (other.file != nil) {
return false
}
return true
}
}
extension TelegramMediaGame {
convenience init(apiGame: Api.Game) {
switch apiGame {
case let .game(_, id, accessHash, shortName, title, description, photo, document):
var file: TelegramMediaFile?
if let document = document {
file = telegramMediaFileFromApiDocument(document)
}
self.init(gameId: id, accessHash: accessHash, name: shortName, title: title, description: description, image: telegramMediaImageFromApiPhoto(photo), file: file)
}
}
}

View File

@ -0,0 +1,27 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
public final class TelegramMediaUnsupported: Media {
public let id: MediaId? = nil
public let peerIds: [PeerId] = []
init() {
}
public init(decoder: Decoder) {
}
public func encode(_ encoder: Encoder) {
}
public func isEqual(_ other: Media) -> Bool {
if other is TelegramMediaUnsupported {
return true
}
return false
}
}

View File

@ -1,12 +1,13 @@
import Foundation
enum UpdateGroup: CustomStringConvertible {
enum UpdateGroup {
case withPts(updates: [Api.Update], users: [Api.User], chats: [Api.Chat])
case withQts(updates: [Api.Update], users: [Api.User], chats: [Api.Chat])
case withSeq(updates: [Api.Update], seqRange: (Int32, Int32), date: Int32, users: [Api.User], chats: [Api.Chat])
case withDate(updates: [Api.Update], date: Int32, users: [Api.User], chats: [Api.Chat])
case reset
case updatePts(pts: Int32, ptsCount: Int32)
case updateChannelPts(channelId: Int32, pts: Int32, ptsCount: Int32)
var updates: [Api.Update] {
switch self {
@ -18,7 +19,7 @@ enum UpdateGroup: CustomStringConvertible {
return updates
case let .withSeq(updates, _, _, _, _):
return updates
case .reset, .updatePts:
case .reset, .updatePts, .updateChannelPts:
return []
}
}
@ -33,7 +34,7 @@ enum UpdateGroup: CustomStringConvertible {
return users
case let .withSeq(_, _, _, users, _):
return users
case .reset, .updatePts:
case .reset, .updatePts, .updateChannelPts:
return []
}
}
@ -48,71 +49,10 @@ enum UpdateGroup: CustomStringConvertible {
return chats
case let .withSeq(_, _, _, _, chats):
return chats
case .reset, .updatePts:
case .reset, .updatePts, .updateChannelPts:
return []
}
}
var description: String {
var string = ""
switch self {
case let .withPts(updates, _, _):
string += "withPts("
var first = true
for update in updates {
if first {
first = false
} else {
string += ", "
}
string += "\(update)"
}
string += ")"
case let .withQts(updates, _, _):
string += "withQts("
var first = true
for update in updates {
if first {
first = false
} else {
string += ", "
}
string += "\(update)"
}
string += ")"
case let .withSeq(updates, seqRange, date, _, _):
string += "withSeq(seq \(seqRange.0)..\(seqRange.1), date \(date), "
var first = true
for update in updates {
if first {
first = false
} else {
string += ", "
}
string += "\(update)"
}
string += ")"
case let .withDate(updates, date, _, _):
string += "withDate(date \(date), "
var first = true
for update in updates {
if first {
first = false
} else {
string += ", "
}
string += "\(update)"
}
string += ")"
case .reset:
string += "reset"
case .updatePts:
string += "updatePts"
}
return string
}
}
extension Api.Update {
@ -142,10 +82,10 @@ extension Api.Update {
var qtsRange: (Int32, Int32)? {
get {
switch self {
case let .updateNewEncryptedMessage(_, qts):
return (qts, 1)
case _:
return nil
case let .updateNewEncryptedMessage(_, qts):
return (qts, 1)
case _:
return nil
}
}
}