126 lines
6.3 KiB
Swift
126 lines
6.3 KiB
Swift
import Combine
|
|
import Foundation
|
|
import UIKit
|
|
|
|
final class FileMiddleware {
|
|
static let shared = FileMiddleware()
|
|
private var downloadingMessageIDs = ThreadSafeSet<String>()
|
|
|
|
func middleware(state _: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> {
|
|
switch action {
|
|
// MARK: - For incomig attachments
|
|
case .conversationAction(.messagesUpdated(let messages)):
|
|
return Future { [weak self] promise in
|
|
guard let wSelf = self else {
|
|
promise(.success(.info("FileMiddleware: on checking attachments/shares messages, middleware self is nil")))
|
|
return
|
|
}
|
|
|
|
// for incoming messages with attachments
|
|
for message in messages where message.attachmentRemotePath != nil && message.attachmentLocalPath == nil {
|
|
if wSelf.downloadingMessageIDs.contains(message.id) {
|
|
continue
|
|
}
|
|
wSelf.downloadingMessageIDs.insert(message.id)
|
|
DispatchQueue.main.async {
|
|
// swiftlint:disable:next force_unwrapping
|
|
store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: message.attachmentRemotePath!)))
|
|
}
|
|
}
|
|
|
|
// for outgoing messages with shared attachments
|
|
for message in messages where message.attachmentLocalPath != nil && message.attachmentRemotePath == nil && message.pending {
|
|
if wSelf.downloadingMessageIDs.contains(message.id) {
|
|
continue
|
|
}
|
|
wSelf.downloadingMessageIDs.insert(message.id)
|
|
DispatchQueue.main.async {
|
|
store.dispatch(.xmppAction(.xmppSharingTryUpload(message)))
|
|
}
|
|
}
|
|
|
|
// for outgoing messages with shared attachments which are already uploaded
|
|
// but have no thumbnail
|
|
for message in messages where message.attachmentLocalName != nil && message.attachmentRemotePath != nil && message.attachmentThumbnailName == nil && !message.pending && !message.sentError {
|
|
DispatchQueue.main.async {
|
|
// swiftlint:disable:next force_unwrapping
|
|
store.dispatch(.fileAction(.createAttachmentThumbnail(messageId: message.id, localName: message.attachmentLocalName!)))
|
|
}
|
|
}
|
|
|
|
promise(.success(.info("FileMiddleware: attachments/shares messages processed")))
|
|
}.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.downloadAttachmentFile(let id, let attachmentRemotePath)):
|
|
return Future { promise in
|
|
let localName = "\(id)_\(UUID().uuidString)\(attachmentRemotePath.lastPathComponent)"
|
|
let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName)
|
|
DownloadManager.shared.enqueueDownload(from: attachmentRemotePath, to: localUrl) { error in
|
|
DispatchQueue.main.async {
|
|
if let error {
|
|
store.dispatch(.fileAction(.downloadingAttachmentFileFailed(messageId: id, reason: error.localizedDescription)))
|
|
} else {
|
|
store.dispatch(.fileAction(.attachmentFileDownloaded(messageId: id, localName: localName)))
|
|
}
|
|
}
|
|
}
|
|
promise(.success(.info("FileMiddleware: started downloading attachment for message \(id)")))
|
|
}.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.attachmentFileDownloaded(let id, let localName)):
|
|
return Future { [weak self] promise in
|
|
self?.downloadingMessageIDs.remove(id)
|
|
promise(.success(.fileAction(.createAttachmentThumbnail(messageId: id, localName: localName))))
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.createAttachmentThumbnail(let id, let localName)):
|
|
return Future { [weak self] promise in
|
|
if let thumbnailName = FileProcessing.shared.createThumbnail(localName: localName) {
|
|
self?.downloadingMessageIDs.remove(id)
|
|
promise(.success(.fileAction(.attachmentThumbnailCreated(messageId: id, thumbnailName: thumbnailName))))
|
|
} else {
|
|
self?.downloadingMessageIDs.remove(id)
|
|
promise(.success(.info("FileMiddleware: failed to create thumbnail from \(localName) for message \(id)")))
|
|
}
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
// MARK: - For outgoing sharing
|
|
case .fileAction(.fetchItemsFromGallery):
|
|
return Future<AppAction, Never> { promise in
|
|
let items = FileProcessing.shared.fetchGallery()
|
|
promise(.success(.fileAction(.itemsFromGalleryFetched(items: items))))
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.itemsFromGalleryFetched(let items)):
|
|
return Future { promise in
|
|
let newItems = FileProcessing.shared.fillGalleryItemsThumbnails(items: items)
|
|
promise(.success(.sharingAction(.galleryItemsUpdated(items: newItems))))
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.copyGalleryItemsForUploading(let items)):
|
|
return Future { promise in
|
|
let ids = FileProcessing.shared.copyGalleryItemsForUploading(items: items)
|
|
promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: ids.map { $0.0 }, localNames: ids.map { $0.1 }))))
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
case .fileAction(.copyCameraCapturedForUploading(let media, let type)):
|
|
return Future { promise in
|
|
if let (id, localName) = FileProcessing.shared.copyCameraCapturedForUploading(media: media, type: type) {
|
|
promise(.success(.fileAction(.itemsCopiedForUploading(newMessageIds: [id], localNames: [localName]))))
|
|
} else {
|
|
promise(.success(.info("FileMiddleware: failed to copy camera captured media for uploading")))
|
|
}
|
|
}
|
|
.eraseToAnyPublisher()
|
|
|
|
default:
|
|
return Empty().eraseToAnyPublisher()
|
|
}
|
|
}
|
|
}
|