| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| #import "remoting/ios/data_store.h" |
| |
| @interface DataStore (Private) |
| - (NSString*)itemArchivePath; |
| @end |
| |
| @implementation DataStore { |
| @private |
| NSMutableArray* _allHosts; |
| NSManagedObjectContext* _context; |
| NSManagedObjectModel* _model; |
| } |
| |
| // Create or Get a static data store |
| + (DataStore*)sharedStore { |
| static DataStore* sharedStore = nil; |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, |
| ^{ sharedStore = [[super allocWithZone:nil] init]; }); |
| |
| return sharedStore; |
| } |
| |
| // General methods |
| + (id)allocWithZone:(NSZone*)zone { |
| return [self sharedStore]; |
| } |
| |
| // Load data store from SQLLite backing store |
| - (id)init { |
| self = [super init]; |
| |
| if (self) { |
| // Read in ChromotingModel.xdatamodeld |
| _model = [NSManagedObjectModel mergedModelFromBundles:nil]; |
| |
| NSPersistentStoreCoordinator* psc = [[NSPersistentStoreCoordinator alloc] |
| initWithManagedObjectModel:_model]; |
| |
| NSString* path = [self itemArchivePath]; |
| NSURL* storeUrl = [NSURL fileURLWithPath:path]; |
| |
| NSError* error = nil; |
| |
| NSDictionary* tryOptions = @{ |
| NSMigratePersistentStoresAutomaticallyOption : @YES, |
| NSInferMappingModelAutomaticallyOption : @YES |
| }; |
| NSDictionary* makeOptions = |
| @{NSMigratePersistentStoresAutomaticallyOption : @YES}; |
| |
| if (![psc addPersistentStoreWithType:NSSQLiteStoreType |
| configuration:nil |
| URL:storeUrl |
| options:tryOptions |
| error:&error]) { |
| // An incompatible version of the store exists, delete it and start over |
| [[NSFileManager defaultManager] removeItemAtURL:storeUrl error:nil]; |
| |
| [psc addPersistentStoreWithType:NSSQLiteStoreType |
| configuration:nil |
| URL:storeUrl |
| options:makeOptions |
| error:&error]; |
| [NSException raise:@"Open failed" |
| format:@"Reason: %@", [error localizedDescription]]; |
| } |
| |
| // Create the managed object context |
| _context = [[NSManagedObjectContext alloc] init]; |
| [_context setPersistentStoreCoordinator:psc]; |
| |
| // The managed object context can manage undo, but we don't need it |
| [_context setUndoManager:nil]; |
| |
| _allHosts = nil; |
| } |
| return self; |
| } |
| |
| // Committing to backing store |
| - (BOOL)saveChanges { |
| NSError* err = nil; |
| BOOL successful = [_context save:&err]; |
| return successful; |
| } |
| |
| // Looking up the backing store path |
| - (NSString*)itemArchivePath { |
| NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains( |
| NSDocumentDirectory, NSUserDomainMask, YES); |
| |
| // Get one and only document directory from that list |
| NSString* documentDirectory = [documentDirectories objectAtIndex:0]; |
| |
| return [documentDirectory stringByAppendingPathComponent:@"store.data"]; |
| } |
| |
| // Return an array of all known hosts, if the list hasn't been loaded yet, then |
| // load it now |
| - (NSArray*)allHosts { |
| if (!_allHosts) { |
| NSFetchRequest* request = [[NSFetchRequest alloc] init]; |
| |
| NSEntityDescription* e = |
| [[_model entitiesByName] objectForKey:@"HostPreferences"]; |
| |
| [request setEntity:e]; |
| |
| NSError* error; |
| NSArray* result = [_context executeFetchRequest:request error:&error]; |
| if (!result) { |
| [NSException raise:@"Fetch failed" |
| format:@"Reason: %@", [error localizedDescription]]; |
| } |
| _allHosts = [result mutableCopy]; |
| } |
| |
| return _allHosts; |
| } |
| |
| // Return a HostPreferences if it already exists, otherwise create a new |
| // HostPreferences to use |
| - (const HostPreferences*)createHost:(NSString*)hostId { |
| |
| const HostPreferences* p = [self getHostForId:hostId]; |
| |
| if (p == nil) { |
| p = [NSEntityDescription insertNewObjectForEntityForName:@"HostPreferences" |
| inManagedObjectContext:_context]; |
| p.hostId = hostId; |
| [_allHosts addObject:p]; |
| } |
| return p; |
| } |
| |
| - (void)removeHost:(HostPreferences*)p { |
| [_context deleteObject:p]; |
| [_allHosts removeObjectIdenticalTo:p]; |
| } |
| |
| // Search the store for any matching HostPreferences |
| // return the 1st match or nil |
| - (const HostPreferences*)getHostForId:(NSString*)hostId { |
| NSFetchRequest* request = [[NSFetchRequest alloc] init]; |
| |
| NSEntityDescription* e = |
| [[_model entitiesByName] objectForKey:@"HostPreferences"]; |
| [request setEntity:e]; |
| |
| NSPredicate* predicate = |
| [NSPredicate predicateWithFormat:@"(hostId = %@)", hostId]; |
| [request setPredicate:predicate]; |
| |
| NSError* error; |
| NSArray* result = [_context executeFetchRequest:request error:&error]; |
| if (!result) { |
| [NSException raise:@"Fetch failed" |
| format:@"Reason: %@", [error localizedDescription]]; |
| } |
| |
| for (HostPreferences* curHost in result) { |
| return curHost; |
| } |
| return nil; |
| } |
| |
| @end |