2024-03-15 15:24:55 +04:00

776 lines
52 KiB
Swift

import Foundation
import Postbox
import TelegramApi
import SwiftSignalKit
func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
return postbox.combinedView(keys: [.basicPeer(rawPeerId)])
|> mapToSignal { views -> Signal<Peer, NoError> in
guard let view = views.views[.basicPeer(rawPeerId)] as? BasicPeerView else {
return .complete()
}
guard let peer = view.peer else {
return .complete()
}
return .single(peer)
}
|> take(1)
|> mapToSignal { _ -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> Signal<Bool, NoError> in
guard let rawPeer = transaction.getPeer(rawPeerId) else {
return .single(false)
}
let peer: Peer
if let secretChat = rawPeer as? TelegramSecretChat {
guard let user = transaction.getPeer(secretChat.regularPeerId) else {
return .single(false)
}
peer = user
} else {
peer = rawPeer
}
let cachedData = transaction.getPeerCachedData(peerId: peer.id)
if let cachedData = cachedData as? CachedUserData {
if cachedData.peerStatusSettings != nil {
return .single(true)
}
} else if let cachedData = cachedData as? CachedGroupData {
if cachedData.peerStatusSettings != nil {
return .single(true)
}
} else if let cachedData = cachedData as? CachedChannelData {
if cachedData.peerStatusSettings != nil {
return .single(true)
}
} else if let cachedData = cachedData as? CachedSecretChatData {
if cachedData.peerStatusSettings != nil {
return .single(true)
}
}
if peer.id.namespace == Namespaces.Peer.SecretChat {
return postbox.transaction { transaction -> Bool in
var peerStatusSettings: PeerStatusSettings
if let peer = transaction.getPeer(peer.id), let associatedPeerId = peer.associatedPeerId, !transaction.isPeerContact(peerId: associatedPeerId) {
if let peer = peer as? TelegramSecretChat, case .creator = peer.role {
peerStatusSettings = PeerStatusSettings(flags: [], managingBot: nil)
} else {
peerStatusSettings = PeerStatusSettings(flags: [.canReport], managingBot: nil)
}
} else {
peerStatusSettings = PeerStatusSettings(flags: [], managingBot: nil)
}
transaction.updatePeerCachedData(peerIds: [peer.id], update: { peerId, current in
if let current = current as? CachedSecretChatData {
return current.withUpdatedPeerStatusSettings(peerStatusSettings)
} else {
return CachedSecretChatData(peerStatusSettings: peerStatusSettings)
}
})
return true
}
} else if let inputPeer = apiInputPeer(peer) {
return network.request(Api.functions.messages.getPeerSettings(peer: inputPeer))
|> retryRequest
|> mapToSignal { peerSettings -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> Bool in
let parsedPeers: AccumulatedPeers
let peerStatusSettings: PeerStatusSettings
switch peerSettings {
case let .peerSettings(settings, chats, users):
peerStatusSettings = PeerStatusSettings(apiSettings: settings)
parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
}
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
switch peer.id.namespace {
case Namespaces.Peer.CloudUser:
let previous: CachedUserData
if let current = current as? CachedUserData {
previous = current
} else {
previous = CachedUserData()
}
return previous.withUpdatedPeerStatusSettings(peerStatusSettings)
case Namespaces.Peer.CloudGroup:
let previous: CachedGroupData
if let current = current as? CachedGroupData {
previous = current
} else {
previous = CachedGroupData()
}
return previous.withUpdatedPeerStatusSettings(peerStatusSettings)
case Namespaces.Peer.CloudChannel:
let previous: CachedChannelData
if let current = current as? CachedChannelData {
previous = current
} else {
previous = CachedChannelData()
}
return previous.withUpdatedPeerStatusSettings(peerStatusSettings)
default:
break
}
return current
})
return true
}
}
} else {
return .single(false)
}
}
|> switchToLatest
}
}
func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
return postbox.combinedView(keys: [.basicPeer(rawPeerId)])
|> mapToSignal { views -> Signal<Bool, NoError> in
if accountPeerId == rawPeerId {
return .single(true)
}
guard let view = views.views[.basicPeer(rawPeerId)] as? BasicPeerView else {
return .complete()
}
guard let _ = view.peer else {
return .complete()
}
return .single(true)
}
|> take(1)
|> mapToSignal { _ -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> (Api.InputUser?, Peer?, PeerId) in
guard let rawPeer = transaction.getPeer(rawPeerId) else {
if rawPeerId == accountPeerId {
return (.inputUserSelf, transaction.getPeer(rawPeerId), rawPeerId)
} else {
return (nil, nil, rawPeerId)
}
}
let peer: Peer
if let secretChat = rawPeer as? TelegramSecretChat {
guard let user = transaction.getPeer(secretChat.regularPeerId) else {
return (nil, nil, rawPeerId)
}
peer = user
} else {
peer = rawPeer
}
if rawPeerId == accountPeerId {
return (.inputUserSelf, rawPeer, rawPeerId)
} else {
return (apiInputUser(peer), peer, peer.id)
}
}
|> mapToSignal { inputUser, maybePeer, peerId -> Signal<Bool, NoError> in
if let inputUser = inputUser {
let editableBotInfo: Signal<EditableBotInfo?, NoError>
if let user = maybePeer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.canEdit) {
let flags: Int32 = (1 << 0)
editableBotInfo = network.request(Api.functions.bots.getBotInfo(flags: flags, bot: inputUser, langCode: ""))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.bots.BotInfo?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<EditableBotInfo?, NoError> in
if let result = result {
switch result {
case let .botInfo(name, about, description):
return .single(EditableBotInfo(name: name, about: about, description: description))
}
} else {
return .single(nil)
}
}
} else {
editableBotInfo = .single(nil)
}
var additionalConnectedBots: Signal<Api.account.ConnectedBots?, NoError> = .single(nil)
if rawPeerId == accountPeerId {
additionalConnectedBots = network.request(Api.functions.account.getConnectedBots())
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.account.ConnectedBots?, NoError> in
return .single(nil)
}
}
return combineLatest(
network.request(Api.functions.users.getFullUser(id: inputUser))
|> retryRequest,
editableBotInfo,
additionalConnectedBots
)
|> mapToSignal { result, editableBotInfo, additionalConnectedBots -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> Bool in
switch result {
case let .userFull(fullUser, chats, users):
var accountUser: Api.User?
var parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
for user in users {
if user.peerId == accountPeerId {
accountUser = user
}
}
let _ = accountUser
var mappedConnectedBot: TelegramAccountConnectedBot?
if let additionalConnectedBots {
switch additionalConnectedBots {
case let .connectedBots(connectedBots, users):
parsedPeers = parsedPeers.union(with: AccumulatedPeers(transaction: transaction, chats: [], users: users))
if let apiBot = connectedBots.first {
switch apiBot {
case let .connectedBot(flags, botId, recipients):
mappedConnectedBot = TelegramAccountConnectedBot(
id: PeerId(botId),
recipients: TelegramBusinessRecipients(apiValue: recipients),
canReply: (flags & (1 << 0)) != 0
)
}
}
}
}
switch fullUser {
case let .userFull(_, _, _, _, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFullNotifySettings)])
}
transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in
let previous: CachedUserData
if let current = current as? CachedUserData {
previous = current
} else {
previous = CachedUserData()
}
switch fullUser {
case let .userFull(userFullFlags, _, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, _, _, userPremiumGiftOptions, userWallpaper, stories, businessWorkHours, businessLocation, greetingMessage, awayMessage):
let _ = stories
let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:))
let isBlocked = (userFullFlags & (1 << 0)) != 0
let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0
let videoCallsAvailable = (userFullFlags & (1 << 13)) != 0
let voiceMessagesAvailable = (userFullFlags & (1 << 20)) == 0
let readDatesPrivate = (userFullFlags & (1 << 30)) != 0
let premiumRequired = (userFullFlags & (1 << 29)) != 0
let translationsDisabled = (userFullFlags & (1 << 23)) != 0
var flags: CachedUserFlags = previous.flags
if premiumRequired {
flags.insert(.premiumRequired)
} else {
flags.remove(.premiumRequired)
}
if readDatesPrivate {
flags.insert(.readDatesPrivate)
} else {
flags.remove(.readDatesPrivate)
}
if translationsDisabled {
flags.insert(.translationHidden)
} else {
flags.remove(.translationHidden)
}
let callsPrivate = (userFullFlags & (1 << 5)) != 0
let canPinMessages = (userFullFlags & (1 << 7)) != 0
let pinnedMessageId = userFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
let peerStatusSettings = PeerStatusSettings(apiSettings: userFullSettings)
let hasScheduledMessages = (userFullFlags & 1 << 12) != 0
let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(userFullTtlPeriod))
let personalPhoto = personalPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let photo = profilePhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let fallbackPhoto = fallbackPhoto.flatMap { telegramMediaImageFromApiPhoto($0) }
let premiumGiftOptions: [CachedPremiumGiftOption]
if let userPremiumGiftOptions = userPremiumGiftOptions {
premiumGiftOptions = userPremiumGiftOptions.map { apiOption in
let option: CachedPremiumGiftOption
switch apiOption {
case let .premiumGiftOption(_, months, currency, amount, botUrl, storeProduct):
option = CachedPremiumGiftOption(months: months, currency: currency, amount: amount, botUrl: botUrl, storeProductId: storeProduct)
}
return option
}
} else {
premiumGiftOptions = []
}
let wallpaper = userWallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) }
var mappedBusinessHours: TelegramBusinessHours?
if let businessWorkHours {
mappedBusinessHours = TelegramBusinessHours(apiWorkingHours: businessWorkHours)
}
var mappedBusinessLocation: TelegramBusinessLocation?
if let businessLocation {
mappedBusinessLocation = TelegramBusinessLocation(apiLocation: businessLocation)
}
var mappedGreetingMessage: TelegramBusinessGreetingMessage?
if let greetingMessage {
mappedGreetingMessage = TelegramBusinessGreetingMessage(apiGreetingMessage: greetingMessage)
}
var mappedAwayMessage: TelegramBusinessAwayMessage?
if let awayMessage {
mappedAwayMessage = TelegramBusinessAwayMessage(apiAwayMessage: awayMessage)
}
return previous.withUpdatedAbout(userFullAbout)
.withUpdatedBotInfo(botInfo)
.withUpdatedEditableBotInfo(editableBotInfo)
.withUpdatedCommonGroupCount(userFullCommonChatsCount)
.withUpdatedIsBlocked(isBlocked)
.withUpdatedVoiceCallsAvailable(voiceCallsAvailable)
.withUpdatedVideoCallsAvailable(videoCallsAvailable)
.withUpdatedCallsPrivate(callsPrivate)
.withUpdatedCanPinMessages(canPinMessages)
.withUpdatedPeerStatusSettings(peerStatusSettings)
.withUpdatedPinnedMessageId(pinnedMessageId)
.withUpdatedHasScheduledMessages(hasScheduledMessages)
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
.withUpdatedPhoto(.known(photo))
.withUpdatedPersonalPhoto(.known(personalPhoto))
.withUpdatedFallbackPhoto(.known(fallbackPhoto))
.withUpdatedPremiumGiftOptions(premiumGiftOptions)
.withUpdatedVoiceMessagesAvailable(voiceMessagesAvailable)
.withUpdatedWallpaper(wallpaper)
.withUpdatedFlags(flags)
.withUpdatedBusinessHours(mappedBusinessHours)
.withUpdatedBusinessLocation(mappedBusinessLocation)
.withUpdatedGreetingMessage(mappedGreetingMessage)
.withUpdatedAwayMessage(mappedAwayMessage)
.withUpdatedConnectedBot(mappedConnectedBot)
}
})
}
return true
}
}
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
return network.request(Api.functions.messages.getFullChat(chatId: peerId.id._internalGetInt64Value()))
|> retryRequest
|> mapToSignal { result -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> Bool in
switch result {
case let .chatFull(fullChat, chats, users):
switch fullChat {
case let .chatFull(_, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _):
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .channelFull:
break
}
switch fullChat {
case let .chatFull(chatFullFlags, _, chatFullAbout, chatFullParticipants, chatFullChatPhoto, _, chatFullExportedInvite, chatFullBotInfo, chatFullPinnedMsgId, _, chatFullCall, chatTtlPeriod, chatFullGroupcallDefaultJoinAs, chatFullThemeEmoticon, chatFullRequestsPending, _, allowedReactions):
var botInfos: [CachedPeerBotInfo] = []
for botInfo in chatFullBotInfo ?? [] {
switch botInfo {
case let .botInfo(_, userId, _, _, _, _, _):
if let userId = userId {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
}
}
}
let participants = CachedGroupParticipants(apiParticipants: chatFullParticipants)
let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(chatTtlPeriod))
var invitedBy: PeerId?
if let participants = participants {
for participant in participants.participants {
if participant.peerId == accountPeerId {
if participant.invitedBy != accountPeerId {
invitedBy = participant.invitedBy
}
break
}
}
}
let photo: TelegramMediaImage? = chatFullChatPhoto.flatMap(telegramMediaImageFromApiPhoto)
let exportedInvitation = chatFullExportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) }
let pinnedMessageId = chatFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
var flags = CachedGroupFlags()
if (chatFullFlags & 1 << 7) != 0 {
flags.insert(.canChangeUsername)
}
var hasScheduledMessages = false
if (chatFullFlags & 1 << 8) != 0 {
hasScheduledMessages = true
}
let groupCallDefaultJoinAs = chatFullGroupcallDefaultJoinAs
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
let previous: CachedGroupData
if let current = current as? CachedGroupData {
previous = current
} else {
previous = CachedGroupData()
}
var updatedActiveCall: CachedChannelData.ActiveCall?
if let inputCall = chatFullCall {
switch inputCall {
case let .inputGroupCall(id, accessHash):
updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribedToScheduled: previous.activeCall?.subscribedToScheduled ?? false, isStream: previous.activeCall?.isStream)
}
}
let mappedAllowedReactions: PeerAllowedReactions
if let allowedReactions = allowedReactions {
switch allowedReactions {
case .chatReactionsAll:
mappedAllowedReactions = .all
case let .chatReactionsSome(reactions):
mappedAllowedReactions = .limited(reactions.compactMap(MessageReaction.Reaction.init(apiReaction:)))
case .chatReactionsNone:
mappedAllowedReactions = .empty
}
} else {
mappedAllowedReactions = .empty
}
return previous.withUpdatedParticipants(participants)
.withUpdatedExportedInvitation(exportedInvitation)
.withUpdatedBotInfos(botInfos)
.withUpdatedPinnedMessageId(pinnedMessageId)
.withUpdatedAbout(chatFullAbout)
.withUpdatedFlags(flags)
.withUpdatedHasScheduledMessages(hasScheduledMessages)
.withUpdatedInvitedBy(invitedBy)
.withUpdatedPhoto(photo)
.withUpdatedActiveCall(updatedActiveCall)
.withUpdatedCallJoinPeerId(groupCallDefaultJoinAs?.peerId)
.withUpdatedThemeEmoticon(chatFullThemeEmoticon)
.withUpdatedInviteRequestsPending(chatFullRequestsPending)
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
.withUpdatedAllowedReactions(.known(mappedAllowedReactions))
})
case .channelFull:
break
}
}
return true
}
}
} else if let inputChannel = maybePeer.flatMap(apiInputChannel) {
let fullChannelSignal = network.request(Api.functions.channels.getFullChannel(channel: inputChannel))
|> map(Optional.init)
|> `catch` { error -> Signal<Api.messages.ChatFull?, NoError> in
if error.errorDescription == "CHANNEL_PRIVATE" {
return .single(nil)
}
return .single(nil)
}
let participantSignal = network.request(Api.functions.channels.getParticipant(channel: inputChannel, participant: .inputPeerSelf))
|> map(Optional.init)
|> `catch` { error -> Signal<Api.channels.ChannelParticipant?, NoError> in
return .single(nil)
}
return combineLatest(fullChannelSignal, participantSignal)
|> mapToSignal { result, participantResult -> Signal<Bool, NoError> in
return postbox.transaction { transaction -> Bool in
if let result = result {
switch result {
case let .chatFull(fullChat, chats, users):
switch fullChat {
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .chatFull:
break
}
switch fullChat {
case let .channelFull(flags, flags2, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, _, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, _, inputCall, ttl, pendingSuggestions, groupcallDefaultJoinAs, themeEmoticon, requestsPending, _, defaultSendAs, allowedReactions, _, wallpaper, appliedBoosts, boostsUnrestrict, emojiSet):
var channelFlags = CachedChannelFlags()
if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants)
}
if (flags & (1 << 6)) != 0 {
channelFlags.insert(.canChangeUsername)
}
if (flags & (1 << 10)) == 0 {
channelFlags.insert(.preHistoryEnabled)
}
if (flags & (1 << 20)) != 0 {
channelFlags.insert(.canViewStats)
}
if (flags & (1 << 7)) != 0 {
channelFlags.insert(.canSetStickerSet)
}
if (flags & (1 << 16)) != 0 {
channelFlags.insert(.canChangePeerGeoLocation)
}
if (flags2 & (1 << 0)) != 0 {
channelFlags.insert(.canDeleteHistory)
}
if (flags2 & Int32(1 << 1)) != 0 {
channelFlags.insert(.antiSpamEnabled)
}
if (flags2 & Int32(1 << 3)) != 0 {
channelFlags.insert(.translationHidden)
}
let sendAsPeerId = defaultSendAs?.peerId
let linkedDiscussionPeerId: PeerId?
if let linkedChatId = linkedChatId, linkedChatId != 0 {
linkedDiscussionPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(Int64(linkedChatId)))
} else {
linkedDiscussionPeerId = nil
}
let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(ttl))
let peerGeoLocation: PeerGeoLocation?
if let location = location {
peerGeoLocation = PeerGeoLocation(apiLocation: location)
} else {
peerGeoLocation = nil
}
var botInfos: [CachedPeerBotInfo] = []
for botInfo in apiBotInfos {
switch botInfo {
case let .botInfo(_, userId, _, _, _, _, _):
if let userId = userId {
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
let parsedBotInfo = BotInfo(apiBotInfo: botInfo)
botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo))
}
}
}
var pinnedMessageId: MessageId?
if let pinnedMsgId = pinnedMsgId {
pinnedMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: pinnedMsgId)
}
var minAvailableMessageId: MessageId?
if let minAvailableMsgId = minAvailableMsgId {
minAvailableMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minAvailableMsgId)
if let pinnedMsgId = pinnedMsgId, pinnedMsgId < minAvailableMsgId {
pinnedMessageId = nil
}
}
var migrationReference: ChannelMigrationReference?
if let migratedFromChatId = migratedFromChatId, let migratedFromMaxId = migratedFromMaxId {
migrationReference = ChannelMigrationReference(maxMessageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(migratedFromChatId)), namespace: Namespaces.Message.Cloud, id: migratedFromMaxId))
}
var parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
if let participantResult = participantResult {
switch participantResult {
case let .channelParticipant(_, chats, users):
parsedPeers = parsedPeers.union(with: AccumulatedPeers(transaction: transaction, chats: chats, users: users))
}
}
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
let stickerPack: StickerPackCollectionInfo? = stickerSet.flatMap { apiSet -> StickerPackCollectionInfo in
let namespace: ItemCollectionId.Namespace
switch apiSet {
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _, _):
if (flags & (1 << 3)) != 0 {
namespace = Namespaces.ItemCollection.CloudMaskPacks
} else if (flags & (1 << 7)) != 0 {
namespace = Namespaces.ItemCollection.CloudEmojiPacks
} else {
namespace = Namespaces.ItemCollection.CloudStickerPacks
}
}
return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace)
}
var hasScheduledMessages = false
if (flags & (1 << 19)) != 0 {
hasScheduledMessages = true
}
var invitedBy: PeerId?
var invitedOn: Int32?
if let participantResult = participantResult {
switch participantResult {
case let .channelParticipant(participant, _, _):
switch participant {
case let .channelParticipantSelf(flags, _, inviterId, invitedDate):
invitedBy = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(inviterId))
if (flags & (1 << 0)) != 0 {
invitedOn = invitedDate
}
default:
break
}
}
}
let photo = telegramMediaImageFromApiPhoto(chatPhoto)
let emojiPack: StickerPackCollectionInfo? = emojiSet.flatMap { apiSet -> StickerPackCollectionInfo in
let namespace: ItemCollectionId.Namespace
switch apiSet {
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _, _):
if (flags & (1 << 3)) != 0 {
namespace = Namespaces.ItemCollection.CloudMaskPacks
} else if (flags & (1 << 7)) != 0 {
namespace = Namespaces.ItemCollection.CloudEmojiPacks
} else {
namespace = Namespaces.ItemCollection.CloudStickerPacks
}
}
return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace)
}
var minAvailableMessageIdUpdated = false
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in
var previous: CachedChannelData
if let current = current as? CachedChannelData {
previous = current
} else {
previous = CachedChannelData()
}
previous = previous.withUpdatedIsNotAccessible(false)
minAvailableMessageIdUpdated = previous.minAvailableMessageId != minAvailableMessageId
var updatedActiveCall: CachedChannelData.ActiveCall?
if let inputCall = inputCall {
switch inputCall {
case let .inputGroupCall(id, accessHash):
updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribedToScheduled: previous.activeCall?.subscribedToScheduled ?? false, isStream: previous.activeCall?.isStream)
}
}
let mappedAllowedReactions: PeerAllowedReactions
if let allowedReactions = allowedReactions {
switch allowedReactions {
case .chatReactionsAll:
mappedAllowedReactions = .all
case let .chatReactionsSome(reactions):
mappedAllowedReactions = .limited(reactions.compactMap(MessageReaction.Reaction.init(apiReaction:)))
case .chatReactionsNone:
mappedAllowedReactions = .empty
}
} else {
mappedAllowedReactions = .empty
}
let membersHidden = (flags2 & (1 << 2)) != 0
let forumViewAsMessages = (flags2 & (1 << 6)) != 0
let wallpaper = wallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) }
return previous.withUpdatedFlags(channelFlags)
.withUpdatedAbout(about)
.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount))
.withUpdatedExportedInvitation(apiExportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) })
.withUpdatedBotInfos(botInfos)
.withUpdatedPinnedMessageId(pinnedMessageId)
.withUpdatedStickerPack(stickerPack)
.withUpdatedMinAvailableMessageId(minAvailableMessageId)
.withUpdatedMigrationReference(migrationReference)
.withUpdatedLinkedDiscussionPeerId(.known(linkedDiscussionPeerId))
.withUpdatedPeerGeoLocation(peerGeoLocation)
.withUpdatedSlowModeTimeout(slowmodeSeconds)
.withUpdatedSlowModeValidUntilTimestamp(slowmodeNextSendDate)
.withUpdatedHasScheduledMessages(hasScheduledMessages)
.withUpdatedStatsDatacenterId(statsDc ?? 0)
.withUpdatedInvitedBy(invitedBy)
.withUpdatedInvitedOn(invitedOn)
.withUpdatedPhoto(photo)
.withUpdatedActiveCall(updatedActiveCall)
.withUpdatedCallJoinPeerId(groupcallDefaultJoinAs?.peerId)
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
.withUpdatedPendingSuggestions(pendingSuggestions ?? [])
.withUpdatedThemeEmoticon(themeEmoticon)
.withUpdatedInviteRequestsPending(requestsPending)
.withUpdatedSendAsPeerId(sendAsPeerId)
.withUpdatedAllowedReactions(.known(mappedAllowedReactions))
.withUpdatedMembersHidden(.known(PeerMembersHidden(value: membersHidden)))
.withUpdatedViewForumAsMessages(.known(forumViewAsMessages))
.withUpdatedWallpaper(wallpaper)
.withUpdatedBoostsToUnrestrict(boostsUnrestrict)
.withUpdatedAppliedBoosts(appliedBoosts)
.withUpdatedEmojiPack(emojiPack)
})
if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated {
var resourceIds: [MediaResourceId] = []
transaction.deleteMessagesInRange(peerId: peerId, namespace: minAvailableMessageId.namespace, minId: 1, maxId: minAvailableMessageId.id, forEachMedia: { media in
addMessageMediaResourceIdsToRemove(media: media, resourceIds: &resourceIds)
})
if !resourceIds.isEmpty {
let _ = postbox.mediaBox.removeCachedResources(Array(Set(resourceIds))).start()
}
}
case .chatFull:
break
}
}
} else {
transaction.updatePeerCachedData(peerIds: [peerId], update: { _, _ in
var updated = CachedChannelData()
updated = updated.withUpdatedIsNotAccessible(true)
return updated
})
}
return true
}
}
} else {
return .single(false)
}
}
}
}
extension CachedPeerAutoremoveTimeout.Value {
init?(_ apiValue: Int32?) {
if let value = apiValue {
self.init(peerValue: value)
} else {
return nil
}
}
}