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

This commit is contained in:
Ilya Laktyushin 2021-01-25 18:38:48 +03:00
commit 9790e94e16
5 changed files with 80 additions and 21 deletions

View File

@ -5922,7 +5922,7 @@ Sorry for the inconvenience.";
"Conversation.AddMembers" = "Add Members"; "Conversation.AddMembers" = "Add Members";
"Conversation.ImportedMessageHint" = "The messages was imported from another app. We can't guarantee it's real."; "Conversation.ImportedMessageHint" = "This message was imported from another app. We can't guarantee it's real.";
"Conversation.GreetingText" = "Send a message or tap on the greeting below."; "Conversation.GreetingText" = "Send a message or tap on the greeting below.";
@ -5933,7 +5933,7 @@ Sorry for the inconvenience.";
"Conversation.AudioRateTooltipSpeedUp" = "The audio will now play 2 times faster."; "Conversation.AudioRateTooltipSpeedUp" = "The audio will now play 2 times faster.";
"Conversation.AudioRateTooltipNormal" = "The audio will now play at normal speed."; "Conversation.AudioRateTooltipNormal" = "The audio will now play at normal speed.";
"ChatImport.Title" = "Import Chat"; "ChatImport.Title" = "Select Chat";
"ChatImport.SelectionErrorNotAdmin" = "You need to be an admin of the group to import messages into it."; "ChatImport.SelectionErrorNotAdmin" = "You need to be an admin of the group to import messages into it.";
"ChatImport.SelectionErrorGroupGeneric" = "You can't import history into this group."; "ChatImport.SelectionErrorGroupGeneric" = "You can't import history into this group.";
"ChatImport.SelectionConfirmationGroupWithTitle" = "Are you sure you want to import messages from **%1$@** into **%2$@**?"; "ChatImport.SelectionConfirmationGroupWithTitle" = "Are you sure you want to import messages from **%1$@** into **%2$@**?";
@ -5956,5 +5956,6 @@ Sorry for the inconvenience.";
"ChatImportActivity.InProgress" = "Please keep this window open\nduring the import."; "ChatImportActivity.InProgress" = "Please keep this window open\nduring the import.";
"ChatImportActivity.ErrorNotAdmin" = "You need to be an admin."; "ChatImportActivity.ErrorNotAdmin" = "You need to be an admin.";
"ChatImportActivity.ErrorInvalidChatType" = "You can't import this history in this type of chat."; "ChatImportActivity.ErrorInvalidChatType" = "You can't import this history in this type of chat.";
"ChatImportActivity.ErrorUserBlocked" = "You need to be an admin.";
"ChatImportActivity.ErrorGeneric" = "An error occurred."; "ChatImportActivity.ErrorGeneric" = "An error occurred.";
"ChatImportActivity.Success" = "Chat imported\nsuccessfully."; "ChatImportActivity.Success" = "Chat imported\nsuccessfully.";

View File

@ -549,8 +549,8 @@ public final class ChatImportActivityScreen: ViewController {
} }
} }
} }
|> mapToSignal { session -> Signal<(String, Float), ImportError> in |> mapToSignal { session -> Signal<[(String, Float)], ImportError> in
var importSignal: Signal<(String, Float), ImportError> = .single(("", 0.0)) var mediaSignals: [Signal<(String, Float), ImportError>] = []
for (_, fileName, mediaType, fileData) in otherEntries { for (_, fileName, mediaType, fileData) in otherEntries {
let unpackedFile: Signal<TempBoxFile, ImportError> = fileData.get() let unpackedFile: Signal<TempBoxFile, ImportError> = fileData.get()
@ -588,28 +588,28 @@ public final class ChatImportActivityScreen: ViewController {
} }
} }
importSignal = importSignal mediaSignals.append(Signal<(String, Float), ImportError>.single((fileName, 0.0))
|> then(uploadedMedia) |> then(uploadedMedia))
} }
importSignal = importSignal return combineLatest(mediaSignals)
|> then(ChatHistoryImport.startImport(account: context.account, session: session) |> then(ChatHistoryImport.startImport(account: context.account, session: session)
|> mapError { _ -> ImportError in |> mapError { _ -> ImportError in
return .generic return .generic
} }
|> map { _ -> (String, Float) in |> map { _ -> [(String, Float)] in
}) })
return importSignal
} }
|> deliverOnMainQueue).start(next: { [weak self] (fileName, progress) in |> deliverOnMainQueue).start(next: { [weak self] fileNameAndProgress in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
for (fileName, progress) in fileNameAndProgress {
if let (fileSize, _) = strongSelf.pendingEntries[fileName] { if let (fileSize, _) = strongSelf.pendingEntries[fileName] {
strongSelf.pendingEntries[fileName] = (fileSize, progress) strongSelf.pendingEntries[fileName] = (fileSize, progress)
} }
}
var totalDoneBytes = strongSelf.mainEntrySize var totalDoneBytes = strongSelf.mainEntrySize
for (_, sizeAndProgress) in strongSelf.pendingEntries { for (_, sizeAndProgress) in strongSelf.pendingEntries {

View File

@ -104,7 +104,7 @@ public enum ChatHistoryImport {
} }
public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, mimeType: String, type: MediaType) -> Signal<Float, UploadMediaError> { public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, mimeType: String, type: MediaType) -> Signal<Float, UploadMediaError> {
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false) return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, useLargerParts: true, useMultiplexedRequests: true)
|> mapError { _ -> UploadMediaError in |> mapError { _ -> UploadMediaError in
return .generic return .generic
} }

View File

@ -82,6 +82,33 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
self.context.authTokenForDatacenter(withIdRequired: self.datacenterId, authToken:self.mtProto.requiredAuthToken, masterDatacenterId: self.mtProto.authTokenMasterDatacenterId) self.context.authTokenForDatacenter(withIdRequired: self.datacenterId, authToken:self.mtProto.requiredAuthToken, masterDatacenterId: self.mtProto.authTokenMasterDatacenterId)
} }
static func uploadPart(multiplexedManager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64, tag: MediaResourceFetchTag?, fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal<Void, UploadPartError> {
let saveFilePart: (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>)
if asBigPart {
let totalParts: Int32
if let bigTotalParts = bigTotalParts {
totalParts = Int32(bigTotalParts)
} else {
totalParts = -1
}
saveFilePart = Api.functions.upload.saveBigFilePart(fileId: fileId, filePart: Int32(index), fileTotalParts: totalParts, bytes: Buffer(data: data))
} else {
saveFilePart = Api.functions.upload.saveFilePart(fileId: fileId, filePart: Int32(index), bytes: Buffer(data: data))
}
return multiplexedManager.request(to: .main(datacenterId), consumerId: consumerId, data: saveFilePart, tag: tag, continueInBackground: true)
|> mapError { error -> UploadPartError in
if error.errorCode == 400 {
return .invalidMedia
} else {
return .generic
}
}
|> mapToSignal { _ -> Signal<Void, UploadPartError> in
return .complete()
}
}
func uploadPart(fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal<Void, UploadPartError> { func uploadPart(fileId: Int64, index: Int, data: Data, asBigPart: Bool, bigTotalParts: Int? = nil) -> Signal<Void, UploadPartError> {
return Signal<Void, MTRpcError> { subscriber in return Signal<Void, MTRpcError> { subscriber in
let request = MTRequest() let request = MTRequest()

View File

@ -117,6 +117,7 @@ private final class MultipartUploadManager {
var defaultPartSize: Int var defaultPartSize: Int
var bigTotalParts: Int? var bigTotalParts: Int?
var bigParts: Bool var bigParts: Bool
private let useLargerParts: Bool
let queue = Queue() let queue = Queue()
let fileId: Int64 let fileId: Int64
@ -138,13 +139,15 @@ private final class MultipartUploadManager {
let state: MultipartUploadState let state: MultipartUploadState
init(headerSize: Int32, data: Signal<MultipartUploadData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, uploadPart: @escaping (UploadPart) -> Signal<Void, UploadPartError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) { init(headerSize: Int32, data: Signal<MultipartUploadData, NoError>, encryptionKey: SecretFileEncryptionKey?, hintFileSize: Int?, hintFileIsLarge: Bool, useLargerParts: Bool, uploadPart: @escaping (UploadPart) -> Signal<Void, UploadPartError>, progress: @escaping (Float) -> Void, completed: @escaping (MultipartIntermediateResult?) -> Void) {
self.dataSignal = data self.dataSignal = data
var fileId: Int64 = 0 var fileId: Int64 = 0
arc4random_buf(&fileId, 8) arc4random_buf(&fileId, 8)
self.fileId = fileId self.fileId = fileId
self.useLargerParts = useLargerParts
self.state = MultipartUploadState(encryptionKey: encryptionKey) self.state = MultipartUploadState(encryptionKey: encryptionKey)
self.committedOffset = 0 self.committedOffset = 0
@ -166,6 +169,10 @@ private final class MultipartUploadManager {
self.defaultPartSize = 512 * 1024 self.defaultPartSize = 512 * 1024
self.bigTotalParts = nil self.bigTotalParts = nil
self.bigParts = true self.bigParts = true
} else if useLargerParts {
self.bigParts = false
self.defaultPartSize = 128 * 1024
self.bigTotalParts = nil
} else { } else {
self.bigParts = false self.bigParts = false
self.defaultPartSize = 16 * 1024 self.defaultPartSize = 16 * 1024
@ -202,7 +209,11 @@ private final class MultipartUploadManager {
self.bigParts = true self.bigParts = true
} else { } else {
self.bigParts = false self.bigParts = false
if self.useLargerParts {
self.defaultPartSize = 128 * 1024
} else {
self.defaultPartSize = 16 * 1024 self.defaultPartSize = 16 * 1024
}
self.bigTotalParts = nil self.bigTotalParts = nil
} }
} }
@ -368,9 +379,24 @@ enum MultipartUploadError {
case generic case generic
} }
func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool) -> Signal<MultipartUploadResult, MultipartUploadError> { func multipartUpload(network: Network, postbox: Postbox, source: MultipartUploadSource, encrypt: Bool, tag: MediaResourceFetchTag?, hintFileSize: Int?, hintFileIsLarge: Bool, useLargerParts: Bool = false, useMultiplexedRequests: Bool = false) -> Signal<MultipartUploadResult, MultipartUploadError> {
return network.upload(tag: tag) enum UploadInterface {
|> mapToSignalPromotingError { download -> Signal<MultipartUploadResult, MultipartUploadError> in case download(Download)
case multiplexed(manager: MultiplexedRequestManager, datacenterId: Int, consumerId: Int64)
}
let uploadInterface: Signal<UploadInterface, NoError>
if useMultiplexedRequests {
uploadInterface = .single(.multiplexed(manager: network.multiplexedRequestManager, datacenterId: network.datacenterId, consumerId: arc4random64()))
} else {
uploadInterface = network.upload(tag: tag)
|> map { download -> UploadInterface in
return .download(download)
}
}
return uploadInterface
|> mapToSignalPromotingError { uploadInterface -> Signal<MultipartUploadResult, MultipartUploadError> in
return Signal { subscriber in return Signal { subscriber in
var encryptionKey: SecretFileEncryptionKey? var encryptionKey: SecretFileEncryptionKey?
if encrypt { if encrypt {
@ -419,8 +445,13 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload
fetchedResource = .complete() fetchedResource = .complete()
} }
let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, uploadPart: { part in let manager = MultipartUploadManager(headerSize: headerSize, data: dataSignal, encryptionKey: encryptionKey, hintFileSize: hintFileSize, hintFileIsLarge: hintFileIsLarge, useLargerParts: useLargerParts, uploadPart: { part in
switch uploadInterface {
case let .download(download):
return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts) return download.uploadPart(fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts)
case let .multiplexed(multiplexed, datacenterId, consumerId):
return Download.uploadPart(multiplexedManager: multiplexed, datacenterId: datacenterId, consumerId: consumerId, tag: nil, fileId: part.fileId, index: part.index, data: part.data, asBigPart: part.bigPart, bigTotalParts: part.bigTotalParts)
}
}, progress: { progress in }, progress: { progress in
subscriber.putNext(.progress(progress)) subscriber.putNext(.progress(progress))
}, completed: { result in }, completed: { result in