Skip to content

Commit 853aecc

Browse files
committed
Merge branch 'release/2.2.4'
2 parents e8de927 + 8ab25f1 commit 853aecc

34 files changed

+786
-221
lines changed

Cryptomator.xcodeproj/project.pbxproj

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
4A03258125A36B7D00E63D7A /* UIViewController+Preview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A03258025A36B7D00E63D7A /* UIViewController+Preview.swift */; };
1414
4A0337CA2726FF46001753B7 /* MoveVaultCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0337C92726FF46001753B7 /* MoveVaultCoordinator.swift */; };
1515
4A03BD6527DF4AEE00B96FA7 /* WorkflowFactoryLocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A03BD6427DF4AEE00B96FA7 /* WorkflowFactoryLocking.swift */; };
16+
4A079FB928084134009AD932 /* WorkingSetEnumerationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A079FB828084134009AD932 /* WorkingSetEnumerationTests.swift */; };
1617
4A09BFC62684D599000E40AB /* VaultDetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A09BFC52684D599000E40AB /* VaultDetailItem.swift */; };
1718
4A09E54C27071F3C0056D32A /* ErrorMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A09E54B27071F3C0056D32A /* ErrorMapperTests.swift */; };
1819
4A09E54E27071F4F0056D32A /* ErrorMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A09E54D27071F4F0056D32A /* ErrorMapper.swift */; };
@@ -486,6 +487,7 @@
486487
4A0337C92726FF46001753B7 /* MoveVaultCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveVaultCoordinator.swift; sourceTree = "<group>"; };
487488
4A03BD6427DF4AEE00B96FA7 /* WorkflowFactoryLocking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkflowFactoryLocking.swift; sourceTree = "<group>"; };
488489
4A0698692619EF9C00A67F30 /* CryptomatorCommon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = CryptomatorCommon; sourceTree = "<group>"; };
490+
4A079FB828084134009AD932 /* WorkingSetEnumerationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkingSetEnumerationTests.swift; sourceTree = "<group>"; };
489491
4A09BFC52684D599000E40AB /* VaultDetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultDetailItem.swift; sourceTree = "<group>"; };
490492
4A09E54B27071F3C0056D32A /* ErrorMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorMapperTests.swift; sourceTree = "<group>"; };
491493
4A09E54D27071F4F0056D32A /* ErrorMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorMapper.swift; sourceTree = "<group>"; };
@@ -877,6 +879,8 @@
877879
74C2FCEC27E2197D00BB527A /* PCloudKeychainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PCloudKeychainTests.swift; sourceTree = "<group>"; };
878880
74D365B9268B5DB0005ECD69 /* FilesAppUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilesAppUtil.swift; sourceTree = "<group>"; };
879881
74DFF9DA26DF87A0009981ED /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
882+
74E93B742810109E0047A116 /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/Localizable.strings; sourceTree = "<group>"; };
883+
74E93B75281010E50047A116 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = "<group>"; };
880884
74F5DC1726D928A100AFE989 /* Configuration.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Configuration.storekit; sourceTree = "<group>"; };
881885
74F5DC1926D92A1D00AFE989 /* StoreKitTestCertificate.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = StoreKitTestCertificate.cer; sourceTree = "<group>"; };
882886
74F5DC1B26DCD2FB00AFE989 /* StoreObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreObserver.swift; sourceTree = "<group>"; };
@@ -1041,6 +1045,7 @@
10411045
4A4F47F224B875070033328B /* URL+NameCollisionExtensionTests.swift */,
10421046
4AE5196427F48D6600BA6E4A /* WorkflowDependencyFactoryTests.swift */,
10431047
4AE5196627F495BF00BA6E4A /* WorkflowDependencyTasksCollectionMock.swift */,
1048+
4A079FB828084134009AD932 /* WorkingSetEnumerationTests.swift */,
10441049
4A9C8E0227A016CF000063E4 /* WorkingSetObserverTests.swift */,
10451050
4ADC66BE27A44557002E6CC7 /* XCTestCase+Promises.swift */,
10461051
4AF69E2924ACCED000A7174C /* DB */,
@@ -2007,12 +2012,14 @@
20072012
Base,
20082013
de,
20092014
ar,
2015+
bn,
20102016
ca,
20112017
cs,
20122018
el,
20132019
es,
20142020
fr,
20152021
hi,
2022+
hr,
20162023
id,
20172024
it,
20182025
ja,
@@ -2211,6 +2218,7 @@
22112218
4ADC66C727A95E67002E6CC7 /* UnlockMonitorTaskExecutorMock.swift in Sources */,
22122219
4A797F9824AC9A1B007DDBE1 /* CustomCloudProviderMockTests.swift in Sources */,
22132220
4AAD444727E26D1800D16707 /* UploadTaskManagerMock.swift in Sources */,
2221+
4A079FB928084134009AD932 /* WorkingSetEnumerationTests.swift in Sources */,
22142222
4AB1C33C265E9DBC00DC7A49 /* CloudTaskExecutorTestCase.swift in Sources */,
22152223
4AE5196727F495BF00BA6E4A /* WorkflowDependencyTasksCollectionMock.swift in Sources */,
22162224
4AC1157827F5BEFD0023F51B /* Promise+AllIgnoringResultsTests.swift in Sources */,
@@ -2666,12 +2674,14 @@
26662674
742679FA26A56B33004C61BC /* en */,
26672675
742679FE26A578E2004C61BC /* de */,
26682676
74AE94EF27A0282300D71AEC /* ar */,
2677+
74E93B742810109E0047A116 /* bn */,
26692678
74AE94F027A0283500D71AEC /* ca */,
26702679
74BDA62B26CE8AE1007FBD72 /* cs */,
26712680
74267A0326A5793E004C61BC /* el */,
26722681
74267A0426A57944004C61BC /* es */,
26732682
74267A0526A57947004C61BC /* fr */,
26742683
74A1B13D2726A9E60098224B /* hi */,
2684+
74E93B75281010E50047A116 /* hr */,
26752685
74AE94F127A0285400D71AEC /* id */,
26762686
74267A0A26A5795C004C61BC /* it */,
26772687
74267A0B26A57960004C61BC /* ja */,
@@ -2852,7 +2862,7 @@
28522862
GCC_WARN_UNUSED_FUNCTION = YES;
28532863
GCC_WARN_UNUSED_VARIABLE = YES;
28542864
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
2855-
MARKETING_VERSION = 2.2.3;
2865+
MARKETING_VERSION = 2.2.4;
28562866
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
28572867
MTL_FAST_MATH = YES;
28582868
ONLY_ACTIVE_ARCH = YES;
@@ -2914,7 +2924,7 @@
29142924
GCC_WARN_UNUSED_FUNCTION = YES;
29152925
GCC_WARN_UNUSED_VARIABLE = YES;
29162926
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
2917-
MARKETING_VERSION = 2.2.3;
2927+
MARKETING_VERSION = 2.2.4;
29182928
MTL_ENABLE_DEBUG_INFO = NO;
29192929
MTL_FAST_MATH = YES;
29202930
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200";

Cryptomator/AppDelegate.swift

+11-7
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
4545
VaultDBManager.shared.recoverMissingFileProviderDomains().catch { error in
4646
DDLogError("Recover missing FileProvider domains failed with error: \(error)")
4747
}
48-
// Clean up
49-
do {
50-
let webDAVAccountUIDs = try CloudProviderAccountDBManager.shared.getAllAccountUIDs(for: .webDAV(type: .custom))
51-
try WebDAVAuthenticator.removeUnusedWebDAVCredentials(existingAccountUIDs: webDAVAccountUIDs)
52-
} catch {
53-
DDLogError("Clean up unused WebDAV Credentials failed with error: \(error)")
54-
}
48+
cleanup()
5549

5650
// Set up cloud storage services
5751
CloudProviderDBManager.shared.useBackgroundSession = false
@@ -114,4 +108,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
114108
func applicationWillTerminate(_ application: UIApplication) {
115109
SKPaymentQueue.default().remove(StoreObserver.shared)
116110
}
111+
112+
private func cleanup() {
113+
_ = VaultDBManager.shared.removeAllUnusedFileProviderDomains()
114+
do {
115+
let webDAVAccountUIDs = try CloudProviderAccountDBManager.shared.getAllAccountUIDs(for: .webDAV(type: .custom))
116+
try WebDAVAuthenticator.removeUnusedWebDAVCredentials(existingAccountUIDs: webDAVAccountUIDs)
117+
} catch {
118+
DDLogError("Clean up unused WebDAV Credentials failed with error: \(error)")
119+
}
120+
}
117121
}

Cryptomator/Settings/SettingsViewModel.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,11 @@ class SettingsViewModel: TableViewModel<SettingsSection> {
152152
}
153153

154154
private func notifyFileProviderAboutLogLevelUpdate() {
155-
let getProxyPromise: Promise<LogLevelUpdating> = fileProviderConnector.getProxy(serviceName: LogLevelUpdatingService.name, domain: nil)
156-
getProxyPromise.then { proxy in
157-
proxy.logLevelUpdated()
155+
let getXPCPromise: Promise<XPC<LogLevelUpdating>> = fileProviderConnector.getXPC(serviceName: LogLevelUpdatingService.name, domain: nil)
156+
getXPCPromise.then { xpc in
157+
xpc.proxy.logLevelUpdated()
158+
}.always {
159+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
158160
}
159161
}
160162
}

Cryptomator/VaultDetail/ChangePassword/ChangePasswordViewModel.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,11 @@ class ChangePasswordViewModel: TableViewModel<ChangePasswordSection>, ChangePass
169169

170170
private func lockVault() -> Promise<Void> {
171171
let domainIdentifier = NSFileProviderDomainIdentifier(vaultAccount.vaultUID)
172-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
173-
return getProxyPromise.then { proxy -> Void in
174-
proxy.lockVault(domainIdentifier: domainIdentifier)
172+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
173+
return getXPCPromise.then { xpc -> Void in
174+
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
175+
}.always {
176+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
175177
}
176178
}
177179
}

Cryptomator/VaultDetail/KeepUnlocked/VaultKeepUnlockedViewModel.swift

+10-11
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,13 @@ class VaultKeepUnlockedViewModel: TableViewModel<VaultKeepUnlockedSection>, Vaul
8282

8383
func gracefulLockVault() -> Promise<Void> {
8484
let domainIdentifier = NSFileProviderDomainIdentifier(vaultUID)
85-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
86-
return getProxyPromise.then { proxy in
87-
proxy.gracefulLockVault(domainIdentifier: domainIdentifier)
85+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
86+
return getXPCPromise.then { xpc in
87+
xpc.proxy.gracefulLockVault(domainIdentifier: domainIdentifier)
8888
}.then {
8989
self.vaultInfo.vaultIsUnlocked.value = false
90+
}.always {
91+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
9092
}
9193
}
9294

@@ -116,17 +118,14 @@ class VaultKeepUnlockedViewModel: TableViewModel<VaultKeepUnlockedSection>, Vaul
116118

117119
private func getVaultIsUnlocked() -> Promise<Bool> {
118120
let domainIdentifier = NSFileProviderDomainIdentifier(vaultUID)
119-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
120-
return getProxyPromise.then { proxy in
121-
proxy.getIsUnlockedVault(domainIdentifier: domainIdentifier)
121+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
122+
return getXPCPromise.then { xpc in
123+
return xpc.proxy.getIsUnlockedVault(domainIdentifier: domainIdentifier)
124+
}.always {
125+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
122126
}
123127
}
124128

125-
private func getVaultLockingProxy() -> Promise<VaultLocking> {
126-
let domainIdentifier = NSFileProviderDomainIdentifier(vaultUID)
127-
return fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
128-
}
129-
130129
private func assertVaultIsLocked() -> Promise<Void> {
131130
return getVaultIsUnlocked().then { vaultIsUnlocked -> Void in
132131
if vaultIsUnlocked {

Cryptomator/VaultDetail/MoveVault/MoveVaultViewModel.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ class MoveVaultViewModel: ChooseFolderViewModel, MoveVaultViewModelProtocol {
7373

7474
private func lockVault() -> Promise<Void> {
7575
let domainIdentifier = NSFileProviderDomainIdentifier(vaultInfo.vaultUID)
76-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
77-
return getProxyPromise.then { proxy -> Void in
78-
proxy.lockVault(domainIdentifier: domainIdentifier)
76+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
77+
return getXPCPromise.then { xpc -> Void in
78+
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
79+
self.fileProviderConnector.invalidateXPC(xpc)
7980
}
8081
}
8182

Cryptomator/VaultDetail/VaultDetailViewModel.swift

+7-6
Original file line numberDiff line numberDiff line change
@@ -215,20 +215,21 @@ class VaultDetailViewModel: VaultDetailViewModelProtocol {
215215

216216
func lockVault() -> Promise<Void> {
217217
let domainIdentifier = NSFileProviderDomainIdentifier(vaultUID)
218-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
219-
return getProxyPromise.then { proxy -> Void in
220-
proxy.lockVault(domainIdentifier: domainIdentifier)
218+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
219+
220+
return getXPCPromise.then { xpc -> Void in
221+
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
221222
self.vaultInfo.vaultIsUnlocked.value = false
222223
}
223224
}
224225

225226
func refreshVaultStatus() -> Promise<Void> {
226227
let domainIdentifier = NSFileProviderDomainIdentifier(vaultUID)
227-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
228+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
228229
switchCellViewModel?.isOn.value = biometricalUnlockEnabled
229-
return getProxyPromise.then { proxy in
230+
return getXPCPromise.then { xpc in
230231
return wrap { handler in
231-
proxy.getIsUnlockedVault(domainIdentifier: domainIdentifier, reply: handler)
232+
xpc.proxy.getIsUnlockedVault(domainIdentifier: domainIdentifier, reply: handler)
232233
}
233234
}.then { isUnlocked -> Void in
234235
self.vaultInfo.vaultIsUnlocked.value = isUnlocked

Cryptomator/VaultList/VaultCellViewModel.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ class VaultCellViewModel: TableViewCellViewModel, VaultCellViewModelProtocol {
4242

4343
func lockVault() -> Promise<Void> {
4444
let domainIdentifier = NSFileProviderDomainIdentifier(vault.vaultUID)
45-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
46-
return getProxyPromise.then { proxy in
47-
proxy.lockVault(domainIdentifier: domainIdentifier)
45+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
46+
return getXPCPromise.then { xpc in
47+
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
4848
}.then {
4949
self.setVaultUnlockStatus(unlocked: false)
5050
}.catch { error in
5151
self.errorPublisher.send(error)
52+
}.always {
53+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
5254
}
5355
}
5456

Cryptomator/VaultList/VaultListViewModel.swift

+11-6
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,22 @@ class VaultListViewModel: ViewModel, VaultListViewModelProtocol {
9393

9494
func lockVault(_ vaultInfo: VaultInfo) -> Promise<Void> {
9595
let domainIdentifier = NSFileProviderDomainIdentifier(vaultInfo.vaultUID)
96-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
97-
return getProxyPromise.then { proxy in
98-
proxy.lockVault(domainIdentifier: domainIdentifier)
96+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domainIdentifier: domainIdentifier)
97+
return getXPCPromise.then { xpc in
98+
xpc.proxy.lockVault(domainIdentifier: domainIdentifier)
9999
}.then {
100100
vaultInfo.vaultIsUnlocked.value = false
101+
}.always {
102+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
101103
}
102104
}
103105

104106
func refreshVaultLockStates() -> Promise<Void> {
105-
let getProxyPromise: Promise<VaultLocking> = fileProviderConnector.getProxy(serviceName: VaultLockingService.name, domain: nil)
106-
return getProxyPromise.then { proxy in
107+
let getXPCPromise: Promise<XPC<VaultLocking>> = fileProviderConnector.getXPC(serviceName: VaultLockingService.name, domain: nil)
108+
109+
return getXPCPromise.then { xpc in
107110
return wrap { handler in
108-
proxy.getUnlockedVaultDomainIdentifiers(reply: handler)
111+
xpc.proxy.getUnlockedVaultDomainIdentifiers(reply: handler)
109112
}
110113
}.then { unlockedVaultDomainIdentifiers -> Void in
111114
unlockedVaultDomainIdentifiers.forEach { domainIdentifier in
@@ -119,6 +122,8 @@ class VaultListViewModel: ViewModel, VaultListViewModelProtocol {
119122
}.forEach { vaultCellViewModel in
120123
vaultCellViewModel.setVaultUnlockStatus(unlocked: false)
121124
}
125+
}.always {
126+
self.fileProviderConnector.invalidateXPC(getXPCPromise)
122127
}
123128
}
124129

CryptomatorCommon/Sources/CryptomatorCommonCore/FileProviderXPC/FileProviderConnector.swift

+60-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,23 @@ import Foundation
1212
import Promises
1313

1414
public protocol FileProviderConnector {
15-
func getProxy<T>(serviceName: NSFileProviderServiceName, domainIdentifier: NSFileProviderDomainIdentifier) -> Promise<T>
16-
func getProxy<T>(serviceName: NSFileProviderServiceName, domain: NSFileProviderDomain?) -> Promise<T>
15+
func getXPC<T>(serviceName: NSFileProviderServiceName, domain: NSFileProviderDomain?) -> Promise<XPC<T>>
16+
func getXPC<T>(serviceName: NSFileProviderServiceName, domainIdentifier: NSFileProviderDomainIdentifier) -> Promise<XPC<T>>
17+
}
18+
19+
public extension FileProviderConnector {
20+
func invalidateXPC<T>(_ xpc: XPC<T>) {
21+
xpc.doneHandler()
22+
}
23+
24+
func invalidateXPC<T>(_ xpcPromise: Promise<XPC<T>>) {
25+
xpcPromise.then(invalidateXPC)
26+
}
27+
}
28+
29+
public struct XPC<T> {
30+
public let proxy: T
31+
let doneHandler: () -> Void
1732
}
1833

1934
public enum FileProviderXPCConnectorError: Error {
@@ -25,6 +40,15 @@ public enum FileProviderXPCConnectorError: Error {
2540
}
2641

2742
public class FileProviderXPCConnector: FileProviderConnector {
43+
public func getXPC<T>(serviceName: NSFileProviderServiceName, domainIdentifier: NSFileProviderDomainIdentifier) -> Promise<XPC<T>> {
44+
return NSFileProviderManager.getDomains().then { domains in
45+
guard let domain = domains.first(where: { $0.identifier == domainIdentifier }) else {
46+
throw FileProviderXPCConnectorError.domainNotFound
47+
}
48+
return self.getXPC(serviceName: serviceName, domain: domain)
49+
}
50+
}
51+
2852
public static let shared = FileProviderXPCConnector()
2953

3054
public func getProxy<T>(serviceName: NSFileProviderServiceName, domainIdentifier: NSFileProviderDomainIdentifier) -> Promise<T> {
@@ -36,6 +60,40 @@ public class FileProviderXPCConnector: FileProviderConnector {
3660
}
3761
}
3862

63+
public func getXPC<T>(serviceName: NSFileProviderServiceName, domain: NSFileProviderDomain?) -> Promise<XPC<T>> {
64+
var url = NSFileProviderManager.default.documentStorageURL
65+
if let domain = domain {
66+
url.appendPathComponent(domain.pathRelativeToDocumentStorage)
67+
}
68+
return wrap { handler in
69+
FileManager.default.getFileProviderServicesForItem(at: url, completionHandler: handler)
70+
}.then { services -> Promise<NSXPCConnection?> in
71+
if let desiredService = services?[serviceName] {
72+
return desiredService.getFileProviderConnection()
73+
} else {
74+
return Promise(FileProviderXPCConnectorError.serviceNotSupported)
75+
}
76+
}.then { connection -> XPC<T> in
77+
guard let connection = connection else {
78+
throw FileProviderXPCConnectorError.connectionIsNil
79+
}
80+
guard let type = T.self as AnyObject as? Protocol else {
81+
throw FileProviderXPCConnectorError.typeMismatch
82+
}
83+
connection.remoteObjectInterface = NSXPCInterface(with: type)
84+
connection.resume()
85+
let rawProxy = connection.remoteObjectProxyWithErrorHandler { errorAccessingRemoteObject in
86+
DDLogError("remoteObjectProxy failed with error: \(errorAccessingRemoteObject)")
87+
}
88+
guard let proxy = rawProxy as? T else {
89+
throw FileProviderXPCConnectorError.rawProxyCastingFailed
90+
}
91+
return XPC(proxy: proxy, doneHandler: {
92+
connection.invalidate()
93+
})
94+
}
95+
}
96+
3997
public func getProxy<T>(serviceName: NSFileProviderServiceName, domain: NSFileProviderDomain?) -> Promise<T> {
4098
var url = NSFileProviderManager.default.documentStorageURL
4199
if let domain = domain {

0 commit comments

Comments
 (0)