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

Reflect File Provider domain sync status in tray icon (macOS VFS) #6930

Merged
merged 34 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d70a388
Modernise slotComputeOverallSyncStatus
claucambra Jul 16, 2024
744ac54
Add support for FILE_PROVIDER_DOMAIN_SYNC_STATE_CHANGE socket message…
claucambra Jul 16, 2024
87066c8
Bounce sync state change signals from socket controller in socket server
claucambra Jul 16, 2024
5237822
Add sets for actions, to be able to track multiple actions
claucambra Jul 16, 2024
885d9f3
Add method to report a change in sync state if applicable in FileProv…
claucambra Jul 16, 2024
3e6b207
Add method to insert new sync action in FileProviderExt
claucambra Jul 16, 2024
c189f29
Add method to mark action as error sync action in FileProviderExt
claucambra Jul 16, 2024
3f3f478
Add method to remove finished sync action in FileProviderExt
claucambra Jul 16, 2024
0c78594
Track sync actions in main FileProviderExt procedures
claucambra Jul 16, 2024
617ca1a
Add conformance to NextcloudFileProviderKit's EnumerationListener pro…
claucambra Jul 16, 2024
939d67b
Set self as listener for Enumerator in FileProviderExt
claucambra Jul 16, 2024
92f42bc
Lock and unlock when accessing sync actions in FileProviderExt to pro…
claucambra Jul 16, 2024
4490927
Remove pointless setStatusText in slotComputeOverallStatus
claucambra Jul 17, 2024
8bc1fce
Expose socket server in FileProvider class
claucambra Jul 17, 2024
3415f39
Expose account state in file provider socket controller
claucambra Jul 17, 2024
3877efb
Store latest sync state in file provider socket controller
claucambra Jul 17, 2024
b290611
Expose latest sync state in file provider socket controller
claucambra Jul 17, 2024
a434e65
Add support for SYNC_PREPARING arg in socket controller reportsyncstate
claucambra Jul 17, 2024
da7c511
Report sync state after initial connection of socket in socket contro…
claucambra Jul 17, 2024
fd7f1ce
Add file provider socket state struct
claucambra Jul 17, 2024
034fbb8
Add file provider socket state provider method in socket server
claucambra Jul 17, 2024
98dba86
Connect sync state changed signal in file provider socket server to c…
claucambra Jul 17, 2024
84d74bc
Process state of file provider account domains in slotComputeOverallS…
claucambra Jul 17, 2024
d2b5691
Append macOS vfs environment state strings to tray message when compu…
claucambra Jul 17, 2024
6e03e6a
Account for file provider states when setting tray icon
claucambra Jul 17, 2024
ee59bea
Do not report account sync state on socket controller if we haven't r…
claucambra Jul 18, 2024
6b14eed
Store and provide latest account's file provider sync state as there …
claucambra Jul 18, 2024
d3d19fd
Modernise problem account handling in slot compute overall sync state
claucambra Jul 18, 2024
ea0ae33
Add method to fileproviderxpc to check if the file provider extension…
claucambra Jul 19, 2024
3194edb
Check if the extension is reachable in owncloudgui compute sync status
claucambra Jul 19, 2024
1128d9d
Ensure all sync result status types are handled for file provider in …
claucambra Jul 19, 2024
58e6cdd
Provide state message in popup for vfs accounts that synced successfu…
claucambra Jul 19, 2024
87b2a84
Clean up unused components in file provider socket controller
claucambra Jul 19, 2024
23a8f08
Ensure file provider instance gets initialised at app launch WITHOUT …
claucambra Jul 19, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,29 @@ extension FileProviderExtension: NSFileProviderServicing, ChangeNotificationInte
)
ncAccount = nil
}

func updatedSyncStateReporting(oldActions: Set<UUID>) {
actionsLock.lock()

guard oldActions.isEmpty != syncActions.isEmpty else {
actionsLock.unlock()
return
}

let command = "FILE_PROVIDER_DOMAIN_SYNC_STATE_CHANGE"
var argument: String?
if oldActions.isEmpty, !syncActions.isEmpty {
argument = "SYNC_STARTED"
} else if !oldActions.isEmpty, syncActions.isEmpty {
argument = errorActions.isEmpty ? "SYNC_FINISHED" : "SYNC_FAILED"
errorActions = []
}

actionsLock.unlock()

guard let argument else { return }
Logger.fileProviderExtension.debug("Reporting sync \(argument)")
let message = command + ":" + argument + "\n"
socketClient?.sendMessage(message)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// FileProviderExtension+EnumerationListener.swift
// FileProviderExt
//
// Created by Claudio Cambra on 16/7/24.
//

import Foundation
import NextcloudFileProviderKit

extension FileProviderExtension: EnumerationListener {
func enumerationActionStarted(actionId: UUID) {
insertSyncAction(actionId)
}

func enumerationActionFinished(actionId: UUID) {
removeSyncAction(actionId)
}

func enumerationActionFailed(actionId: UUID, error: Error) {
insertErrorAction(actionId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ import OSLog
return LocalSocketClient(socketPath: socketPath.path, lineProcessor: lineProcessor)
}()

var syncActions = Set<UUID>()
var errorActions = Set<UUID>()
var actionsLock = NSLock()

// Whether or not we are going to recursively scan new folders when they are discovered.
// Apple's recommendation is that we should always scan the file hierarchy fully.
// This does lead to long load times when a file provider domain is initially configured.
Expand Down Expand Up @@ -67,6 +71,32 @@ import OSLog
)
}

func insertSyncAction(_ actionId: UUID) {
actionsLock.lock()
let oldActions = syncActions
syncActions.insert(actionId)
actionsLock.unlock()
updatedSyncStateReporting(oldActions: oldActions)
}

func insertErrorAction(_ actionId: UUID) {
actionsLock.lock()
let oldActions = syncActions
syncActions.remove(actionId)
errorActions.insert(actionId)
actionsLock.unlock()
updatedSyncStateReporting(oldActions: oldActions)
}

func removeSyncAction(_ actionId: UUID) {
actionsLock.lock()
let oldActions = syncActions
syncActions.remove(actionId)
errorActions.remove(actionId)
actionsLock.unlock()
updatedSyncStateReporting(oldActions: oldActions)
}

// MARK: - NSFileProviderReplicatedExtension protocol methods

func item(
Expand All @@ -88,6 +118,9 @@ import OSLog
request: NSFileProviderRequest,
completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void
) -> Progress {
let actionId = UUID()
insertSyncAction(actionId)

Logger.fileProviderExtension.debug(
"Received request to fetch contents of item with identifier: \(itemIdentifier.rawValue, privacy: .public)"
)
Expand All @@ -97,6 +130,7 @@ import OSLog
Logger.fileProviderExtension.error(
"Can't return contents for a specific version as this is not supported."
)
insertErrorAction(actionId)
completionHandler(
nil,
nil,
Expand All @@ -112,6 +146,7 @@ import OSLog
as account not set up yet.
"""
)
insertErrorAction(actionId)
completionHandler(nil, nil, NSFileProviderError(.notAuthenticated))
return Progress()
}
Expand All @@ -124,6 +159,7 @@ import OSLog
"""
)
completionHandler(nil, nil, NSFileProviderError(.noSuchItem))
insertErrorAction(actionId)
return Progress()
}

Expand All @@ -132,6 +168,7 @@ import OSLog
let (localUrl, updatedItem, error) = await item.fetchContents(
domain: self.domain, progress: progress
)
removeSyncAction(actionId)
completionHandler(localUrl, updatedItem, error)
}
return progress
Expand All @@ -147,6 +184,8 @@ import OSLog
NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?
) -> Void
) -> Progress {
let actionId = UUID()
insertSyncAction(actionId)

let tempId = itemTemplate.itemIdentifier.rawValue
Logger.fileProviderExtension.debug(
Expand All @@ -163,6 +202,7 @@ import OSLog
as account not set up yet
"""
)
insertErrorAction(actionId)
completionHandler(
itemTemplate,
NSFileProviderItemFields(),
Expand All @@ -184,9 +224,14 @@ import OSLog
ncAccount: ncAccount,
progress: progress
)

if error != nil {
insertErrorAction(actionId)
signalEnumerator(completionHandler: { _ in })
} else {
removeSyncAction(actionId)
}

completionHandler(
item ?? itemTemplate,
NSFileProviderItemFields(),
Expand All @@ -210,6 +255,8 @@ import OSLog
) -> Progress {
// An item was modified on disk, process the item's modification
// TODO: Handle finder things like tags, other possible item changed fields
let actionId = UUID()
insertSyncAction(actionId)

let identifier = item.itemIdentifier
let ocId = identifier.rawValue
Expand All @@ -224,6 +271,7 @@ import OSLog
Logger.fileProviderExtension.error(
"Not modifying item: \(ocId, privacy: .public) as account not set up yet."
)
insertErrorAction(actionId)
completionHandler(item, [], false, NSFileProviderError(.notAuthenticated))
return Progress()
}
Expand All @@ -232,6 +280,7 @@ import OSLog
Logger.fileProviderExtension.error(
"Not modifying item: \(ocId, privacy: .public) as item not found."
)
insertErrorAction(actionId)
completionHandler(item, [], false, NSFileProviderError(.noSuchItem))
return Progress()
}
Expand All @@ -249,9 +298,14 @@ import OSLog
domain: domain,
progress: progress
)

if error != nil {
insertErrorAction(actionId)
signalEnumerator(completionHandler: { _ in })
} else {
removeSyncAction(actionId)
}

completionHandler(modifiedItem ?? item, [], false, error)
}
return progress
Expand All @@ -264,6 +318,9 @@ import OSLog
request _: NSFileProviderRequest,
completionHandler: @escaping (Error?) -> Void
) -> Progress {
let actionId = UUID()
insertSyncAction(actionId)

Logger.fileProviderExtension.debug(
"Received delete request for item: \(identifier.rawValue, privacy: .public)"
)
Expand All @@ -272,6 +329,7 @@ import OSLog
Logger.fileProviderExtension.error(
"Not deleting item \(identifier.rawValue, privacy: .public), account not set up yet"
)
insertErrorAction(actionId)
completionHandler(NSFileProviderError(.notAuthenticated))
return Progress()
}
Expand All @@ -280,6 +338,7 @@ import OSLog
Logger.fileProviderExtension.error(
"Not deleting item \(identifier.rawValue, privacy: .public), item not found"
)
insertErrorAction(actionId)
completionHandler(NSFileProviderError(.noSuchItem))
return Progress()
}
Expand All @@ -288,7 +347,10 @@ import OSLog
Task {
let error = await item.delete()
if error != nil {
insertErrorAction(actionId)
signalEnumerator(completionHandler: { _ in })
} else {
removeSyncAction(actionId)
}
progress.completedUnitCount = 1
completionHandler(await item.delete())
Expand All @@ -311,7 +373,8 @@ import OSLog
ncAccount: ncAccount,
remoteInterface: ncKit,
domain: domain,
fastEnumeration: config.fastEnumerationEnabled
fastEnumeration: config.fastEnumerationEnabled,
listener: self
)
}

Expand Down Expand Up @@ -342,6 +405,8 @@ import OSLog
materialisedEnumerator.enumerateItems(for: materialisedObserver, startingAt: startingPage)
}

// MARK: - Helper functions
claucambra marked this conversation as resolved.
Show resolved Hide resolved

func signalEnumerator(completionHandler: @escaping (_ error: Error?) -> Void) {
guard let fpManager = NSFileProviderManager(for: domain) else {
Logger.fileProviderExtension.error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
5307A6E62965C6FA001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E52965C6FA001E0C6A /* NextcloudKit */; };
5307A6E82965DAD8001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E72965DAD8001E0C6A /* NextcloudKit */; };
531522822B8E01C6002E31BE /* ShareTableItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 531522812B8E01C6002E31BE /* ShareTableItemView.xib */; };
532572082C4690340068DEC3 /* FileProviderExtension+EnumerationListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532572072C4690340068DEC3 /* FileProviderExtension+EnumerationListener.swift */; };
5350E4E92B0C534A00F276CB /* ClientCommunicationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */; };
5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */; };
5358F2B92BAA0F5300E3C729 /* NextcloudCapabilitiesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5358F2B82BAA0F5300E3C729 /* NextcloudCapabilitiesKit */; };
Expand Down Expand Up @@ -148,6 +149,7 @@

/* Begin PBXFileReference section */
531522812B8E01C6002E31BE /* ShareTableItemView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShareTableItemView.xib; sourceTree = "<group>"; };
532572072C4690340068DEC3 /* FileProviderExtension+EnumerationListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+EnumerationListener.swift"; sourceTree = "<group>"; };
5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClientCommunicationProtocol.h; sourceTree = "<group>"; };
5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientCommunicationService.swift; sourceTree = "<group>"; };
5350E4EA2B0C9CE100F276CB /* FileProviderExt-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FileProviderExt-Bridging-Header.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -294,6 +296,7 @@
53D666602B70C9A70042C03D /* FileProviderConfig.swift */,
538E396C27F4765000FA63D5 /* FileProviderExtension.swift */,
53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */,
532572072C4690340068DEC3 /* FileProviderExtension+EnumerationListener.swift */,
5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */,
536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */,
538E397327F4765000FA63D5 /* FileProviderExt.entitlements */,
Expand Down Expand Up @@ -671,6 +674,7 @@
535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */,
537630952B860D560026BFAB /* FPUIExtensionServiceSource.swift in Sources */,
5350E4E92B0C534A00F276CB /* ClientCommunicationService.swift in Sources */,
532572082C4690340068DEC3 /* FileProviderExtension+EnumerationListener.swift in Sources */,
5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ Application::Application(int &argc, char **argv)
AccountSetupCommandLineManager::destroy();

#if defined(BUILD_FILE_PROVIDER_MODULE)
_fileProvider.reset(new Mac::FileProvider);
Mac::FileProvider::instance();
#endif
}

Expand Down
8 changes: 0 additions & 8 deletions src/gui/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,6 @@ class Folder;
class ShellExtensionsServer;
class SslErrorDialog;

#ifdef Q_OS_MACOS
namespace Mac {
class FileProvider;
}
#endif

/**
* @brief The Application class
* @ingroup gui
Expand Down Expand Up @@ -163,8 +157,6 @@ protected slots:
QScopedPointer<FolderMan> _folderManager;
#if defined(Q_OS_WIN)
QScopedPointer<ShellExtensionsServer> _shellExtensionsServer;
#elif defined(Q_OS_MACOS)
QScopedPointer<Mac::FileProvider> _fileProvider;
#endif
};

Expand Down
1 change: 1 addition & 0 deletions src/gui/macOS/fileprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#pragma once

#include <QObject>

Check failure on line 17 in src/gui/macOS/fileprovider.h

View workflow job for this annotation

GitHub Actions / build

src/gui/macOS/fileprovider.h:17:10 [clang-diagnostic-error]

'QObject' file not found

#include "fileproviderdomainmanager.h"
#include "fileprovidersocketserver.h"
Expand All @@ -41,6 +41,7 @@

[[nodiscard]] FileProviderXPC *xpc() const;
[[nodiscard]] FileProviderDomainManager *domainManager() const;
[[nodiscard]] FileProviderSocketServer *socketServer() const;

private slots:
void configureXPC();
Expand Down
5 changes: 5 additions & 0 deletions src/gui/macOS/fileprovider_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,10 @@
return _domainManager.get();
}

FileProviderSocketServer *FileProvider::socketServer() const
{
return _socketServer.get();
}

} // namespace Mac
} // namespace OCC
Loading
Loading