Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fetch activities using listing #1242

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 6 additions & 155 deletions kDriveCore/Data/Cache/DriveFileManager/DriveFileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -540,163 +540,14 @@ public final class DriveFileManager {
}
}

public struct ActivitiesResult {
public var inserted: [File]
public var updated: [File]
public var deleted: [File]

public init(inserted: [File] = [], updated: [File] = [], deleted: [File] = []) {
self.inserted = inserted
self.updated = updated
self.deleted = deleted
}
}

public func fileActivities(file: ProxyFile,
from timestamp: Int? = nil) async throws -> (result: ActivitiesResult, responseAt: Int) {
// Get all pages and assemble
let fetchedFile = try file.resolve(within: self).freeze()
let timestamp = TimeInterval(timestamp ?? fetchedFile.responseAt)
var cursor: String?
var moreComing = true
var pagedActions = [String: FileActivityType]()
var pagedActivities = ActivitiesResult()
var responseAt = 0

while moreComing {
// Get activities page
let response = try await apiFetcher.fileActivities(
file: file,
from: Date(timeIntervalSince1970: timestamp),
cursor: cursor
)

let activities = response.validApiResponse.data
moreComing = response.validApiResponse.hasMore
cursor = response.validApiResponse.cursor
responseAt = response.validApiResponse.responseAt ?? Int(Date().timeIntervalSince1970)

try database.writeTransaction { writableRealm in
let cachedFile = try file.resolve(using: writableRealm)

// Apply activities to file
let results = apply(
activities: activities,
to: cachedFile,
pagedActions: &pagedActions,
timestamp: responseAt,
writableRealm: writableRealm
)
/// Fetch changes for a given directory and add it to DB
/// - With API V3 there is no notion of activities. We only do a listing for an existing cursor
public func fileActivities(file: ProxyFile) async throws {
var (_, nextCursor) = try await fileListing(in: file)

pagedActivities.inserted.insert(contentsOf: results.inserted, at: 0)
pagedActivities.updated.insert(contentsOf: results.updated, at: 0)
pagedActivities.deleted.insert(contentsOf: results.deleted, at: 0)
}
while nextCursor != nil {
(_, nextCursor) = try await fileListing(in: file)
}
return (pagedActivities, responseAt)
}

// swiftlint:disable:next cyclomatic_complexity
// TODO: Refactor
private func apply(activities: [FileActivity],
to file: File,
pagedActions: inout [String: FileActivityType],
timestamp: Int,
writableRealm: Realm) -> ActivitiesResult {
var insertedFiles = [File]()
var updatedFiles = [File]()
var deletedFiles = [File]()

for activity in activities {
let fileId = File.uid(driveId: file.driveId, fileId: activity.fileId)
if pagedActions[fileId] == nil {
switch activity.action {
case .fileDelete, .fileTrash:
if let file = writableRealm.object(ofType: File.self, forPrimaryKey: fileId), !file.isInvalidated {
deletedFiles.append(file.freeze())
}
removeFileInDatabase(fileUid: fileId, cascade: true, writableRealm: writableRealm)
if let file = activity.file {
deletedFiles.append(file)
}
pagedActions[fileId] = .fileDelete
case .fileMoveOut:
if let file = writableRealm.object(ofType: File.self, forPrimaryKey: fileId),
!file.isInvalidated,
let oldParent = file.parent {
oldParent.children.remove(file)
}
if let file = activity.file {
deletedFiles.append(file)
}
pagedActions[fileId] = .fileDelete
case .fileRename:
if let oldFile = writableRealm.object(ofType: File.self, forPrimaryKey: fileId),
!file.isInvalidated,
let renamedFile = activity.file {
try? renameCachedFile(updatedFile: renamedFile, oldFile: oldFile)
// If the file is a folder we have to copy the old attributes which are not returned by the API
keepCacheAttributesForFile(
newFile: renamedFile,
keepProperties: [.standard, .extras],
writableRealm: writableRealm
)
writableRealm.add(renamedFile, update: .modified)
file.children.insert(renamedFile)
renamedFile.applyLastModifiedDateToLocalFile()
updatedFiles.append(renamedFile)
pagedActions[fileId] = .fileUpdate
}
case .fileMoveIn, .fileRestore, .fileCreate:
if let newFile = activity.file {
keepCacheAttributesForFile(
newFile: newFile,
keepProperties: [.standard, .extras],
writableRealm: writableRealm
)
writableRealm.add(newFile, update: .modified)
// If was already had a local parent, remove it
if let file = writableRealm.object(ofType: File.self, forPrimaryKey: fileId),
!file.isInvalidated,
let oldParent = file.parent {
oldParent.children.remove(file)
}
file.children.insert(newFile)
insertedFiles.append(newFile)
pagedActions[fileId] = .fileCreate
}
case .fileFavoriteCreate, .fileFavoriteRemove, .fileUpdate, .fileShareCreate, .fileShareUpdate, .fileShareDelete,
.collaborativeFolderCreate, .collaborativeFolderUpdate, .collaborativeFolderDelete, .fileColorUpdate,
.fileColorDelete:
if let newFile = activity.file {
if newFile.isTrashed {
removeFileInDatabase(fileUid: fileId, cascade: true, writableRealm: writableRealm)
deletedFiles.append(newFile)
pagedActions[fileId] = .fileDelete
} else {
keepCacheAttributesForFile(
newFile: newFile,
keepProperties: [.standard, .extras],
writableRealm: writableRealm
)
writableRealm.add(newFile, update: .modified)
file.children.insert(newFile)
updatedFiles.append(newFile)
pagedActions[fileId] = .fileUpdate
}
}
default:
break
}
}
}
file.responseAt = timestamp

return ActivitiesResult(
inserted: insertedFiles.map { $0.freeze() },
updated: updatedFiles.map { $0.freeze() },
deleted: deletedFiles
)
}

func handleError(message: String, offlineFile file: File) {
Expand Down
3 changes: 1 addition & 2 deletions kDriveCore/UI/UIConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ public enum UIConstants {
action: .init(title: KDriveResourcesStrings.Localizable.buttonCancel) {
Task {
do {
let now = Date()
try await driveFileManager.undoAction(cancelId: cancelableResponse.id)
if let parentFile {
_ = try? await driveFileManager.fileActivities(file: parentFile, from: Int(now.timeIntervalSince1970))
_ = try? await driveFileManager.fileActivities(file: parentFile)
}

UIConstants.showSnackBar(message: cancelSuccessMessage)
Expand Down
Loading