@@ -12,16 +12,23 @@ import PCloudSDKSwift
12
12
13
13
public protocol CloudProviderManager {
14
14
func getProvider( with accountUID: String ) throws -> CloudProvider
15
+ func getBackgroundSessionProvider( with accountUID: String , sessionIdentifier: String ) throws -> CloudProvider
15
16
}
16
17
17
18
public protocol CloudProviderUpdating {
18
19
func providerShouldUpdate( with accountUID: String )
19
20
}
20
21
22
+ struct CachedProvider {
23
+ let accountUID : String
24
+ let provider : CloudProvider
25
+ let backgroundSessionIdentifier : String ?
26
+ var isBackgroundSession : Bool { backgroundSessionIdentifier != nil }
27
+ }
28
+
21
29
public class CloudProviderDBManager : CloudProviderManager , CloudProviderUpdating {
22
- static var cachedProvider = [ String : CloudProvider ] ( )
30
+ static var cachedProvider = [ CachedProvider ] ( )
23
31
public static let shared = CloudProviderDBManager ( accountManager: CloudProviderAccountDBManager . shared)
24
- public var useBackgroundSession = true
25
32
let accountManager : CloudProviderAccountDBManager
26
33
27
34
private let maxPageSizeForFileProvider = 500
@@ -31,84 +38,129 @@ public class CloudProviderDBManager: CloudProviderManager, CloudProviderUpdating
31
38
}
32
39
33
40
public func getProvider( with accountUID: String ) throws -> CloudProvider {
34
- if let provider = CloudProviderDBManager . cachedProvider [ accountUID] {
35
- return provider
41
+ if let entry = CloudProviderDBManager . cachedProvider. first ( where: {
42
+ $0. accountUID == accountUID && !$0. isBackgroundSession
43
+ } ) {
44
+ return entry. provider
36
45
}
37
46
return try createProvider ( for: accountUID)
38
47
}
39
48
49
+ public func getBackgroundSessionProvider( with accountUID: String , sessionIdentifier: String ) throws -> any CloudProvider {
50
+ if let entry = CloudProviderDBManager . cachedProvider. first ( where: {
51
+ $0. accountUID == accountUID && $0. backgroundSessionIdentifier == sessionIdentifier
52
+ } ) {
53
+ return entry. provider
54
+ }
55
+ return try createBackgroundSessionProvider ( for: accountUID, sessionIdentifier: sessionIdentifier)
56
+ }
57
+
40
58
/**
41
59
Creates and returns a cloud provider for the given `accountUID`.
42
-
43
- If `useBackgroundURLSession` is set to `true`, the number of returned items from a `fetchItemList(forFolderAt:pageToken:)` call is limited to 500.
44
- This is necessary because otherwise memory limit problems can occur with folders with many items in the `FileProviderExtension` where a background `URLSession` is used.
45
60
*/
46
61
func createProvider( for accountUID: String ) throws -> CloudProvider {
47
62
let cloudProviderType = try accountManager. getCloudProviderType ( for: accountUID)
48
63
let provider : CloudProvider
49
64
switch cloudProviderType {
50
65
case . dropbox:
51
66
let credential = DropboxCredential ( tokenUID: accountUID)
52
- provider = DropboxCloudProvider ( credential: credential, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : . max)
67
+ provider = DropboxCloudProvider ( credential: credential, maxPageSize: . max)
53
68
case . googleDrive:
54
69
let credential = GoogleDriveCredential ( userID: accountUID)
55
- provider = try GoogleDriveCloudProvider ( credential: credential,
56
- useBackgroundSession: useBackgroundSession,
57
- maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : . max)
70
+ provider = try GoogleDriveCloudProvider ( credential: credential, maxPageSize: . max)
58
71
case . oneDrive:
59
72
let credential = try OneDriveCredential ( with: accountUID)
60
- provider = try OneDriveCloudProvider ( credential: credential,
61
- useBackgroundSession: useBackgroundSession,
62
- maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : . max)
73
+ provider = try OneDriveCloudProvider ( credential: credential, maxPageSize: . max)
63
74
case . pCloud:
64
- provider = try createPCloudProvider ( for: accountUID)
75
+ let credential = try PCloudCredential ( userID: accountUID)
76
+ let client = PCloud . createClient ( with: credential. user)
77
+ provider = try PCloudCloudProvider ( client: client)
65
78
case . webDAV:
66
- guard let credential = WebDAVCredentialManager . shared. getCredentialFromKeychain ( with: accountUID) else {
79
+ let credential = try getWebDAVCredential ( for: accountUID)
80
+ let client = WebDAVClient ( credential: credential)
81
+ provider = try WebDAVProvider ( with: client, maxPageSize: . max)
82
+ case . localFileSystem:
83
+ guard let rootURL = try LocalFileSystemBookmarkManager . getBookmarkedRootURL ( for: accountUID) else {
67
84
throw CloudProviderAccountError . accountNotFoundError
68
85
}
69
- let client : WebDAVClient
70
- if useBackgroundSession {
71
- client = WebDAVClient . withBackgroundSession ( credential: credential, sharedContainerIdentifier: CryptomatorConstants . appGroupName)
72
- } else {
73
- client = WebDAVClient ( credential: credential)
74
- }
75
- provider = try WebDAVProvider ( with: client, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : . max)
86
+ provider = try LocalFileSystemProvider ( rootURL: rootURL, maxPageSize: . max)
87
+ case . s3:
88
+ let credential = try getS3Credential ( for: accountUID)
89
+ provider = try S3CloudProvider ( credential: credential)
90
+ }
91
+ CloudProviderDBManager . cachedProvider. append (
92
+ . init(
93
+ accountUID: accountUID,
94
+ provider: provider,
95
+ backgroundSessionIdentifier: nil
96
+ )
97
+ )
98
+ return provider
99
+ }
100
+
101
+ /**
102
+ Creates and returns a cloud provider for the given `accountUID` using a background URLSession with the given `sessionIdentifier`.
103
+
104
+ The number of returned items from a `fetchItemList(forFolderAt:pageToken:)` call is limited to 500.
105
+ This is necessary because otherwise memory limit problems can occur with folders with many items in the `FileProviderExtension` where a background `URLSession` is used.
106
+ */
107
+ func createBackgroundSessionProvider( for accountUID: String , sessionIdentifier: String ) throws -> CloudProvider {
108
+ let cloudProviderType = try accountManager. getCloudProviderType ( for: accountUID)
109
+ let provider : CloudProvider
110
+
111
+ switch cloudProviderType {
112
+ case . dropbox:
113
+ let credential = DropboxCredential ( tokenUID: accountUID)
114
+ provider = DropboxCloudProvider ( credential: credential, maxPageSize: maxPageSizeForFileProvider)
115
+ case . googleDrive:
116
+ let credential = GoogleDriveCredential ( userID: accountUID)
117
+ provider = try GoogleDriveCloudProvider . withBackgroundSession ( credential: credential, maxPageSize: maxPageSizeForFileProvider, sessionIdentifier: sessionIdentifier)
118
+ case . oneDrive:
119
+ let credential = try OneDriveCredential ( with: accountUID)
120
+ provider = try OneDriveCloudProvider . withBackgroundSession ( credential: credential, maxPageSize: maxPageSizeForFileProvider, sessionIdentifier: sessionIdentifier)
121
+ case . pCloud:
122
+ let credential = try PCloudCredential ( userID: accountUID)
123
+ let client = PCloud . createBackgroundClient ( with: credential. user, sessionIdentifier: sessionIdentifier)
124
+ provider = try PCloudCloudProvider ( client: client)
125
+ case . webDAV:
126
+ let credential = try getWebDAVCredential ( for: accountUID)
127
+ let client = WebDAVClient . withBackgroundSession ( credential: credential, sessionIdentifier: sessionIdentifier, sharedContainerIdentifier: CryptomatorConstants . appGroupName)
128
+ provider = try WebDAVProvider ( with: client, maxPageSize: maxPageSizeForFileProvider)
76
129
case . localFileSystem:
77
130
guard let rootURL = try LocalFileSystemBookmarkManager . getBookmarkedRootURL ( for: accountUID) else {
78
131
throw CloudProviderAccountError . accountNotFoundError
79
132
}
80
- provider = try LocalFileSystemProvider ( rootURL: rootURL, maxPageSize: useBackgroundSession ? maxPageSizeForFileProvider : . max )
133
+ provider = try LocalFileSystemProvider ( rootURL: rootURL, maxPageSize: maxPageSizeForFileProvider)
81
134
case . s3:
82
- provider = try createS3Provider ( for: accountUID)
135
+ let credential = try getS3Credential ( for: accountUID)
136
+ provider = try S3CloudProvider . withBackgroundSession ( credential: credential, sharedContainerIdentifier: CryptomatorConstants . appGroupName)
83
137
}
84
- CloudProviderDBManager . cachedProvider [ accountUID] = provider
138
+ CloudProviderDBManager . cachedProvider. append (
139
+ . init(
140
+ accountUID: accountUID,
141
+ provider: provider,
142
+ backgroundSessionIdentifier: sessionIdentifier
143
+ )
144
+ )
85
145
return provider
86
146
}
87
147
88
- private func createS3Provider ( for accountUID: String ) throws -> CloudProvider {
148
+ private func getS3Credential ( for accountUID: String ) throws -> S3Credential {
89
149
guard let credential = S3CredentialManager . shared. getCredential ( with: accountUID) else {
90
150
throw CloudProviderAccountError . accountNotFoundError
91
151
}
92
- if useBackgroundSession {
93
- return try S3CloudProvider . withBackgroundSession ( credential: credential, sharedContainerIdentifier: CryptomatorConstants . appGroupName)
94
- } else {
95
- return try S3CloudProvider ( credential: credential)
96
- }
152
+ return credential
97
153
}
98
154
99
- private func createPCloudProvider( for accountUID: String ) throws -> CloudProvider {
100
- let credential = try PCloudCredential ( userID: accountUID)
101
- let client : PCloudClient
102
- if useBackgroundSession {
103
- client = PCloud . createBackgroundClient ( with: credential. user, sharedContainerIdentifier: CryptomatorConstants . appGroupName)
104
- } else {
105
- client = PCloud . createClient ( with: credential. user)
155
+ private func getWebDAVCredential( for accountUID: String ) throws -> WebDAVCredential {
156
+ guard let credential = WebDAVCredentialManager . shared. getCredentialFromKeychain ( with: accountUID) else {
157
+ throw CloudProviderAccountError . accountNotFoundError
106
158
}
107
- return try PCloudCloudProvider ( client : client )
159
+ return credential
108
160
}
109
161
110
162
public func providerShouldUpdate( with accountUID: String ) {
111
- CloudProviderDBManager . cachedProvider [ accountUID] = nil
163
+ CloudProviderDBManager . cachedProvider. removeAll ( where : { $0 . accountUID == accountUID } )
112
164
// call XPCService for FileProvider
113
165
}
114
166
}
0 commit comments