no message

This commit is contained in:
Peter
2017-03-30 17:54:38 +03:00
parent 71ff550bcc
commit 7cf44fbcbd
5 changed files with 133 additions and 61 deletions

View File

@@ -11,7 +11,7 @@ import Foundation
private func pendingWebpages(entries: [MessageHistoryEntry]) -> Set<MessageId> {
var messageIds = Set<MessageId>()
for case let .MessageEntry(message, _, _) in entries {
for case let .MessageEntry(message, _, _, _) in entries {
for media in message.media {
if let media = media as? TelegramMediaWebpage {
if case .Pending = media.content {
@@ -422,27 +422,27 @@ public final class AccountViewTracker {
}
}
public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundUnreadMessageHistoryViewForPeerId(peerId, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
let signal = account.postbox.aroundUnreadMessageHistoryViewForPeerId(peerId, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
return wrappedMessageHistorySignal(peerId: peerId, signal: signal)
} else {
return .never()
}
}
public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundIdMessageHistoryViewForPeerId(peerId, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
let signal = account.postbox.aroundIdMessageHistoryViewForPeerId(peerId, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
return wrappedMessageHistorySignal(peerId: peerId, signal: signal)
} else {
return .never()
}
}
public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: anchorIndex, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
let signal = account.postbox.aroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: anchorIndex, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData)
return wrappedMessageHistorySignal(peerId: peerId, signal: signal)
} else {
return .never()

View File

@@ -112,6 +112,28 @@ private struct MultipartIntermediateResult {
let bigTotalParts: Int?
}
private enum MultipartUploadData {
case resourceData(MediaResourceData)
case data(Data)
var size: Int {
switch self {
case let .resourceData(data):
return data.size
case let .data(data):
return data.count
}
}
var complete: Bool {
switch self {
case let .resourceData(data):
return data.complete
case .data:
return true
}
}
}
private final class MultipartUploadManager {
let parallelParts: Int = 3
let defaultPartSize: Int
@@ -120,7 +142,7 @@ private final class MultipartUploadManager {
let queue = Queue()
let fileId: Int64
let dataSignal: Signal<MediaResourceData, NoError>
let dataSignal: Signal<MultipartUploadData, NoError>
var committedOffset: Int
let uploadPart: (UploadPart) -> Signal<Void, NoError>
@@ -131,13 +153,13 @@ private final class MultipartUploadManager {
var uploadedParts: [Int: Int] = [:]
let dataDisposable = MetaDisposable()
var resourceData: MediaResourceData?
var resourceData: MultipartUploadData?
var headerPartReady: Bool
let state: MultipartUploadState
init(resource: MediaResource, data: Signal<MediaResourceData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, uploadPart: @escaping (UploadPart) -> Signal<Void, NoError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult) -> Void) {
init(headerSize: Int32, data: Signal<MultipartUploadData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, uploadPart: @escaping (UploadPart) -> Signal<Void, NoError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult) -> Void) {
self.dataSignal = data
var fileId: Int64 = 0
@@ -151,7 +173,7 @@ private final class MultipartUploadManager {
self.progress = progress
self.completed = completed
self.headerPartReady = resource.headerSize == 0
self.headerPartReady = headerSize == 0
if let hintFileSize = hintFileSize, hintFileSize > 5 * 1024 * 1024 {
self.defaultPartSize = 512 * 1024
@@ -219,7 +241,13 @@ private final class MultipartUploadManager {
let partOffset = 0
let partSize = min(resourceData.size - partOffset, self.defaultPartSize)
let partIndex = partOffset / self.defaultPartSize
let fileData = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.alwaysMapped])
let fileData: Data?
switch resourceData {
case let .resourceData(data):
fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.alwaysMapped])
case let .data(data):
fileData = data
}
let partData = fileData!.subdata(in: partOffset ..< (partOffset + partSize))
var currentBigTotalParts = self.bigTotalParts
if let _ = self.bigTotalParts {
@@ -251,7 +279,13 @@ private final class MultipartUploadManager {
if nextOffset < resourceData.size && partSize > 0 && (resourceData.complete || partSize == self.defaultPartSize) {
let partIndex = partOffset / self.defaultPartSize
let fileData = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.alwaysMapped])
let fileData: Data?
switch resourceData {
case let .resourceData(data):
fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.alwaysMapped])
case let .data(data):
fileData = data
}
let partData = self.state.transform(data: fileData!.subdata(in: partOffset ..< (partOffset + partSize)))
var currentBigTotalParts = self.bigTotalParts
if let _ = self.bigTotalParts, resourceData.complete && partOffset + partSize == resourceData.size {
@@ -283,7 +317,12 @@ enum MultipartUploadResult {
case inputSecretFile(Api.InputEncryptedFile, Int32, SecretFileEncryptionKey)
}
func multipartUpload(network: Network, postbox: Postbox, resource: MediaResource, encrypt: Bool, hintFileSize: Int? = nil) -> Signal<MultipartUploadResult, NoError> {
enum MultipartUploadSource {
case resource(MediaResource)
case data(Data)
}
func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, hintFileSize: Int? = nil) -> Signal<MultipartUploadResult, NoError> {
return network.download(datacenterId: network.datacenterId)
|> mapToSignal { download -> Signal<MultipartUploadResult, NoError> in
return Signal { subscriber in
@@ -302,9 +341,21 @@ func multipartUpload(network: Network, postbox: Postbox, resource: MediaResource
encryptionKey = SecretFileEncryptionKey(aesKey: aesKey, aesIv: aesIv)
}
let resourceData = postbox.mediaBox.resourceData(resource, option: .incremental(waitUntilFetchStatus: true))
let dataSignal: Signal<MultipartUploadData, NoError>
let headerSize: Int32
let fetchedResource: Signal<Void, NoError>
switch source {
case let .resource(resource):
dataSignal = postbox.mediaBox.resourceData(resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) }
headerSize = resource.headerSize
fetchedResource = postbox.mediaBox.fetchedResource(resource)
case let .data(data):
dataSignal = .single(.data(data))
headerSize = 0
fetchedResource = .complete()
}
let manager = MultipartUploadManager(resource: resource, data: resourceData, encryptionKey: encryptionKey, hintFileSize: hintFileSize, uploadPart: { part in
let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, uploadPart: { part in
return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, bigTotalParts: part.bigTotalParts)
}, progress: { progress in
subscriber.putNext(.progress(progress))
@@ -337,11 +388,11 @@ func multipartUpload(network: Network, postbox: Postbox, resource: MediaResource
manager.start()
let fetchedResource = postbox.mediaBox.fetchedResource(resource).start()
let fetchedResourceDisposable = fetchedResource.start()
return ActionDisposable {
manager.cancel()
fetchedResource.dispose()
fetchedResourceDisposable.dispose()
}
}
}

View File

@@ -25,7 +25,7 @@ public func updateAccountPhoto(account:Account, resource:MediaResource) -> Signa
public func updatePeerPhoto(account:Account, peerId:PeerId, resource:MediaResource) -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> {
return account.postbox.loadedPeerWithId(peerId) |> mapError {_ in return .generic} |> mapToSignal { peer in
return multipartUpload(network: account.network, postbox: account.postbox, resource: resource, encrypt: false)
return multipartUpload(network: account.network, postbox: account.postbox, source: .resource(resource), encrypt: false)
|> mapError {_ in return .generic}
|> mapToSignal { result -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
switch result {

View File

@@ -74,7 +74,7 @@ func messageContentToUpload(network: Network, postbox: Postbox, transformOutgoin
private func uploadedMediaImageContent(network: Network, postbox: Postbox, peerId: PeerId, image: TelegramMediaImage, text: String) -> Signal<PendingMessageUploadedContentResult, NoError> {
if let largestRepresentation = largestImageRepresentation(image.representations) {
return multipartUpload(network: network, postbox: postbox, resource: largestRepresentation.resource, encrypt: peerId.namespace == Namespaces.Peer.SecretChat)
return multipartUpload(network: network, postbox: postbox, source: .resource(largestRepresentation.resource), encrypt: peerId.namespace == Namespaces.Peer.SecretChat)
|> map { next -> PendingMessageUploadedContentResult in
switch next {
case let .progress(progress):
@@ -90,9 +90,9 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, peerI
}
}
private func inputDocumentAttributesFromFile(_ file: TelegramMediaFile) -> [Api.DocumentAttribute] {
func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaFileAttribute]) -> [Api.DocumentAttribute] {
var attributes: [Api.DocumentAttribute] = []
for attribute in file.attributes {
for attribute in fileAttributes {
switch attribute {
case .Animated:
attributes.append(.documentAttributeAnimated)
@@ -149,7 +149,7 @@ private enum UploadedMediaThumbnail {
}
private func uploadedThumbnail(network: Network, postbox: Postbox, image: TelegramMediaImageRepresentation) -> Signal<Api.InputFile?, NoError> {
return multipartUpload(network: network, postbox: postbox, resource: image.resource, encrypt: false)
return multipartUpload(network: network, postbox: postbox, source: .resource(image.resource), encrypt: false)
|> mapToSignal { result -> Signal<Api.InputFile?, NoError> in
switch result {
case .progress:
@@ -169,7 +169,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, transf
} else if let resource = file.resource as? LocalFileReferenceMediaResource, let size = resource.size {
hintSize = Int(size)
}
let upload = multipartUpload(network: network, postbox: postbox, resource: file.resource, encrypt: peerId.namespace == Namespaces.Peer.SecretChat, hintFileSize: hintSize)
let upload = multipartUpload(network: network, postbox: postbox, source: .resource(file.resource), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, hintFileSize: hintSize)
/*|> map { next -> UploadedMediaFileContent in
switch next {
case let .progress(progress):
@@ -249,9 +249,9 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, transf
if case let .done(thumbnail) = media {
let inputMedia: Api.InputMedia
if let thumbnail = thumbnail {
inputMedia = Api.InputMedia.inputMediaUploadedThumbDocument(flags: 0, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFile(file), caption: text, stickers: nil)
inputMedia = Api.InputMedia.inputMediaUploadedThumbDocument(flags: 0, file: inputFile, thumb: thumbnail, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), caption: text, stickers: nil)
} else {
inputMedia = Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFile(file), caption: text, stickers: nil)
inputMedia = Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), caption: text, stickers: nil)
}
return .single(.content(.media(inputMedia)))
} else {

View File

@@ -11,32 +11,46 @@ import Foundation
public enum StandaloneMedia {
case image(Data)
case file(Data)
case file(data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute])
}
public func standaloneSendMessage(account: Account, peerId: PeerId, text: String, attributes: [MessageAttribute], replyToMessageId: MessageId?) -> Signal<Void, NoError> {
let contentToUpload = messageContentToUpload(network: account.network, postbox: account.postbox, transformOutgoingMessageMedia: nil, peerId: peerId, messageId: nil, attributes: attributes, text: text, media: [])
switch contentToUpload {
case let .ready(content):
return sendMessageContent(account: account, peerId: peerId, attributes: attributes, content: content)
case let .upload(uploadSignal):
return .complete()
/*if strongSelf.canBeginUploadingMessage(id: message.id) {
strongSelf.beginUploadingMessage(messageContext: messageContext, id: message.id, uploadSignal: uploadSignal)
} else {
messageContext.state = .waitingForUploadToStart(uploadSignal)
}*/
private enum StandaloneMessageContent {
case text(String)
case media(Api.InputMedia)
}
public func standaloneSendMessage(account: Account, peerId: PeerId, text: String, attributes: [MessageAttribute], media: StandaloneMedia?, replyToMessageId: MessageId?) -> Signal<Void, NoError> {
let content: Signal<StandaloneMessageContent, NoError>
if let media = media {
switch media {
case let .image(data):
content = uploadedImage(account: account, text: text, data: data)
|> map { next -> StandaloneMessageContent in
return .media(next)
}
case let .file(data, mimeType, attributes):
content = uploadedFile(account: account, text: text, data: data, mimeType: mimeType, attributes: attributes)
|> map { next -> StandaloneMessageContent in
return .media(next)
}
}
} else {
content = .single(.text(text))
}
return content
|> mapToSignal { content -> Signal<Void, NoError> in
return sendMessageContent(account: account, peerId: peerId, attributes: attributes, content: content)
}
}
private func sendMessageContent(account: Account, peerId: PeerId, attributes: [MessageAttribute], content: PendingMessageUploadedContent) -> Signal<Void, NoError> {
private func sendMessageContent(account: Account, peerId: PeerId, attributes: [MessageAttribute], content: StandaloneMessageContent) -> Signal<Void, NoError> {
return account.postbox.modify { modifier -> Signal<Void, NoError> in
if peerId.namespace == Namespaces.Peer.SecretChat {
return .complete()
} else if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
var uniqueId: Int64 = 0
var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
//var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
var messageEntities: [Api.MessageEntity]?
var replyMessageId: Int32?
@@ -49,8 +63,8 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
replyMessageId = replyAttribute.messageId.id
} else if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute {
uniqueId = outgoingInfo.uniqueId
} else if let attribute = attribute as? ForwardSourceInfoAttribute {
forwardSourceInfoAttribute = attribute
} else if let _ = attribute as? ForwardSourceInfoAttribute {
//forwardSourceInfoAttribute = attribute
} else if let attribute = attribute as? TextEntitiesMessageAttribute {
messageEntities = apiTextAttributeEntities(attribute, associatedPeers: SimpleDictionary())
} else if let attribute = attribute as? OutgoingContentInfoMessageAttribute {
@@ -79,23 +93,6 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|> mapError { _ -> NoError in
return NoError()
}
case let .forward(sourceInfo):
if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = modifier.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) {
sendMessageRequest = account.network.request(Api.functions.messages.forwardMessages(flags: 0, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer))
|> mapError { _ -> NoError in
return NoError()
}
} else {
sendMessageRequest = .fail(NoError())
}
case let .chatContextResult(chatContextResult):
sendMessageRequest = account.network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id))
|> mapError { _ -> NoError in
return NoError()
}
case .secretMedia:
assertionFailure()
sendMessageRequest = .fail(NoError())
}
return sendMessageRequest
@@ -115,3 +112,27 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
}
} |> switchToLatest
}
private func uploadedImage(account: Account, text: String, data: Data) -> Signal<Api.InputMedia, NoError> {
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false)
|> mapToSignal { next -> Signal<Api.InputMedia, NoError> in
switch next {
case let .inputFile(inputFile):
return .single(Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, caption: text, stickers: nil))
case .inputSecretFile, .progress:
return .complete()
}
}
}
private func uploadedFile(account: Account, text: String, data: Data, mimeType: String, attributes: [TelegramMediaFileAttribute]) -> Signal<Api.InputMedia, NoError> {
return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false)
|> mapToSignal { next -> Signal<Api.InputMedia, NoError> in
switch next {
case let .inputFile(inputFile):
return .single(Api.InputMedia.inputMediaUploadedDocument(flags: 0, file: inputFile, mimeType: mimeType, attributes: inputDocumentAttributesFromFileAttributes(attributes), caption: text, stickers: nil))
case .inputSecretFile, .progress:
return .complete()
}
}
}