diff --git a/ownCloudSDK/Bookmark/OCBookmark+DataItem.m b/ownCloudSDK/Bookmark/OCBookmark+DataItem.m index 6c0f88d0..97ddea7a 100644 --- a/ownCloudSDK/Bookmark/OCBookmark+DataItem.m +++ b/ownCloudSDK/Bookmark/OCBookmark+DataItem.m @@ -20,7 +20,7 @@ #import "OCDataTypes.h" #import "OCResource.h" #import "OCMacros.h" -#import "OCCoreManager.h" +#import "OCPlatform.h" @implementation OCBookmark (DataItem) @@ -36,7 +36,7 @@ - (OCDataItemReference)dataItemReference - (OCDataItemVersion)dataItemVersion { - if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum) + if (OCPlatform.current.memoryConfiguration != OCPlatformMemoryConfigurationMinimum) { OCResource *avatarResource = OCTypedCast(self.avatar, OCResource); NSString *avatarVersion = ((avatarResource != nil) ? avatarResource.version : @""); diff --git a/ownCloudSDK/Bookmark/OCBookmark.h b/ownCloudSDK/Bookmark/OCBookmark.h index ac187051..4fadff43 100644 --- a/ownCloudSDK/Bookmark/OCBookmark.h +++ b/ownCloudSDK/Bookmark/OCBookmark.h @@ -86,6 +86,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeCapability:(OCBookmarkCapability)capability; - (BOOL)hasCapability:(OCBookmarkCapability)capability; +#pragma mark - Metadata storage +@property(strong,nullable) NSURL *metaDataStorageURL; //!< URL to store bookmark data in (f.ex. certificates, avatar images, ..) + +- (nullable NSError *)storeMetadata; + #pragma mark - Certificate approval - (NSNotificationName)certificateUserApprovalUpdateNotificationName; //!< Notification that gets sent if the bookmark's certificate user-approved status changed - (void)postCertificateUserApprovalUpdateNotification; //!< Posts a .certificateUserApprovalUpdateNotificationName notification diff --git a/ownCloudSDK/Bookmark/OCBookmark.m b/ownCloudSDK/Bookmark/OCBookmark.m index 5eedd7d1..3d24c505 100644 --- a/ownCloudSDK/Bookmark/OCBookmark.m +++ b/ownCloudSDK/Bookmark/OCBookmark.m @@ -34,6 +34,7 @@ @interface OCBookmark () OCIPCNotificationName _bookmarkAuthUpdateNotificationName; id _avatar; + NSURL *_avatarDataURL; NSData *_avatarData; NSString *_lastUsername; @@ -246,19 +247,64 @@ - (OCCertificate *)primaryCertificate return (primaryCertificate); } +#pragma mark - Metadata storage +- (NSError *)storeMetadata +{ + NSError *error = nil; + + @synchronized(self) + { + if (_metaDataStorageURL != nil) + { + if ([NSFileManager.defaultManager createDirectoryAtURL:_metaDataStorageURL withIntermediateDirectories:YES attributes:nil error:&error]) + { + if ((_avatarDataURL != nil) && (_avatarData != nil)) + { + [_avatarData writeToURL:_avatarDataURL options:NSDataWritingAtomic error:&error]; + } + } + } + } + + return (error); +} + #pragma mark - Avatar +- (NSData *)avatarData +{ + @synchronized(self) + { + if ((_avatarData == nil) && (_avatarDataURL != nil)) + { + _avatarData = [[NSData alloc] initWithContentsOfURL:_avatarDataURL]; + } + } + + return (_avatarData); +} + - (id)avatar { @synchronized(self) { - if ((_avatar == nil) && (_avatarData != nil)) + if (_avatar == nil) { - @try + NSData *avatarData = _avatarData; + + if ((avatarData == nil) && (_avatarDataURL != nil)) { - _avatar = [NSKeyedUnarchiver unarchiveObjectWithData:_avatarData]; + avatarData = [[NSData alloc] initWithContentsOfURL:_avatarDataURL]; } - @catch (NSException *exception) + + if (avatarData != nil) { + @try + { + _avatar = [NSKeyedUnarchiver unarchiveObjectWithData:avatarData]; + } + @catch (NSException *exception) + { + } } } @@ -304,6 +350,15 @@ - (void)setAvatar:(id)avatar _avatar = (avatarData != nil) ? avatar : nil; _avatarData = avatarData; + + if ((avatarData != nil) && (_metaDataStorageURL != nil)) + { + _avatarDataURL = [_metaDataStorageURL URLByAppendingPathComponent:@"avatarData"]; + } + else + { + _avatarDataURL = nil; + } } } @@ -415,6 +470,8 @@ - (instancetype)initWithCoder:(NSCoder *)decoder _originURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"originURL"]; + _metaDataStorageURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"metaDataStorageURL"]; + _capabilities = [decoder decodeObjectOfClasses:[NSSet setWithObjects:NSSet.class, NSString.class, nil] forKey:@"capabilities"]; _certificateStore = [decoder decodeObjectOfClass:OCCertificateStore.class forKey:@"certificateStore"]; @@ -435,6 +492,7 @@ - (instancetype)initWithCoder:(NSCoder *)decoder _authenticationValidationDate = [decoder decodeObjectOfClass:NSDate.class forKey:@"authenticationValidationDate"]; _avatarData = [decoder decodeObjectOfClass:NSData.class forKey:@"avatarData"]; + _avatarDataURL = [decoder decodeObjectOfClass:NSURL.class forKey:@"avatarDataURL"]; _databaseVersion = [decoder decodeIntegerForKey:@"databaseVersion"]; @@ -462,6 +520,8 @@ - (void)encodeWithCoder:(NSCoder *)coder [coder encodeObject:_originURL forKey:@"originURL"]; + [coder encodeObject:_metaDataStorageURL forKey:@"metaDataStorageURL"]; + [coder encodeObject:_capabilities forKey:@"capabilities"]; [coder encodeObject:_certificateStore forKey:@"certificateStore"]; @@ -469,7 +529,11 @@ - (void)encodeWithCoder:(NSCoder *)coder [coder encodeObject:_authenticationMethodIdentifier forKey:@"authenticationMethodIdentifier"]; [coder encodeObject:_authenticationValidationDate forKey:@"authenticationValidationDate"]; - [coder encodeObject:_avatarData forKey:@"avatarData"]; + if (_avatarDataURL == nil) + { + [coder encodeObject:_avatarData forKey:@"avatarData"]; + } + [coder encodeObject:_avatarDataURL forKey:@"avatarDataURL"]; [coder encodeInteger:_databaseVersion forKey:@"databaseVersion"]; diff --git a/ownCloudSDK/Connection/OCConnection+Upload.m b/ownCloudSDK/Connection/OCConnection+Upload.m index abe6cf91..1b0f992d 100644 --- a/ownCloudSDK/Connection/OCConnection+Upload.m +++ b/ownCloudSDK/Connection/OCConnection+Upload.m @@ -27,7 +27,7 @@ #import "OCHTTPResponse+DAVError.h" #import "NSProgress+OCExtensions.h" #import "OCCore+SyncEngine.h" -#import "OCCoreManager.h" +#import "OCPlatform.h" typedef NSString* OCUploadInfoKey; typedef NSString* OCUploadInfoTask; @@ -241,7 +241,7 @@ - (OCProgress *)_tusUploadFileFromURL:(NSURL *)sourceURL withName:(NSString *)fi { NSNumber *capabilitiesTusMaxChunkSize; - if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum) + if (OCPlatform.current.memoryConfiguration != OCPlatformMemoryConfigurationMinimum) { // Memory configuration is NOT minimum, so avoid splitting up files into chunks if // possible, which requires additional memory and could mean going over a tight memory @@ -296,7 +296,7 @@ - (OCProgress *)_continueTusJob:(OCTUSJob *)tusJob lastTask:(NSString *)lastTask return (nil); } - if (OCCoreManager.sharedCoreManager.memoryConfiguration == OCCoreMemoryConfigurationMinimum) + if (OCPlatform.current.memoryConfiguration == OCPlatformMemoryConfigurationMinimum) { // Memory configuration is minimum, so use just Creation instead of Creation-With-Upload // to avoid splitting up files into chunks if possible, which requires additional memory diff --git a/ownCloudSDK/Core/ItemList/OCCore+ItemList.m b/ownCloudSDK/Core/ItemList/OCCore+ItemList.m index f78ebe9a..463aaa69 100644 --- a/ownCloudSDK/Core/ItemList/OCCore+ItemList.m +++ b/ownCloudSDK/Core/ItemList/OCCore+ItemList.m @@ -51,11 +51,11 @@ - (NSUInteger)parallelItemListTaskCount { switch (self.memoryConfiguration) { - case OCCoreMemoryConfigurationMinimum: + case OCPlatformMemoryConfigurationMinimum: return (1); break; - case OCCoreMemoryConfigurationDefault: + case OCPlatformMemoryConfigurationDefault: default: return (2); break; diff --git a/ownCloudSDK/Core/OCCore+ItemUpdates.m b/ownCloudSDK/Core/OCCore+ItemUpdates.m index ef136a3e..11be2090 100644 --- a/ownCloudSDK/Core/OCCore+ItemUpdates.m +++ b/ownCloudSDK/Core/OCCore+ItemUpdates.m @@ -124,21 +124,6 @@ - (void)performUpdatesForAddedItems:(nullable NSArray *)addedItems }]; } - // In parallel: remove thumbnails from in-memory cache for removed items - OCWaitWillStartTask(cacheUpdatesGroup); - - dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ - for (OCItem *removeItem in removedItems) - { - if (removeItem.fileID != nil) - { - [self->_thumbnailCache removeObjectForKey:removeItem.fileID]; - } - } - - OCWaitDidFinishTask(cacheUpdatesGroup); - }); - // Wait for updates to complete OCWaitForCompletion(cacheUpdatesGroup); } diff --git a/ownCloudSDK/Core/OCCore.h b/ownCloudSDK/Core/OCCore.h index 741d1002..78b660e8 100644 --- a/ownCloudSDK/Core/OCCore.h +++ b/ownCloudSDK/Core/OCCore.h @@ -43,6 +43,7 @@ #import "OCDataSourceComposition.h" #import "OCDataItemPresentable.h" #import "OCShareRole.h" +#import "OCPlatform.h" @class OCCore; @class OCItem; @@ -95,12 +96,6 @@ typedef NS_ENUM(NSUInteger, OCCoreConnectionStatusSignalState) OCCoreConnectionStatusSignalStateForceTrue //!< Signal state is force true (overriding any false states) } __attribute__((enum_extensibility(closed))); -typedef NS_ENUM(NSUInteger, OCCoreMemoryConfiguration) -{ - OCCoreMemoryConfigurationDefault, //!< Default memory configuration - OCCoreMemoryConfigurationMinimum //!< Try using only the minimum amount of memory needed -} __attribute__((enum_extensibility(closed))); - typedef NS_ENUM(NSUInteger,OCCoreAvailableOfflineCoverage) { OCCoreAvailableOfflineCoverageNone, //!< Item is not targeted by available offline item policy @@ -156,7 +151,7 @@ typedef id OCCoreItemTracking; OCConnection *_connection; BOOL _attemptConnect; - OCCoreMemoryConfiguration _memoryConfiguration; + OCPlatformMemoryConfiguration _memoryConfiguration; NSMutableArray *_queries; @@ -229,7 +224,6 @@ typedef id OCCoreItemTracking; OCSignalManager *_signalManager; - OCCache *_thumbnailCache; NSMutableDictionary *> *_pendingThumbnailRequests; NSMutableDictionary *_remoteSyncEngineTriggerAcknowledgements; @@ -310,7 +304,7 @@ typedef id OCCoreItemTracking; @property(readonly) OCVault *vault; //!< Vault managing storage and database access for this core. @property(readonly) OCConnection *connection; //!< Connection used by the core to make requests to the server. -@property(assign,nonatomic) OCCoreMemoryConfiguration memoryConfiguration; +@property(assign,nonatomic) OCPlatformMemoryConfiguration memoryConfiguration; @property(readonly,nonatomic) OCCoreState state; @property(copy) OCCoreStateChangedHandler stateChangedHandler; diff --git a/ownCloudSDK/Core/OCCore.m b/ownCloudSDK/Core/OCCore.m index a8911836..0c5b019b 100644 --- a/ownCloudSDK/Core/OCCore.m +++ b/ownCloudSDK/Core/OCCore.m @@ -327,8 +327,6 @@ - (instancetype)initWithBookmark:(OCBookmark *)bookmark _claimTokensByClaimIdentifier = [NSMapTable strongToWeakObjectsMapTable]; - _thumbnailCache = [OCCache new]; - _queue = dispatch_queue_create("OCCore work queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); _connectivityQueue = dispatch_queue_create("OCCore connectivity queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); @@ -410,7 +408,7 @@ - (instancetype)initWithBookmark:(OCBookmark *)bookmark [self addSignalProvider:_connectingStatusSignalProvider]; [self addSignalProvider:_connectionStatusSignalProvider]; - self.memoryConfiguration = OCCoreManager.sharedCoreManager.memoryConfiguration; + self.memoryConfiguration = OCPlatform.current.memoryConfiguration; [self startIPCObservation]; } @@ -755,7 +753,7 @@ - (void)__attemptConnect } // If app provider is available and enabled - if (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum) // only load app providers in memory configurations other than minimum + if (self.memoryConfiguration != OCPlatformMemoryConfigurationMinimum) // only load app providers in memory configurations other than minimum { OCAppProvider *latestSupportedAppProvider = self.connection.capabilities.latestSupportedAppProvider; @@ -1043,22 +1041,11 @@ - (OCMessageQueue *)messageQueue } #pragma mark - Memory configuration -- (void)setMemoryConfiguration:(OCCoreMemoryConfiguration)memoryConfiguration +- (void)setMemoryConfiguration:(OCPlatformMemoryConfiguration)memoryConfiguration { _memoryConfiguration = memoryConfiguration; self.vault.resourceManager.memoryConfiguration = memoryConfiguration; - - switch (_memoryConfiguration) - { - case OCCoreMemoryConfigurationDefault: - _thumbnailCache.countLimit = OCCacheLimitNone; - break; - - case OCCoreMemoryConfigurationMinimum: - _thumbnailCache.countLimit = 1; - break; - } } #pragma mark - Inter-Process change notification/handling diff --git a/ownCloudSDK/Core/Resources/Manager/OCResourceManager.h b/ownCloudSDK/Core/Resources/Manager/OCResourceManager.h index 28cb49b4..75d3237d 100644 --- a/ownCloudSDK/Core/Resources/Manager/OCResourceManager.h +++ b/ownCloudSDK/Core/Resources/Manager/OCResourceManager.h @@ -40,7 +40,7 @@ typedef void(^OCResourceRetrieveCompletionHandler)(NSError * _Nullable error, OC @property(weak,nullable) id storage; @property(weak,nullable) OCCore *core; -@property(assign,nonatomic) OCCoreMemoryConfiguration memoryConfiguration; +@property(assign,nonatomic) OCPlatformMemoryConfiguration memoryConfiguration; // @property(assign) NSUInteger maximumConcurrentJobs; //!< Maximum number of jobs to work on in parallel. A value of 0 indicates no limit. diff --git a/ownCloudSDK/Core/Resources/Manager/OCResourceManager.m b/ownCloudSDK/Core/Resources/Manager/OCResourceManager.m index 7c681073..f5739f24 100644 --- a/ownCloudSDK/Core/Resources/Manager/OCResourceManager.m +++ b/ownCloudSDK/Core/Resources/Manager/OCResourceManager.m @@ -56,18 +56,21 @@ - (instancetype)initWithStorage:(id)storage return (self); } -- (void)setMemoryConfiguration:(OCCoreMemoryConfiguration)memoryConfiguration +- (void)setMemoryConfiguration:(OCPlatformMemoryConfiguration)memoryConfiguration { _memoryConfiguration = memoryConfiguration; switch (_memoryConfiguration) { - case OCCoreMemoryConfigurationDefault: + case OCPlatformMemoryConfigurationDefault: + if (_cache == nil) { + _cache = [OCCache new]; + } _cache.countLimit = OCCacheLimitNone; break; - case OCCoreMemoryConfigurationMinimum: - _cache.countLimit = 1; + case OCPlatformMemoryConfigurationMinimum: + _cache = nil; // Do not perform any caching break; } } diff --git a/ownCloudSDK/Platforms/OCPlatform.h b/ownCloudSDK/Platforms/OCPlatform.h index 8918ccb6..ddab8dd7 100644 --- a/ownCloudSDK/Platforms/OCPlatform.h +++ b/ownCloudSDK/Platforms/OCPlatform.h @@ -34,10 +34,20 @@ #define OCView NSView #endif /* TARGET_OS_OSX */ +typedef NS_ENUM(NSUInteger, OCPlatformMemoryConfiguration) +{ + OCPlatformMemoryConfigurationDefault, //!< Default memory configuration + OCPlatformMemoryConfigurationMinimum //!< Try using only the minimum amount of memory needed +} __attribute__((enum_extensibility(closed))); + NS_ASSUME_NONNULL_BEGIN @interface OCPlatform : NSObject +@property(readonly,strong,nonatomic,class) OCPlatform *current; + +@property(assign) OCPlatformMemoryConfiguration memoryConfiguration; + @end NS_ASSUME_NONNULL_END diff --git a/ownCloudSDK/Platforms/OCPlatform.m b/ownCloudSDK/Platforms/OCPlatform.m index 07026d0c..a0b60f8c 100644 --- a/ownCloudSDK/Platforms/OCPlatform.m +++ b/ownCloudSDK/Platforms/OCPlatform.m @@ -17,7 +17,38 @@ */ #import "OCPlatform.h" +#import "OCAppIdentity.h" +#import "OCSQLiteDB.h" @implementation OCPlatform ++ (OCPlatform *)current +{ + static OCPlatform *currentPlatform; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + currentPlatform = [OCPlatform new]; + }); + + return (currentPlatform); +} + +- (instancetype)init +{ + if ((self = [super init]) != nil) + { + _memoryConfiguration = OCPlatformMemoryConfigurationDefault; + + if ([OCAppIdentity.sharedAppIdentity.componentIdentifier isEqual:OCAppComponentIdentifierFileProviderExtension] || + [OCAppIdentity.sharedAppIdentity.componentIdentifier isEqual:OCAppComponentIdentifierFileProviderUIExtension] || + [OCAppIdentity.sharedAppIdentity.componentIdentifier isEqual:OCAppComponentIdentifierShareExtension]) + { + _memoryConfiguration = OCPlatformMemoryConfigurationMinimum; + } + } + + return (self); +} + @end diff --git a/ownCloudSDK/Resource Management/OCBookmarkManager.m b/ownCloudSDK/Resource Management/OCBookmarkManager.m index 427a332f..c15aefba 100644 --- a/ownCloudSDK/Resource Management/OCBookmarkManager.m +++ b/ownCloudSDK/Resource Management/OCBookmarkManager.m @@ -21,6 +21,7 @@ #import "OCLogger.h" #import "OCDataSourceArray.h" #import "OCBookmark+DataItem.h" +#import "OCVault.h" @implementation OCBookmarkManager { @@ -106,6 +107,13 @@ - (void)loadBookmarks { OCBookmark *existingBookmark = nil; + if (loadedBookmark.metaDataStorageURL == nil) + { + // Old-style bookmark with internal/memory metadata storage - transition it to external storage + loadedBookmark.metaDataStorageURL = [OCVault bookmarkMetadataURLForVaultUUID:loadedBookmark.uuid]; // Provide bookmark storage location + loadedBookmark.avatar = loadedBookmark.avatar; // Re-set avatar to force generation of _avatarDataURL + } + for (OCBookmark *bookmark in existingBookmarks) { if ([bookmark.uuid isEqual:loadedBookmark.uuid]) @@ -206,6 +214,16 @@ - (void)saveBookmarks OCLogError(@"Error archiving bookmarks: %@", OCLogPrivate(exception)); } + for (OCBookmark *bookmark in _bookmarks) + { + NSError *error; + + if ((error = [bookmark storeMetadata]) != nil) + { + OCLogError(@"Error storing metadata for bookmark: %@ (for %@)", error, bookmark); + } + } + [bookmarkData writeToURL:self.bookmarkStoreURL atomically:YES]; } } diff --git a/ownCloudSDK/Resource Management/OCCoreManager.h b/ownCloudSDK/Resource Management/OCCoreManager.h index 935571b1..b117e1dc 100644 --- a/ownCloudSDK/Resource Management/OCCoreManager.h +++ b/ownCloudSDK/Resource Management/OCCoreManager.h @@ -42,7 +42,6 @@ typedef void(^OCCoreManagerOfflineOperation)(OCBookmark *bookmark, dispatch_bloc @property(class, readonly, strong, nonatomic) OCCoreManager *sharedCoreManager; @property(assign) BOOL postFileProviderNotifications; -@property(assign,nonatomic) OCCoreMemoryConfiguration memoryConfiguration; @property(readonly, nonatomic, strong) NSArray *activeRunIdentifiers; diff --git a/ownCloudSDK/Resource Management/OCCoreManager.m b/ownCloudSDK/Resource Management/OCCoreManager.m index 3993fef6..19bf476f 100644 --- a/ownCloudSDK/Resource Management/OCCoreManager.m +++ b/ownCloudSDK/Resource Management/OCCoreManager.m @@ -411,29 +411,6 @@ - (void)_runNextOfflineOperationForBookmark:(OCBookmark *)bookmark return (nil); } -#pragma mark - Memory configuration -- (void)setMemoryConfiguration:(OCCoreMemoryConfiguration)memoryConfiguration -{ - @synchronized (self) - { - _memoryConfiguration = memoryConfiguration; - - [_coresByUUID enumerateKeysAndObjectsUsingBlock:^(NSUUID * _Nonnull key, OCCore * _Nonnull core, BOOL * _Nonnull stop) { - core.memoryConfiguration = memoryConfiguration; - }]; - - switch (memoryConfiguration) - { - case OCCoreMemoryConfigurationMinimum: - [OCSQLiteDB setMemoryLimit:(1 * 1024 * 512)]; // Set 0.5 MB memory limit for SQLite; - break; - - default: break; - } - - } -} - #pragma mark - Active run identifiers - (NSArray *)activeRunIdentifiers { diff --git a/ownCloudSDK/Settings/OCClassSettings.m b/ownCloudSDK/Settings/OCClassSettings.m index 3f2a0a42..963ea280 100644 --- a/ownCloudSDK/Settings/OCClassSettings.m +++ b/ownCloudSDK/Settings/OCClassSettings.m @@ -39,16 +39,23 @@ + (instancetype)sharedSettings { static dispatch_once_t onceToken; static OCClassSettings *sharedClassSettings = nil; - + __block BOOL addDefaultSources = NO; + dispatch_once(&onceToken, ^{ sharedClassSettings = [OCClassSettings new]; + addDefaultSources = YES; + }); + if (addDefaultSources) + { + // Add sources outside dispatch_once, so that calling OCLog / OCClassSettings.sharedSettings will not + // lead to a crash due to a call of dispatch_once from within the same dispatch_once [sharedClassSettings addSource:[OCClassSettingsFlatSourceManagedConfiguration new]]; [sharedClassSettings addSource:[OCClassSettingsUserPreferences sharedUserPreferences]]; [sharedClassSettings addSource:[OCClassSettingsFlatSourcePostBuild sharedPostBuildSettings]]; [sharedClassSettings addSource:[[OCClassSettingsFlatSourceEnvironment alloc] initWithPrefix:@"oc:"]]; - }); - + } + return(sharedClassSettings); } @@ -104,7 +111,37 @@ - (void)registerDefaults:(NSDictionary *)defaults metada _registeredMetaDataCollectionsByIdentifier[identifier] = registeredMetaDataCollections; } - [registeredMetaDataCollections addObject:metaData]; + if (OCPlatform.current.memoryConfiguration == OCPlatformMemoryConfigurationMinimum) + { + @autoreleasepool { + NSMutableDictionary *filteredCollection = [NSMutableDictionary new]; + + for (OCClassSettingsKey settingsKey in metaData) + { + OCClassSettingsMetadata settingsMetadata = metaData[settingsKey]; + id mdType = settingsMetadata[OCClassSettingsMetadataKeyType]; + id mdPossibleKeys = settingsMetadata[OCClassSettingsMetadataKeyPossibleKeys]; + + if ((mdType != nil) || (mdPossibleKeys != nil)) + { + NSMutableDictionary *filteredMetadata = [NSMutableDictionary new]; + filteredMetadata[OCClassSettingsMetadataKeyType] = mdType; + filteredMetadata[OCClassSettingsMetadataKeyPossibleKeys] = mdPossibleKeys; + + filteredCollection[settingsKey] = [[NSDictionary alloc] initWithDictionary:filteredMetadata]; + } + } + + if (filteredCollection.count > 0) + { + [registeredMetaDataCollections addObject:[[NSDictionary alloc] initWithDictionary:filteredCollection]]; + } + } + } + else + { + [registeredMetaDataCollections addObject:metaData]; + } } [self clearSourceCache]; diff --git a/ownCloudSDK/Vaults/Database/OCDatabase.m b/ownCloudSDK/Vaults/Database/OCDatabase.m index 4d0e8dd3..1ca09d69 100644 --- a/ownCloudSDK/Vaults/Database/OCDatabase.m +++ b/ownCloudSDK/Vaults/Database/OCDatabase.m @@ -36,7 +36,7 @@ #import "OCAsyncSequentialQueue.h" #import "NSString+OCSQLTools.h" #import "OCItemPolicy.h" -#import "OCCoreManager.h" +#import "OCPlatform.h" #import "NSArray+OCSegmentedProcessing.h" #import "OCSQLiteDB+Internal.h" @@ -50,7 +50,7 @@ @interface OCDatabase () OCAsyncSequentialQueue *_openQueue; NSInteger _openCount; - OCCoreMemoryConfiguration _memoryConfiguration; + OCPlatformMemoryConfiguration _memoryConfiguration; NSMutableSet *_knownInvalidSyncRecordIDs; } @@ -79,7 +79,7 @@ - (instancetype)initWithURL:(NSURL *)databaseURL _selectItemRowsSQLQueryPrefix = @"SELECT mdID, mdTimestamp, syncAnchor, itemData"; - _memoryConfiguration = OCCoreManager.sharedCoreManager.memoryConfiguration; + _memoryConfiguration = OCPlatform.current.memoryConfiguration; _progressBySyncRecordID = [NSMutableDictionary new]; _ephermalParametersBySyncRecordID = [NSMutableDictionary new]; @@ -336,7 +336,7 @@ - (void)addCacheItems:(NSArray *)items syncAnchor:(OCSyncAnchor)syncA completionHandler(self, error); } }]]; - } segmentSize:((_memoryConfiguration == OCCoreMemoryConfigurationMinimum) ? 10 : 200)]; + } segmentSize:((_memoryConfiguration == OCPlatformMemoryConfigurationMinimum) ? 10 : 200)]; } - (void)updateCacheItems:(NSArray *)items syncAnchor:(OCSyncAnchor)syncAnchor completionHandler:(OCDatabaseCompletionHandler)completionHandler @@ -452,7 +452,7 @@ - (void)updateCacheItems:(NSArray *)items syncAnchor:(OCSyncAnchor)sy completionHandler(self, error); } }]]; - } segmentSize:((_memoryConfiguration == OCCoreMemoryConfigurationMinimum) ? 10 : 200)]; + } segmentSize:((_memoryConfiguration == OCPlatformMemoryConfigurationMinimum) ? 10 : 200)]; } - (void)removeCacheItems:(NSArray *)items syncAnchor:(OCSyncAnchor)syncAnchor completionHandler:(OCDatabaseCompletionHandler)completionHandler diff --git a/ownCloudSDK/Vaults/Database/SQLite/OCSQLiteDB.m b/ownCloudSDK/Vaults/Database/SQLite/OCSQLiteDB.m index d79ca037..64771193 100644 --- a/ownCloudSDK/Vaults/Database/SQLite/OCSQLiteDB.m +++ b/ownCloudSDK/Vaults/Database/SQLite/OCSQLiteDB.m @@ -28,6 +28,7 @@ #import "NSProgress+OCExtensions.h" #import "OCCoreManager.h" #import "OCSQLiteCollationLocalized.h" +#import "OCPlatform.h" #import "OCExtension+License.h" @@ -49,6 +50,11 @@ @implementation OCSQLiteDB + (void)load { [[OCExtensionManager sharedExtensionManager] addExtension:[OCExtension licenseExtensionWithIdentifier:@"license.ISRunLoopThread" bundleOfClass:[OCRunLoopThread class] title:@"ISRunLoopThread" resourceName:@"ISRunLoopThread" fileExtension:@"LICENSE"]]; + + if (OCPlatform.current.memoryConfiguration == OCPlatformMemoryConfigurationMinimum) + { + [OCSQLiteDB setMemoryLimit:(1 * 1024 * 512)]; // Set 0.5 MB memory limit for SQLite; + } } + (BOOL)allowConcurrentFileAccess @@ -72,7 +78,7 @@ - (instancetype)init _journalMode = OCSQLiteJournalModeDelete; // (SQLite default) - self.cacheStatements = (OCCoreManager.sharedCoreManager.memoryConfiguration != OCCoreMemoryConfigurationMinimum); + self.cacheStatements = (OCPlatform.current.memoryConfiguration != OCPlatformMemoryConfigurationMinimum); #if TARGET_OS_IOS [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shrinkMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; diff --git a/ownCloudSDK/Vaults/OCVault.h b/ownCloudSDK/Vaults/OCVault.h index 1b46ceb2..a78273a0 100644 --- a/ownCloudSDK/Vaults/OCVault.h +++ b/ownCloudSDK/Vaults/OCVault.h @@ -44,6 +44,7 @@ [Bookmark UUID].ockvs - OCVault.keyValueStoreURL + "BookmarkMetadata"/ - OCVault.bookmarkMetadataURL and +bookmarkMetadataURLForVaultUUID: (folder where (larger) bookmark metadata blobs are stored) "Erasure"/ - OCVault.wipeContainerRootURL (folder whose contents should be erased) "HTTPPipeline"/ - OCVault.httpPipelineRootURL @@ -53,6 +54,7 @@ "TemporaryDownloads"/ - OCVault.temporaryDownloadURL [Random UUID] (temporary files for downloads) + "messageQueue.dat" - OCMessageQueue.globalQueue KVS "postBuildSettings.plist" - OCClassSettingsFlatSourcePostBuild storage @@ -102,6 +104,7 @@ typedef BOOL(^OCVaultCompactSelector)(OCSyncAnchor _Nullable syncAnchor, OCItem NSURL *_filesRootURL; NSURL *_httpPipelineRootURL; NSURL *_temporaryDownloadURL; + NSURL *_bookmarkMetadataURL; NSURL *_wipeContainerRootURL; NSURL *_wipeContainerFilesRootURL; @@ -140,6 +143,7 @@ typedef BOOL(^OCVaultCompactSelector)(OCSyncAnchor _Nullable syncAnchor, OCItem @property(nullable,readonly,nonatomic) NSURL *drivesRootURL; //!< The vault's root URL for drive folders @property(nullable,readonly,nonatomic) NSURL *httpPipelineRootURL; //!< The vault's root URL for HTTP pipeline data @property(nullable,readonly,nonatomic) NSURL *temporaryDownloadURL; //!< The vault's root URL for temporarily downloaded files. +@property(nullable,readonly,nonatomic) NSURL *bookmarkMetadataURL; //!< The vault's root URL for bookmark metadata files. @property(nullable,readonly,nonatomic) NSURL *wipeContainerRootURL; //!< The vault's rootURL subfolder for items to erase. @property(nullable,readonly,nonatomic) NSURL *wipeContainerFilesRootURL; //!< The vault's filesRootURL subfolder for items to erase. @@ -200,6 +204,8 @@ typedef BOOL(^OCVaultCompactSelector)(OCSyncAnchor _Nullable syncAnchor, OCItem + (nullable NSString *)databaseFilePathRelativeToRootPathForVaultUUID:(NSUUID *)uuid; ++ (nullable NSURL *)bookmarkMetadataURLForVaultUUID:(NSUUID *)uuid; + @property(nullable,readonly,nonatomic,class) NSURL *httpPipelineRootURL; #pragma mark - URL/path parser diff --git a/ownCloudSDK/Vaults/OCVault.m b/ownCloudSDK/Vaults/OCVault.m index 9a427bb5..aa33db30 100644 --- a/ownCloudSDK/Vaults/OCVault.m +++ b/ownCloudSDK/Vaults/OCVault.m @@ -280,6 +280,15 @@ - (NSURL *)temporaryDownloadURL return (_temporaryDownloadURL); } +- (NSURL *)bookmarkMetadataURL +{ + if (_bookmarkMetadataURL == nil) + { + _bookmarkMetadataURL = [self.class bookmarkMetadataURLForVaultUUID:self.uuid]; + } + return (_bookmarkMetadataURL); +} + - (NSURL *)wipeContainerRootURL { if (_wipeContainerRootURL == nil) @@ -1110,6 +1119,11 @@ + (NSString *)keyValueStoreFilePathRelativeToRootPathForVaultUUID:(NSUUID *)uuid return ([uuid.UUIDString stringByAppendingString:@".ockvs"]); } ++ (nullable NSURL *)bookmarkMetadataURLForVaultUUID:(NSUUID *)uuid +{ + return ([[self rootURLForUUID:uuid] URLByAppendingPathComponent:@"BookmarkMetadata" isDirectory:YES]); +} + + (NSURL *)httpPipelineRootURL { return [[[OCAppIdentity sharedAppIdentity] appGroupContainerURL] URLByAppendingPathComponent:OCVaultPathHTTPPipeline];