Merge branch 'master' of gitlab.com:peter-iakovlev/TelegramCore

This commit is contained in:
Ilya Laktyushin 2019-01-10 23:17:32 +04:00
commit d708bd4e2b
9 changed files with 337 additions and 212 deletions

View File

@ -222,8 +222,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) } dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) }
dict[-471670279] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) } dict[-471670279] = { return Api.ChannelParticipant.parse_channelParticipantCreator($0) }
dict[1674301556] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
dict[470789295] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) } dict[470789295] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) }
dict[1571450403] = { return Api.ChannelParticipant.parse_channelParticipantAdmin($0) }
dict[471043349] = { return Api.contacts.Blocked.parse_blocked($0) } dict[471043349] = { return Api.contacts.Blocked.parse_blocked($0) }
dict[-1878523231] = { return Api.contacts.Blocked.parse_blockedSlice($0) } dict[-1878523231] = { return Api.contacts.Blocked.parse_blockedSlice($0) }
dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) } dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) }

View File

@ -5489,8 +5489,8 @@ extension Api {
case channelParticipant(userId: Int32, date: Int32) case channelParticipant(userId: Int32, date: Int32)
case channelParticipantSelf(userId: Int32, inviterId: Int32, date: Int32) case channelParticipantSelf(userId: Int32, inviterId: Int32, date: Int32)
case channelParticipantCreator(userId: Int32) case channelParticipantCreator(userId: Int32)
case channelParticipantAdmin(flags: Int32, userId: Int32, inviterId: Int32, promotedBy: Int32, date: Int32, adminRights: Api.ChatAdminRights)
case channelParticipantBanned(flags: Int32, userId: Int32, kickedBy: Int32, date: Int32, bannedRights: Api.ChatBannedRights) case channelParticipantBanned(flags: Int32, userId: Int32, kickedBy: Int32, date: Int32, bannedRights: Api.ChatBannedRights)
case channelParticipantAdmin(flags: Int32, userId: Int32, inviterId: Int32?, promotedBy: Int32, date: Int32, adminRights: Api.ChatAdminRights)
func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -5515,17 +5515,6 @@ extension Api {
} }
serializeInt32(userId, buffer: buffer, boxed: false) serializeInt32(userId, buffer: buffer, boxed: false)
break break
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights):
if boxed {
buffer.appendInt32(1674301556)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(userId, buffer: buffer, boxed: false)
serializeInt32(inviterId, buffer: buffer, boxed: false)
serializeInt32(promotedBy, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
adminRights.serialize(buffer, true)
break
case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights):
if boxed { if boxed {
buffer.appendInt32(470789295) buffer.appendInt32(470789295)
@ -5536,6 +5525,17 @@ extension Api {
serializeInt32(date, buffer: buffer, boxed: false) serializeInt32(date, buffer: buffer, boxed: false)
bannedRights.serialize(buffer, true) bannedRights.serialize(buffer, true)
break break
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights):
if boxed {
buffer.appendInt32(1571450403)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(userId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(inviterId!, buffer: buffer, boxed: false)}
serializeInt32(promotedBy, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
adminRights.serialize(buffer, true)
break
} }
} }
@ -5547,10 +5547,10 @@ extension Api {
return ("channelParticipantSelf", [("userId", userId), ("inviterId", inviterId), ("date", date)]) return ("channelParticipantSelf", [("userId", userId), ("inviterId", inviterId), ("date", date)])
case .channelParticipantCreator(let userId): case .channelParticipantCreator(let userId):
return ("channelParticipantCreator", [("userId", userId)]) return ("channelParticipantCreator", [("userId", userId)])
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights):
return ("channelParticipantAdmin", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("promotedBy", promotedBy), ("date", date), ("adminRights", adminRights)])
case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights): case .channelParticipantBanned(let flags, let userId, let kickedBy, let date, let bannedRights):
return ("channelParticipantBanned", [("flags", flags), ("userId", userId), ("kickedBy", kickedBy), ("date", date), ("bannedRights", bannedRights)]) return ("channelParticipantBanned", [("flags", flags), ("userId", userId), ("kickedBy", kickedBy), ("date", date), ("bannedRights", bannedRights)])
case .channelParticipantAdmin(let flags, let userId, let inviterId, let promotedBy, let date, let adminRights):
return ("channelParticipantAdmin", [("flags", flags), ("userId", userId), ("inviterId", inviterId), ("promotedBy", promotedBy), ("date", date), ("adminRights", adminRights)])
} }
} }
@ -5596,34 +5596,6 @@ extension Api {
return nil return nil
} }
} }
static func parse_channelParticipantAdmin(_ reader: BufferReader) -> ChannelParticipant? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Api.ChatAdminRights?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.ChannelParticipant.channelParticipantAdmin(flags: _1!, userId: _2!, inviterId: _3!, promotedBy: _4!, date: _5!, adminRights: _6!)
}
else {
return nil
}
}
static func parse_channelParticipantBanned(_ reader: BufferReader) -> ChannelParticipant? { static func parse_channelParticipantBanned(_ reader: BufferReader) -> ChannelParticipant? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
@ -5649,6 +5621,34 @@ extension Api {
return nil return nil
} }
} }
static func parse_channelParticipantAdmin(_ reader: BufferReader) -> ChannelParticipant? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_3 = reader.readInt32() }
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Api.ChatAdminRights?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.ChatAdminRights
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.ChannelParticipant.channelParticipantAdmin(flags: _1!, userId: _2!, inviterId: _3, promotedBy: _4!, date: _5!, adminRights: _6!)
}
else {
return nil
}
}
} }
enum InputDialogPeer: TypeConstructorDescription { enum InputDialogPeer: TypeConstructorDescription {

View File

@ -1547,20 +1547,6 @@ extension Api {
}) })
} }
static func exportChatInvite(chatId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(2106086025)
serializeInt32(chatId, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("chatId", chatId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
return result
})
}
static func checkChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ChatInvite>) { static func checkChatInvite(hash: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ChatInvite>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1051570619) buffer.appendInt32(1051570619)
@ -2796,6 +2782,20 @@ extension Api {
return result return result
}) })
} }
static func exportChatInvite(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(234312524)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.exportChatInvite", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
return result
})
}
} }
struct channels { struct channels {
static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
@ -3053,20 +3053,6 @@ extension Api {
}) })
} }
static func exportInvite(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.ExportedChatInvite>) {
let buffer = Buffer()
buffer.appendInt32(-950663035)
channel.serialize(buffer, true)
return (FunctionDescription(name: "channels.exportInvite", parameters: [("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.ExportedChatInvite? in
let reader = BufferReader(buffer)
var result: Api.ExportedChatInvite?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.ExportedChatInvite
}
return result
})
}
static func deleteChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) { static func deleteChannel(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(-1072619549) buffer.appendInt32(-1072619549)

View File

@ -36,8 +36,8 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
var role: TelegramGroupRole = .member var role: TelegramGroupRole = .member
if (flags & (1 << 0)) != 0 { if (flags & (1 << 0)) != 0 {
role = .creator role = .creator
} else if adminRights != nil { } else if let adminRights = adminRights {
//role = .admin role = .admin(TelegramChatAdminRights(apiAdminRights: adminRights))
} }
if (flags & (1 << 5)) != 0 { if (flags & (1 << 5)) != 0 {
groupFlags.insert(.deactivated) groupFlags.insert(.deactivated)

View File

@ -504,7 +504,7 @@ final class TelegramCloudMediaResourceFetchInfo: MediaResourceFetchInfo {
} }
} }
public func fetchedMediaResource(postbox: Postbox, reference: MediaResourceReference, range: (Range<Int>, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal<FetchResourceSourceType, NoError> { public func fetchedMediaResource(postbox: Postbox, reference: MediaResourceReference, range: (Range<Int>, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal<FetchResourceSourceType, FetchResourceError> {
if let (range, priority) = range { if let (range, priority) = range {
return postbox.mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground))) return postbox.mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground)))
|> map { _ in .local } |> map { _ in .local }

View File

@ -11,45 +11,45 @@ import Foundation
public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal<Void, NoError> { public func ensuredExistingPeerExportedInvitation(account: Account, peerId: PeerId, revokeExisted: Bool = false) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Signal<Void, NoError> in return account.postbox.transaction { transaction -> Signal<Void, NoError> in
if let peer = transaction.getPeer(peerId) { if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { if let _ = peer as? TelegramChannel {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted { if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, cachedData.exportedInvitation != nil && !revokeExisted {
return .complete() return .complete()
} else { } else {
return account.network.request(Api.functions.channels.exportInvite(channel: inputChannel)) return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<Void, NoError> in |> mapToSignal { result -> Signal<Void, NoError> in
return account.postbox.transaction { transaction -> Void in return account.postbox.transaction { transaction -> Void in
if let invitation = ExportedInvitation(apiExportedInvite: result) { if let invitation = ExportedInvitation(apiExportedInvite: result) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData { if let current = current as? CachedChannelData {
return current.withUpdatedExportedInvitation(invitation) return current.withUpdatedExportedInvitation(invitation)
} else { } else {
return CachedChannelData().withUpdatedExportedInvitation(invitation) return CachedChannelData().withUpdatedExportedInvitation(invitation)
} }
}) })
}
} }
} }
}
} }
} else if let group = peer as? TelegramGroup { } else if let _ = peer as? TelegramGroup {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted { if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedGroupData, cachedData.exportedInvitation != nil && !revokeExisted {
return .complete() return .complete()
} else { } else {
return account.network.request(Api.functions.messages.exportChatInvite(chatId: group.id.id)) return account.network.request(Api.functions.messages.exportChatInvite(peer: inputPeer))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<Void, NoError> in |> mapToSignal { result -> Signal<Void, NoError> in
return account.postbox.transaction { transaction -> Void in return account.postbox.transaction { transaction -> Void in
if let invitation = ExportedInvitation(apiExportedInvite: result) { if let invitation = ExportedInvitation(apiExportedInvite: result) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedGroupData { if let current = current as? CachedGroupData {
return current.withUpdatedExportedInvitation(invitation) return current.withUpdatedExportedInvitation(invitation)
} else { } else {
return current return current
} }
}) })
}
} }
}
} }
} }
} else { } else {

View File

@ -391,7 +391,7 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload
let dataSignal: Signal<MultipartUploadData, NoError> let dataSignal: Signal<MultipartUploadData, NoError>
let headerSize: Int32 let headerSize: Int32
let fetchedResource: Signal<Void, NoError> let fetchedResource: Signal<Void, FetchResourceError>
switch source { switch source {
case let .resource(resource): case let .resource(resource):
dataSignal = postbox.mediaBox.resourceData(resource.resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) } dataSignal = postbox.mediaBox.resourceData(resource.resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) }
@ -454,7 +454,9 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload
manager.start() manager.start()
let fetchedResourceDisposable = fetchedResource.start() let fetchedResourceDisposable = fetchedResource.start(error: { _ in
subscriber.putError(.generic)
})
return ActionDisposable { return ActionDisposable {
manager.cancel() manager.cancel()

View File

@ -189,7 +189,9 @@ private func maybePredownloadedImageResource(postbox: Postbox, peerId: PeerId, r
} }
} }
}) })
let fetched = postbox.mediaBox.fetchedResource(resource, parameters: nil).start() let fetched = postbox.mediaBox.fetchedResource(resource, parameters: nil).start(error: { _ in
subscriber.putError(.generic)
})
return ActionDisposable { return ActionDisposable {
data.dispose() data.dispose()
@ -609,7 +611,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
var thumbnailFile: Api.InputFile? var thumbnailFile: Api.InputFile?
if case let .file(file) = thumbnail { if case let .file(file) = thumbnail {
//thumbnailFile = file thumbnailFile = file
} }
if let _ = thumbnailFile { if let _ = thumbnailFile {

View File

@ -15,18 +15,173 @@ public enum SearchMessagesLocation: Equatable {
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?) case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?)
} }
public func searchMessages(account: Account, location: SearchMessagesLocation, query: String, lowerBound: MessageIndex? = nil, limit: Int32 = 100) -> Signal<([Message], [PeerId : CombinedPeerReadState], Int32), NoError> { private struct SearchMessagesPeerState: Equatable {
let remoteSearchResult: Signal<Api.messages.Messages?, NoError> let messages: [Message]
let readStates: [PeerId: CombinedPeerReadState]
let totalCount: Int32
let completed: Bool
static func ==(lhs: SearchMessagesPeerState, rhs: SearchMessagesPeerState) -> Bool {
if lhs.totalCount != rhs.totalCount {
return false
}
if lhs.completed != rhs.completed {
return false
}
if lhs.messages.count != rhs.messages.count {
return false
}
for i in 0 ..< lhs.messages.count {
if lhs.messages[i].id != rhs.messages[i].id {
return false
}
}
return true
}
}
public struct SearchMessagesResult {
public let messages: [Message]
public let readStates: [PeerId: CombinedPeerReadState]
public let totalCount: Int32
public let completed: Bool
}
public struct SearchMessagesState: Equatable {
fileprivate let main: SearchMessagesPeerState
fileprivate let additional: SearchMessagesPeerState?
}
private func mergedState(transaction: Transaction, state: SearchMessagesPeerState?, result: Api.messages.Messages?) -> SearchMessagesPeerState? {
guard let result = result else {
return state
}
let messages: [Api.Message]
let chats: [Api.Chat]
let users: [Api.User]
let totalCount: Int32
switch result {
case let .channelMessages(_, _, count, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = count
case let .messages(apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = Int32(messages.count)
case let .messagesSlice(_, count, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = count
case .messagesNotModified:
messages = []
chats = []
users = []
totalCount = 0
}
var peers: [PeerId: Peer] = [:]
for user in users {
if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
peers[user.id] = user
}
}
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
var peerIdsSet: Set<PeerId> = Set()
var readStates: [PeerId: CombinedPeerReadState] = [:]
var renderedMessages: [Message] = []
for message in messages {
if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) {
renderedMessages.append(renderedMessage)
peerIdsSet.insert(message.id.peerId)
}
}
for peerId in peerIdsSet {
if let readState = transaction.getCombinedPeerReadState(peerId) {
readStates[peerId] = readState
}
}
renderedMessages.sort(by: { lhs, rhs in
return MessageIndex(lhs) > MessageIndex(rhs)
})
let completed = renderedMessages.isEmpty
if let previous = state {
var currentIds = Set<MessageId>()
var mergedMessages: [Message] = []
for message in previous.messages {
if currentIds.contains(message.id) {
continue
}
currentIds.insert(message.id)
mergedMessages.append(message)
}
for message in renderedMessages {
if currentIds.contains(message.id) {
continue
}
currentIds.insert(message.id)
mergedMessages.append(message)
}
mergedMessages.sort(by: { lhs, rhs in
return MessageIndex(lhs) > MessageIndex(rhs)
})
return SearchMessagesPeerState(messages: mergedMessages, readStates: readStates, totalCount: completed ? Int32(mergedMessages.count) : totalCount, completed: completed)
} else {
return SearchMessagesPeerState(messages: renderedMessages, readStates: readStates, totalCount: completed ? Int32(renderedMessages.count) : totalCount, completed: completed)
}
}
private func mergedResult(_ state: SearchMessagesState) -> SearchMessagesResult {
var messages: [Message] = state.main.messages
if let additional = state.additional {
if state.main.completed {
messages.append(contentsOf: additional.messages)
} else if let lastMessage = state.main.messages.last {
let earliestIndex = MessageIndex(lastMessage)
messages.append(contentsOf: additional.messages.filter({ MessageIndex($0) > earliestIndex }))
}
}
messages.sort(by: { lhs, rhs in
return MessageIndex(lhs) > MessageIndex(rhs)
})
var readStates: [PeerId: CombinedPeerReadState] = [:]
for message in messages {
let readState = state.main.readStates[message.id.peerId] ?? state.additional?.readStates[message.id.peerId]
if let readState = readState {
readStates[message.id.peerId] = readState
}
}
return SearchMessagesResult(messages: messages, readStates: readStates, totalCount: state.main.totalCount + (state.additional?.totalCount ?? 0), completed: state.main.completed && (state.additional?.completed ?? true))
}
public func searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
let remoteSearchResult: Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError>
switch location { switch location {
case let .peer(peerId, fromId, tags): case let .peer(peerId, fromId, tags):
if peerId.namespace == Namespaces.Peer.SecretChat { if peerId.namespace == Namespaces.Peer.SecretChat {
return account.postbox.transaction { transaction -> ([Message], [PeerId : CombinedPeerReadState], Int32) in return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
var readStates: [PeerId : CombinedPeerReadState] = [:] var readStates: [PeerId: CombinedPeerReadState] = [:]
if let readState = transaction.getCombinedPeerReadState(peerId) { if let readState = transaction.getCombinedPeerReadState(peerId) {
readStates[peerId] = readState readStates[peerId] = readState
} }
let result = transaction.searchMessages(peerId: peerId, query: query, tags: tags) let result = transaction.searchMessages(peerId: peerId, query: query, tags: tags)
return (result, readStates, Int32(result.count)) return (SearchMessagesResult(messages: result, readStates: readStates, totalCount: Int32(result.count), completed: true), SearchMessagesState(main: SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true), additional: nil))
} }
} }
@ -45,134 +200,114 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
} else { } else {
filter = .inputMessagesFilterEmpty filter = .inputMessagesFilterEmpty
} }
remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?)? in
remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer?, from: Peer?) in guard let peer = transaction.getPeer(peerId) else {
if let fromId = fromId { return nil
return (peer: transaction.getPeer(peerId), from: transaction.getPeer(fromId))
} }
return (peer: transaction.getPeer(peerId), from: nil) var additionalPeer: Peer?
if let _ = peer as? TelegramChannel, let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
additionalPeer = transaction.getPeer(migrationReference.maxMessageId.peerId)
}
if let fromId = fromId {
return (peer: peer, additionalPeer: additionalPeer, from: transaction.getPeer(fromId))
}
return (peer: peer, additionalPeer: additionalPeer, from: nil)
} }
|> mapToSignal { values -> Signal<Api.messages.Messages?, NoError> in |> mapToSignal { values -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in
if let peer = values.peer, let inputPeer = apiInputPeer(peer) { guard let values = values else {
var fromInputUser: Api.InputUser? = nil return .single((nil, nil))
var flags: Int32 = 0 }
if let from = values.from { let peer = values.peer
fromInputUser = apiInputUser(from) guard let inputPeer = apiInputPeer(peer) else {
if let _ = fromInputUser { return .single((nil, nil))
flags |= (1 << 0) }
} var fromInputUser: Api.InputUser? = nil
var flags: Int32 = 0
if let from = values.from {
fromInputUser = apiInputUser(from)
if let _ = fromInputUser {
flags |= (1 << 0)
} }
return account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0)) }
let peerMessages: Signal<Api.messages.Messages?, NoError>
if let completed = state?.main.completed, completed {
peerMessages = .single(nil)
} else {
let lowerBound = state?.main.messages.last.flatMap(MessageIndex.init)
peerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in |> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in
return .single(nil) return .single(nil)
} }
} else {
return .never()
} }
let additionalPeerMessages: Signal<Api.messages.Messages?, NoError>
if let inputPeer = values.additionalPeer.flatMap(apiInputPeer) {
let mainCompleted = state?.main.completed ?? false
let hasAdditional = state?.additional != nil
if let completed = state?.additional?.completed, completed {
additionalPeerMessages = .single(nil)
} else if mainCompleted || !hasAdditional {
let lowerBound = state?.additional?.messages.last.flatMap(MessageIndex.init)
additionalPeerMessages = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in
return .single(nil)
}
} else {
additionalPeerMessages = .single(nil)
}
} else {
additionalPeerMessages = .single(nil)
}
return combineLatest(peerMessages, additionalPeerMessages)
} }
case let .group(groupId): case let .group(groupId):
/*feed*/ /*feed*/
remoteSearchResult = .single(nil) remoteSearchResult = .single((nil, nil))
/*remoteSearchResult = account.network.request(Api.functions.channels.searchFeed(feedId: groupId.rawValue, q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64), automaticFloodWait: false) /*remoteSearchResult = account.network.request(Api.functions.channels.searchFeed(feedId: groupId.rawValue, q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64), automaticFloodWait: false)
|> mapError { _ in } |> map(Optional.init)*/ |> mapError { _ in } |> map(Optional.init)*/
case .general: case .general:
remoteSearchResult = account.postbox.transaction { transaction -> Api.InputPeer in remoteSearchResult = account.postbox.transaction { transaction -> (MessageIndex?, Api.InputPeer) in
var lowerBound: MessageIndex?
if let state = state, let message = state.main.messages.last {
lowerBound = MessageIndex(message)
}
if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) { if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) {
return inputPeer return (lowerBound, inputPeer)
} else { } else {
return .inputPeerEmpty return (lowerBound, .inputPeerEmpty)
} }
} }
|> mapToSignal { inputPeer in |> mapToSignal { (lowerBound, inputPeer) in
account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: lowerBound?.timestamp ?? 0, offsetPeer: inputPeer, offsetId: lowerBound?.id.id ?? 0, limit: limit), automaticFloodWait: false) account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: lowerBound?.timestamp ?? 0, offsetPeer: inputPeer, offsetId: lowerBound?.id.id ?? 0, limit: limit), automaticFloodWait: false)
|> map(Optional.init) |> map { result -> (Api.messages.Messages?, Api.messages.Messages?) in
|> `catch` { _ -> Signal<Api.messages.Messages?, NoError> in return (result, nil)
return .single(nil) }
|> `catch` { _ -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in
return .single((nil, nil))
} }
} }
} }
let processedSearchResult = remoteSearchResult return remoteSearchResult
|> mapToSignal { result -> Signal<([Message], [PeerId: CombinedPeerReadState], Int32), NoError> in |> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in
guard let result = result else { return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
return .single(([], [:], 0)) var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult)
} if state?.additional == nil, case .general = location {
//assert(false)
let messages: [Api.Message]
let chats: [Api.Chat]
let users: [Api.User]
let totalCount: Int32
switch result {
case let .channelMessages(_, _, count, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = count
case let .messages(apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = Int32(messages.count)
case let .messagesSlice(_, count, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
totalCount = count
case .messagesNotModified:
messages = []
chats = []
users = []
totalCount = 0
}
return account.postbox.transaction { transaction -> ([Message], [PeerId : CombinedPeerReadState], Int32) in
var peers: [PeerId: Peer] = [:]
for user in users {
if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
peers[user.id] = user
}
}
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
var peerIdsSet: Set<PeerId> = Set()
var readStates:[PeerId : CombinedPeerReadState] = [:]
var renderedMessages: [Message] = []
for message in messages {
if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) {
renderedMessages.append(renderedMessage)
peerIdsSet.insert(message.id.peerId)
}
}
for peerId in peerIdsSet {
if let readState = transaction.getCombinedPeerReadState(peerId) {
readStates[peerId] = readState
}
}
if case .general = location {
let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: nil) let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: nil)
renderedMessages.append(contentsOf: secretMessages) var readStates: [PeerId: CombinedPeerReadState] = [:]
for message in secretMessages {
if let readState = transaction.getCombinedPeerReadState(message.id.peerId) {
readStates[message.id.peerId] = readState
}
}
additional = SearchMessagesPeerState(messages: secretMessages, readStates: readStates, totalCount: Int32(secretMessages.count), completed: true)
} }
renderedMessages.sort(by: { lhs, rhs in let updatedState = SearchMessagesState(main: mergedState(transaction: transaction, state: state?.main, result: result) ?? SearchMessagesPeerState(messages: [], readStates: [:], totalCount: 0, completed: true), additional: additional)
return MessageIndex(lhs) > MessageIndex(rhs) return (mergedResult(updatedState), updatedState)
})
return (renderedMessages, readStates, totalCount)
} }
} }
return processedSearchResult
} }
public func downloadMessage(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<Message?, NoError> { public func downloadMessage(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<Message?, NoError> {