Skip to content

Commit

Permalink
feat: Download file from public share
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien-coye committed Sep 19, 2024
1 parent 07e1c48 commit c26647f
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,15 @@ class MultipleSelectionFileListViewModel {
init(configuration: FileListViewModel.Configuration, driveFileManager: DriveFileManager, currentDirectory: File) {
isMultipleSelectionEnabled = false
selectedCount = 0
multipleSelectionActions = [.move, .delete, .more]

self.driveFileManager = driveFileManager

if driveFileManager.isPublicShare {
multipleSelectionActions = []
} else {
multipleSelectionActions = [.move, .delete, .more]
}

self.currentDirectory = currentDirectory
self.configuration = configuration
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ extension FileActionsFloatingPanelViewController {
}

private func setupActions() {
guard !driveFileManager.isPublicShare else {
actions = []
return
}

actions = (file.isDirectory ? FloatingPanelAction.folderListActions : FloatingPanelAction.listActions).filter { action in
switch action {
case .openWith:
Expand Down Expand Up @@ -175,7 +180,8 @@ extension FileActionsFloatingPanelViewController {
if file.isMostRecentDownloaded {
presentShareSheet(from: indexPath)
} else {
downloadFile(action: action, indexPath: indexPath) { [weak self] in
downloadFile(action: action,
indexPath: indexPath) { [weak self] in
self?.presentShareSheet(from: indexPath)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,9 @@ final class FileActionsFloatingPanelViewController: UICollectionViewController {
present(activityViewController, animated: true)
}

func downloadFile(action: FloatingPanelAction, indexPath: IndexPath, completion: @escaping () -> Void) {
func downloadFile(action: FloatingPanelAction,
indexPath: IndexPath,
completion: @escaping () -> Void) {
guard let observerViewController = UIApplication.shared.windows.first?.rootViewController else { return }
downloadAction = action
setLoading(true, action: action, at: indexPath)
Expand All @@ -405,7 +407,16 @@ final class FileActionsFloatingPanelViewController: UICollectionViewController {
}
}
}
DownloadQueue.instance.addToQueue(file: file, userId: accountManager.currentUserId)

if let publicShareProxy = driveFileManager.publicShareProxy {
DownloadQueue.instance.addPublicShareToQueue(file: file,
userId: accountManager.currentUserId,
driveFileManager: driveFileManager,
publicShareProxy: publicShareProxy)
} else {
DownloadQueue.instance.addToQueue(file: file,
userId: accountManager.currentUserId)
}
}

func copyShareLinkToPasteboard(from indexPath: IndexPath, link: String) {
Expand Down
12 changes: 10 additions & 2 deletions kDriveCore/Data/Api/Endpoint+Files.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,22 @@ public extension Endpoint {
])
}

static func download(file: AbstractFile, as asType: String? = nil) -> Endpoint {
static func download(file: AbstractFile,
publicShareProxy: PublicShareProxy? = nil,
as asType: String? = nil) -> Endpoint {
let queryItems: [URLQueryItem]?
if let asType {
queryItems = [URLQueryItem(name: "as", value: asType)]
} else {
queryItems = nil
}
return .fileInfoV2(file).appending(path: "/download", queryItems: queryItems)
if let publicShareProxy {
return .downloadShareLinkFile(driveId: publicShareProxy.driveId,
linkUuid: publicShareProxy.shareLinkUid,
fileId: file.id)
} else {
return .fileInfoV2(file).appending(path: "/download", queryItems: queryItems)
}
}

static func convert(file: AbstractFile) -> Endpoint {
Expand Down
4 changes: 2 additions & 2 deletions kDriveCore/Data/Api/Endpoint+Share.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ public extension Endpoint {
return shareLinkFileV2(driveId: driveId, linkUuid: linkUuid, fileId: fileId).appending(path: "/thumbnail")
}

/// Share mink file preview
/// Share link file preview
static func shareLinkFilePreview(driveId: Int, linkUuid: String, fileId: Int) -> Endpoint {
return shareLinkFileV2(driveId: driveId, linkUuid: linkUuid, fileId: fileId).appending(path: "/preview")
}

/// Download share link file
static func downloadShareLinkFile(driveId: Int, linkUuid: String, fileId: Int) -> Endpoint {
return shareLinkFile(driveId: driveId, linkUuid: linkUuid, fileId: fileId).appending(path: "/download")
return shareLinkFileV2(driveId: driveId, linkUuid: linkUuid, fileId: fileId).appending(path: "/download")
}

func showOfficeShareLinkFile(driveId: Int, linkUuid: String, fileId: Int) -> Endpoint {
Expand Down
60 changes: 57 additions & 3 deletions kDriveCore/Data/DownloadQueue/DownloadOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class DownloadOperation: Operation, DownloadOperationable {
private let fileManager = FileManager.default
private let driveFileManager: DriveFileManager
private let urlSession: FileDownloadSession
private let publicShareProxy: PublicShareProxy?
private let itemIdentifier: NSFileProviderItemIdentifier?
private var progressObservation: NSKeyValueObservation?
private var backgroundTaskIdentifier: UIBackgroundTaskIdentifier = .invalid
Expand Down Expand Up @@ -93,19 +94,25 @@ public class DownloadOperation: Operation, DownloadOperationable {
file: File,
driveFileManager: DriveFileManager,
urlSession: FileDownloadSession,
publicShareProxy: PublicShareProxy? = nil,
itemIdentifier: NSFileProviderItemIdentifier? = nil
) {
self.file = File(value: file)
self.driveFileManager = driveFileManager
self.urlSession = urlSession
self.publicShareProxy = publicShareProxy
self.itemIdentifier = itemIdentifier
}

public init(file: File, driveFileManager: DriveFileManager, task: URLSessionDownloadTask, urlSession: FileDownloadSession) {
public init(file: File,
driveFileManager: DriveFileManager,
task: URLSessionDownloadTask,
urlSession: FileDownloadSession) {
self.file = file
self.driveFileManager = driveFileManager
self.urlSession = urlSession
self.task = task
publicShareProxy = nil
itemIdentifier = nil
}

Expand Down Expand Up @@ -170,6 +177,53 @@ public class DownloadOperation: Operation, DownloadOperationable {
}

override public func main() {
DDLogInfo("[DownloadOperation] Start for \(file.id) with session \(urlSession.identifier)")

if let publicShareProxy {
downloadPublicShareFile(publicShareProxy: publicShareProxy)
} else {
downloadFile()
}
}

private func downloadPublicShareFile(publicShareProxy: PublicShareProxy) {
DDLogInfo("[DownloadOperation] Downloading publicShare \(file.id) with session \(urlSession.identifier)")

let url = Endpoint.download(file: file, publicShareProxy: publicShareProxy).url

// Add download task to Realm
let downloadTask = DownloadTask(
fileId: file.id,
isDirectory: file.isDirectory,
driveId: file.driveId,
userId: driveFileManager.drive.userId,
sessionId: urlSession.identifier,
sessionUrl: url.absoluteString
)

try? uploadsDatabase.writeTransaction { writableRealm in
writableRealm.add(downloadTask, update: .modified)
}

let request = URLRequest(url: url)
task = urlSession.downloadTask(with: request, completionHandler: downloadCompletion)
progressObservation = task?.progress.observe(\.fractionCompleted, options: .new) { [fileId = file.id] _, value in
guard let newValue = value.newValue else {
return
}
DownloadQueue.instance.publishProgress(newValue, for: fileId)
}
if let itemIdentifier {
driveInfosManager.getFileProviderManager(for: driveFileManager.drive) { manager in
manager.register(self.task!, forItemWithIdentifier: itemIdentifier) { _ in
// META: keep SonarCloud happy
}
}
}
task?.resume()
}

private func downloadFile() {
DDLogInfo("[DownloadOperation] Downloading \(file.id) with session \(urlSession.identifier)")

let url = Endpoint.download(file: file).url
Expand Down Expand Up @@ -207,7 +261,7 @@ public class DownloadOperation: Operation, DownloadOperationable {
}
task?.resume()
} else {
error = .localError // Other error?
error = .unknownToken // Other error?
end(sessionUrl: url)
}
}
Expand Down Expand Up @@ -288,7 +342,7 @@ public class DownloadOperation: Operation, DownloadOperationable {
return
}

assert(file.isDownloaded, "Expecting to be downloaded at the end of the downloadOperation")
assert(file.isDownloaded, "Expecting to be downloaded at the end of the downloadOperation error:\(error)")

try? uploadsDatabase.writeTransaction { writableRealm in
guard let task = writableRealm.objects(DownloadTask.self)
Expand Down
35 changes: 35 additions & 0 deletions kDriveCore/Data/DownloadQueue/DownloadQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,41 @@ public final class DownloadQueue: ParallelismHeuristicDelegate {

// MARK: - Public methods

public func addPublicShareToQueue(file: File,
userId: Int,
driveFileManager: DriveFileManager,
publicShareProxy: PublicShareProxy,
itemIdentifier: NSFileProviderItemIdentifier? = nil) {
Log.downloadQueue("addPublicShareToQueue file:\(file.id)")
let file = file.freezeIfNeeded()

dispatchQueue.async {
guard !self.hasOperation(for: file.id) else {
Log.downloadQueue("Already in download queue, skipping \(file.id)", level: .error)
return
}

OperationQueueHelper.disableIdleTimer(true)

let operation = DownloadOperation(
file: file,
driveFileManager: driveFileManager,
urlSession: self.bestSession,
publicShareProxy: publicShareProxy,
itemIdentifier: itemIdentifier
)
operation.completionBlock = {
self.dispatchQueue.async {
self.operationsInQueue.removeValue(forKey: file.id)
self.publishFileDownloaded(fileId: file.id, error: operation.error)
OperationQueueHelper.disableIdleTimer(false, hasOperationsInQueue: !self.operationsInQueue.isEmpty)
}
}
self.operationQueue.addOperation(operation)
self.operationsInQueue[file.id] = operation
}
}

public func addToQueue(file: File,
userId: Int,
itemIdentifier: NSFileProviderItemIdentifier? = nil) {
Expand Down

0 comments on commit c26647f

Please sign in to comment.