#import "ASINetworkQueue.h"
#import "ASIPithosRequest.h"
#import "ASIPithos.h"
+#import "ASIPithosContainer.h"
#import "ASIPithosContainerRequest.h"
#import "ASIPithosObjectRequest.h"
#import "ASIPithosObject.h"
@interface PithosSyncDaemon (Private)
-- (void)resetLocalState;
-- (NSString *)pithosStateFilePath;
+- (void)loadLocalState;
+- (void)resetLocalStateWithAll:(BOOL)all;
- (void)saveLocalState;
-- (BOOL)moveToTempTrashFile:(NSString *)filePath;
+- (BOOL)moveToTempTrashFile:(NSString *)filePath pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)emptyTempTrash;
- (BOOL)findLocalCopyForObjectWithHash:(NSString *)hash forFile:(NSString *)filePath;
-- (void)updateLocalStateWithObject:(ASIPithosObject *)object localFilePath:(NSString *)filePath;
+- (void)updateLocalStateWithObject:(ASIPithosObject *)object
+ localFilePath:(NSString *)filePath
+ pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
object:(ASIPithosObject *)object
- localFilePath:(NSString *)filePath;
+ localFilePath:(NSString *)filePath
+ pithosContainer:(ASIPithosContainer *)pithosContainer;
- (void)listRequestFailed:(ASIPithosContainerRequest *)containerRequest;
- (void)requestFailed:(ASIPithosRequest *)request;
@end
@implementation PithosSyncDaemon
-@synthesize directoryPath, pithosAccount, containerName, pithos;
-@synthesize blockHash, blockSize, lastModified, lastCompletedSync, remoteObjects, storedLocalObjectStates, currentLocalObjectStates;
-@synthesize containerDirectoryPath, pithosStateFilePath, tempDownloadsDirPath, tempTrashDirPath;
+@synthesize directoryPath, pithosAccount, containersDictionary, pithos;
+@synthesize pithosContainers;
+@synthesize lastCompletedSync, remoteObjects, previousRemoteObjects, storedLocalObjectStates, currentLocalObjectStates;
+@synthesize pithosStateFilePath, tempDownloadsDirPath, tempTrashDirPath;
#pragma mark -
#pragma Object Lifecycle
- (id)initWithDirectoryPath:(NSString *)aDirectoryPath
pithosAccount:(PithosAccount *)aPithosAccount
- containerName:(NSString *)aContainerName
+ containersDictionary:(NSMutableDictionary *)aContainersDictionary
resetLocalState:(BOOL)resetLocalState {
if ((self = [super init])) {
directoryPath = [aDirectoryPath copy];
pithosAccount = [aPithosAccount retain];
- containerName = [aContainerName copy];
+ containersDictionary = [aContainersDictionary retain];
self.pithos = pithosAccount.pithos;
+ containersCount = [containersDictionary count];
+ self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
+ for (NSString *containerName in [containersDictionary allKeys]) {
+ ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
+ pithosContainer.name = containerName;
+ [pithosContainers addObject:pithosContainer];
+ }
+
activityFacility = [PithosActivityFacility defaultPithosActivityFacility];
if (resetLocalState)
- [self resetLocalState];
+ [self resetLocalStateWithAll:YES];
+ else
+ [self resetLocalStateWithAll:NO];
networkQueue = [[ASINetworkQueue alloc] init];
networkQueue.showAccurateProgress = YES;
selector:@selector(applicationWillTerminate:)
name:NSApplicationWillTerminateNotification
object:[NSApplication sharedApplication]];
-
- [self startDaemon];
}
return self;
}
-- (void)resetLocalState {
+- (void)loadLocalState {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:self.pithosStateFilePath])
+ self.storedLocalObjectStates = [NSKeyedUnarchiver unarchiveObjectWithFile:self.pithosStateFilePath];
+ else
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ if (!storedLocalObjectStates)
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ if (![storedLocalObjectStates objectForKey:pithosContainer.name]) {
+ [storedLocalObjectStates setObject:[NSMutableDictionary dictionary] forKey:pithosContainer.name];
+ }
+ }
+ [pool drain];
+}
+
+- (void)resetLocalStateWithAll:(BOOL)all {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.lastCompletedSync = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error = nil;
- if ([fileManager fileExistsAtPath:self.pithosStateFilePath] &&
- (![fileManager removeItemAtPath:self.pithosStateFilePath error:&error] || error))
- [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
- message:[NSString stringWithFormat:@"Cannot remove file at '%@'", self.pithosStateFilePath]
- error:error];
- if (self.tempDownloadsDirPath) {
- error = nil;
- for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:self.tempDownloadsDirPath error:&error]) {
- if (error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", self.tempDownloadsDirPath]
- error:error];
- break;
+ NSError *error;
+ if (all) {
+ self.storedLocalObjectStates = [NSMutableDictionary dictionary];
+ [self saveLocalState]; // Save an empty dictionary
+ [self loadLocalState]; // Load to populate with containers
+ [self saveLocalState]; // Save again
+ if (self.tempDownloadsDirPath) {
+ error = nil;
+ for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:self.tempDownloadsDirPath error:&error]) {
+ if (error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
+ message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", self.tempDownloadsDirPath]
+ error:error];
+ break;
+ }
+ NSString *subFilePath = [self.tempDownloadsDirPath stringByAppendingPathComponent:subPath];
+ if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
+ message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath]
+ error:error];
+ }
+ error = nil;
}
- NSString *subFilePath = [self.tempDownloadsDirPath stringByAppendingPathComponent:subPath];
- if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
- [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
- message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath]
- error:error];
+ }
+ } else {
+ // Remove containers that don't interest us anymore and save
+ if (!storedLocalObjectStates)
+ [self loadLocalState];
+ for (NSString *containerName in [storedLocalObjectStates allKeys]) {
+ if (![containersDictionary objectForKey:containerName]) {
+ [storedLocalObjectStates removeObjectForKey:containerName];
+ if (self.tempDownloadsDirPath) {
+ NSString *containerTempDownloadsDirPath = [self.tempDownloadsDirPath stringByAppendingPathComponent:containerName];
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:containerTempDownloadsDirPath isDirectory:&isDirectory];
+ if (fileExists && isDirectory) {
+ error = nil;
+ for (NSString *subPath in [fileManager contentsOfDirectoryAtPath:containerTempDownloadsDirPath error:&error]) {
+ if (error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
+ message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'",
+ containerTempDownloadsDirPath]
+ error:error];
+ break;
+ }
+ NSString *subFilePath = [containerTempDownloadsDirPath stringByAppendingPathComponent:subPath];
+ if (![fileManager removeItemAtPath:subFilePath error:&error] || error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
+ message:[NSString stringWithFormat:@"Cannot remove file at '%@'",
+ subFilePath]
+ error:error];
+ }
+ error = nil;
+ }
+ } else if (fileExists && !isDirectory) {
+ error = nil;
+ if (![fileManager removeItemAtPath:containerTempDownloadsDirPath error:&error] || error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error"
+ message:[NSString stringWithFormat:@"Cannot remove file at '%@'",
+ containerTempDownloadsDirPath]
+ error:error];
+ }
+ }
+ }
}
- error = nil;
}
+ [self saveLocalState];
}
+ [pool drain];
+}
+
+- (void)saveLocalState {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [NSKeyedArchiver archiveRootObject:storedLocalObjectStates toFile:self.pithosStateFilePath];
+ [pool drain];
}
- (void)resetDaemon {
[callbackQueue setSuspended:YES];
[self emptyTempTrash];
+ syncOperationCount = 0;
+
@synchronized(self) {
daemonActive = NO;
}
if (daemonActive)
return;
}
+
+ // In the improbable case of leftover operations
+ [networkQueue reset];
+ [callbackQueue cancelAllOperations];
syncOperationCount = 0;
newSyncRequested = NO;
syncIncomplete = NO;
syncLate = NO;
-
- self.containerDirectoryPath = [directoryPath stringByAppendingPathComponent:containerName];
-
- if ([[NSFileManager defaultManager] fileExistsAtPath:self.pithosStateFilePath]) {
- NSData *data = [NSData dataWithContentsOfFile:self.pithosStateFilePath];
- NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
- self.storedLocalObjectStates = [unarchiver decodeObjectForKey:containerName];
- [unarchiver finishDecoding];
- } else {
- self.storedLocalObjectStates = [NSMutableDictionary dictionary];
- }
-
- // In the improbable case of leftover operations
- [networkQueue reset];
- [callbackQueue cancelAllOperations];
+
+ [self loadLocalState];
[networkQueue go];
[callbackQueue setSuspended:NO];
[tempTrashDirPath release];
[tempDownloadsDirPath release];
[pithosStateFilePath release];
- [containerDirectoryPath release];
[currentLocalObjectStates release];
[storedLocalObjectStates release];
+ [previousRemoteObjects release];
[remoteObjects release];
[objects release];
[lastCompletedSync release];
- [lastModified release];
- [blockHash release];
+ [pithosContainers release];
[pithos release];
- [containerName release];
+ [containersDictionary release];
[pithosAccount release];
[directoryPath release];
[super dealloc];
#pragma mark Properties
- (NSString *)pithosStateFilePath {
- if (!pithosStateFilePath)
+ if (!pithosStateFilePath) {
pithosStateFilePath = [[[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-PithosLocalObjectStates.archive",
pithosAccount.uniqueName]] retain];
+ NSString *pithosStateFileDirPath = [pithosStateFilePath stringByDeletingLastPathComponent];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDirectory;
+ BOOL fileExists = [fileManager fileExistsAtPath:pithosStateFileDirPath isDirectory:&isDirectory];
+ NSError *error = nil;
+ if (fileExists && !isDirectory)
+ [fileManager removeItemAtPath:pithosStateFileDirPath error:&error];
+ if (!error && !fileExists)
+ [fileManager createDirectoryAtPath:pithosStateFileDirPath withIntermediateDirectories:YES attributes:nil error:&error];
+ //if (error)
+ // pithosStateFilePath = nil;
+ // XXX create a dir using mktmps?
+ }
return [[pithosStateFilePath copy] autorelease];
}
NSError *error = nil;
if (fileExists && !isDirectory)
[fileManager removeItemAtPath:tempDownloadsDirPath error:&error];
- if (!error & !fileExists)
+ if (!error && !fileExists)
[fileManager createDirectoryAtPath:tempDownloadsDirPath withIntermediateDirectories:YES attributes:nil error:&error];
//if (error)
// tempDownloadsDirPath = nil;
NSError *error = nil;
if (fileExists && !isDirectory)
[fileManager removeItemAtPath:tempTrashDirPath error:&error];
- if (!error & !fileExists)
+ if (!error && !fileExists)
[fileManager createDirectoryAtPath:tempTrashDirPath withIntermediateDirectories:YES attributes:nil error:&error];
//if (error)
// tempTrashDirPath = nil;
- (void)setDirectoryPath:(NSString *)aDirectoryPath {
if (aDirectoryPath && ![aDirectoryPath isEqualToString:directoryPath]) {
[self resetDaemon];
- [self resetLocalState];
+ [self resetLocalStateWithAll:YES];
[directoryPath release];
directoryPath = [aDirectoryPath copy];
}
}
-- (void)setContainerName:(NSString *)aContainerName {
- if (aContainerName && ![aContainerName isEqualToString:containerName]) {
+- (void)setContainersDictionary:(NSDictionary *)aContainersDictionary {
+ if (aContainersDictionary && ![aContainersDictionary isEqualToDictionary:containersDictionary]) {
[self resetDaemon];
- [self resetLocalState];
- [containerName release];
- containerName = [aContainerName copy];
+ [containersDictionary release];
+ containersDictionary = [aContainersDictionary retain];
+ containersCount = [containersDictionary count];
+ self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
+ for (NSString *containerName in [containersDictionary allKeys]) {
+ ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
+ pithosContainer.name = containerName;
+ [pithosContainers addObject:pithosContainer];
+ }
+ [self resetLocalStateWithAll:NO];
}
}
[self resetDaemon];
if (![aPithos.authUser isEqualToString:pithos.authUser] ||
![aPithos.storageURLPrefix isEqualToString:pithos.storageURLPrefix])
- [self resetLocalState];
+ [self resetLocalStateWithAll:YES];
pithos.authUser = [[aPithos.authUser copy] autorelease];
pithos.authToken = [[aPithos.authToken copy] autorelease];
pithos.storageURLPrefix = [[aPithos.storageURLPrefix copy] autorelease];
#pragma mark -
#pragma mark Sync
-- (void)saveLocalState {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSMutableData *data = [NSMutableData data];
- NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
- [archiver encodeObject:storedLocalObjectStates forKey:containerName];
- [archiver finishEncoding];
- [data writeToFile:self.pithosStateFilePath atomically:YES];
- [pool drain];
-}
-
- (void)syncOperationStarted {
@synchronized(self) {
syncOperationCount++;
@synchronized(self) {
if (!operationSuccessfull)
syncIncomplete = YES;
- if (syncOperationCount == 0)
+ if (syncOperationCount == 0) {
// XXX This shouldn't happen, maybe change operationCount to a BOOL as operationsPending in browser
+ NSLog(@"Sync::WARNING: tried to decrease syncOperationCount when 0");
return;
+ }
syncOperationCount--;
if (syncOperationCount == 0) {
if (!syncIncomplete) {
// If at least one operation is running return
newSyncRequested = YES;
return;
- } else if (daemonActive) {
+ } else if (daemonActive && containersCount) {
// The first operation is the server listing
[self syncOperationStarted];
newSyncRequested = NO;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory;
NSError *error = nil;
- if (![fileManager fileExistsAtPath:containerDirectoryPath isDirectory:&isDirectory]) {
- if (![fileManager createDirectoryAtPath:containerDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error] ||
+ if (![fileManager fileExistsAtPath:directoryPath isDirectory:&isDirectory]) {
+ if (![fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error] ||
error) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'", containerDirectoryPath]
+ message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'", directoryPath]
error:error];
[self syncOperationFinishedWithSuccess:NO];
return;
}
} else if (!isDirectory) {
[PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
- message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'", containerDirectoryPath]
+ message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'", directoryPath]
error:nil];
[self syncOperationFinishedWithSuccess:NO];
return;
}
-
+ NSString *containerDirectoryPath;
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ error = nil;
+ if (![fileManager fileExistsAtPath:containerDirectoryPath isDirectory:&isDirectory]) {
+ if (![fileManager createDirectoryAtPath:containerDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error] ||
+ error) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
+ message:[NSString stringWithFormat:@"Cannot create local sync directory at '%@'",
+ containerDirectoryPath]
+ error:error];
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ } else if (!isDirectory) {
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Local Sync Directory Error"
+ message:[NSString stringWithFormat:@"File already exists at the local sync directory path at '%@'",
+ containerDirectoryPath]
+ error:nil];
+ [self syncOperationFinishedWithSuccess:NO];
+ return;
+ }
+ }
+ containersIndex = 0;
+ self.remoteObjects = [NSMutableDictionary dictionaryWithCapacity:containersCount];
ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
- containerName:containerName
+ containerName:[[pithosContainers objectAtIndex:containersIndex] name]
limit:0
marker:nil
prefix:nil
meta:nil
shared:NO
until:nil
- ifModifiedSince:lastModified];
+ ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
containerRequest.delegate = self;
containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
[PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath]
+ message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", trashDirPath]
error:error];
});
[pool drain];
[pool drain];
}
-- (BOOL)moveToTempTrashFile:(NSString *)filePath {
+- (BOOL)moveToTempTrashFile:(NSString *)filePath pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSString *trashDirPath = self.tempTrashDirPath;
- if (!tempTrashDirPath) {
+ if (!self.tempTrashDirPath) {
[pool drain];
return NO;
}
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
NSError *error = nil;
- NSString *newFilePath = [filePath stringByReplacingOccurrencesOfString:containerDirectoryPath
- withString:trashDirPath];
+ NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ NSString *newFilePath = [filePath stringByReplacingOccurrencesOfString:containerDirectoryPath withString:self.tempTrashDirPath];
NSString *newDirPath = [newFilePath stringByDeletingLastPathComponent];
if (fileExists && isDirectory) {
NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:filePath error:&error];
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
[PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath]
+ message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", filePath]
error:error];
});
[pool drain];
[currentLocalObjectStates removeObjectForKey:filePath];
} else {
[currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
- blockHash:blockHash
- blockSize:blockSize]
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
forKey:newFilePath];
}
for (NSString *subPath in subPaths) {
NSString *subFilePath = [filePath stringByAppendingPathComponent:subPath];
NSString *newSubFilePath = [subFilePath stringByReplacingOccurrencesOfString:containerDirectoryPath
- withString:trashDirPath];
+ withString:self.tempTrashDirPath];
currentState = [currentLocalObjectStates objectForKey:subFilePath];
if (currentState) {
currentState.filePath = newSubFilePath;
[currentLocalObjectStates removeObjectForKey:subFilePath];
} else {
[currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newSubFilePath
- blockHash:blockHash
- blockSize:blockSize]
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
forKey:newSubFilePath];
}
}
[currentLocalObjectStates removeObjectForKey:filePath];
} else {
[currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:newFilePath
- blockHash:blockHash
- blockSize:blockSize]
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
forKey:newFilePath];
}
}
localState = [currentLocalObjectStates objectForKey:localFilePath];
if (!localState.isDirectory && [hash isEqualToString:localState.hash] &&
[fileManager fileExistsAtPath:localFilePath isDirectory:&isDirectory] && !isDirectory) {
- if ([localFilePath hasPrefix:containerDirectoryPath]) {
+ if ([localFilePath hasPrefix:directoryPath]) {
if (![fileManager copyItemAtPath:localFilePath toPath:filePath error:&error] || error) {
dispatch_async(dispatch_get_main_queue(), ^{
[PithosUtilities fileActionFailedAlertWithTitle:@"Copy File Error"
} else {
[pool drain];
return YES;
- }
+ }
} else if (self.tempTrashDirPath && [localFilePath hasPrefix:self.tempTrashDirPath]) {
if (![fileManager moveItemAtPath:localFilePath toPath:filePath error:&error] || error) {
dispatch_async(dispatch_get_main_queue(), ^{
}
- (void)updateLocalStateWithObject:(ASIPithosObject *)object
- localFilePath:(NSString *)filePath {
+ localFilePath:(NSString *)filePath
+ pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
BOOL isDirectory;
BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
NSString *fileDirectoryPath = [filePath stringByDeletingLastPathComponent];
- PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:object.name];
+ NSMutableDictionary *containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
+ PithosLocalObjectState *storedState = [containerStoredLocalObjectStates objectForKey:object.name];
// Remote updated info
NSError *remoteError;
BOOL remoteIsDirectory;
BOOL remoteObjectExists = [PithosUtilities objectExistsAtPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
objectName:object.name
error:&remoteError
isDirectory:&remoteIsDirectory
syncIncomplete = YES;
}
NSLog(@"Sync::delete local object: %@", filePath);
- if (!fileExists || [self moveToTempTrashFile:filePath]) {
+ if (!fileExists || [self moveToTempTrashFile:filePath pithosContainer:pithosContainer]) {
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Deleting '%@' locally (finished)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Deleting '%@/%@' locally (finished)",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
});
- [storedLocalObjectStates removeObjectForKey:object.name];
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
[self saveLocalState];
}
} else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
}
NSLog(@"Sync::create local directory object: %@", filePath);
BOOL directoryCreated = NO;
- if (!fileExists || (!isDirectory && [self moveToTempTrashFile:filePath])) {
+ if (!fileExists || (!isDirectory && [self moveToTempTrashFile:filePath pithosContainer:pithosContainer])) {
NSLog(@"Sync::local directory object doesn't exist: %@", filePath);
error = nil;
if (![fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:&error] || error) {
if (directoryCreated)
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Creating directory '%@' locally (finished)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@' locally (finished)",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
});
} else if (object.bytes == 0) {
}
NSLog(@"Sync::create local zero length object: %@", filePath);
BOOL fileCreated = NO;
- if (!fileExists || ((isDirectory || [PithosUtilities bytesOfFile:filePath]) && [self moveToTempTrashFile:filePath])) {
+ if (!fileExists || ((isDirectory || [PithosUtilities bytesOfFile:filePath]) && [self moveToTempTrashFile:filePath pithosContainer:pithosContainer])) {
NSLog(@"Sync::local zero length object doesn't exist: %@", filePath);
// Create directory of the file, if it doesn't exist
error = nil;
if (fileCreated)
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
});
} else if (storedState.tmpFilePath == nil) {
[self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
});
} else {
[self syncOperationStarted];
__block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
object:object
blockIndex:0
- blockSize:blockSize];
+ blockSize:pithosContainer.blockSize];
objectRequest.delegate = self;
objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
- message:[NSString stringWithFormat:@"Sync: Downloading '%@' (0%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (0%%)",
+ pithosContainer.name, object.name]
totalBytes:object.bytes
currentBytes:0
pithosAccount:pithosAccount];
[activityFacility updateActivity:activity withMessage:activity.message];
});
objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
object, @"pithosObject",
- [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, (NSUInteger)ceil((object.bytes +0.0)/(blockSize + 0.0)))], @"missingBlocks",
+ [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, (NSUInteger)ceil((object.bytes +0.0)/(pithosContainer.blockSize + 0.0)))], @"missingBlocks",
[NSNumber numberWithUnsignedInteger:0], @"missingBlockIndex",
filePath, @"filePath",
activity, @"activity",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (stopped)", object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (failed)", object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)", pithosContainer.name, object.name], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(downloadObjectBlockFinished:)), @"didFinishSelector",
nil];
[objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)",
+ withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
+ objectRequest.containerName,
[[objectRequest.userInfo objectForKey:@"pithosObject"] name],
(100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
[self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility startAndEndActivityWithType:PithosActivityOther
- message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
});
} else {
[self syncOperationStarted];
ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectHashmapRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
objectName:object.name];
objectRequest.delegate = self;
objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload
- message:[NSString stringWithFormat:@"Sync: Downloading '%@' (0%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (0%%)",
+ pithosContainer.name, object.name]
totalBytes:object.bytes
currentBytes:0
pithosAccount:pithosAccount];
[activityFacility updateActivity:activity withMessage:activity.message];
});
objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
object, @"pithosObject",
filePath, @"filePath",
activity, @"activity",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (stopped)", object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (failed)", object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Downloading '%@/%@' (100%%)", pithosContainer.name, object.name], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(downloadObjectHashMapFinished:)), @"didFinishSelector",
-(void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState
object:(ASIPithosObject *)object
- localFilePath:(NSString *)filePath {
+ localFilePath:(NSString *)filePath
+ pithosContainer:(ASIPithosContainer *)pithosContainer {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self syncOperationStarted];
NSFileManager *fileManager = [NSFileManager defaultManager];
return;
}
ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
objectName:object.name
eTag:nil
contentType:@"application/directory"
objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory
- message:[NSString stringWithFormat:@"Sync: Creating directory '%@'", object.name]
+ message:[NSString stringWithFormat:@"Sync: Creating directory '%@/%@'",
+ pithosContainer.name, object.name]
pithosAccount:pithosAccount];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility updateActivity:activity withMessage:activity.message];
});
objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
object, @"pithosObject",
activity, @"activity",
- [NSString stringWithFormat:@"Sync: Creating directory '%@' (stopped)", object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Creating directory '%@' (failed)", object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Creating directory '%@' (finished)", object.name], @"finishedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Creating directory '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
[NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
[NSNumber numberWithUnsignedInteger:10], @"retries",
NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector",
// Local object created in the meantime, just mark the sync cycle as incomplete, but do delete the server object
syncIncomplete = YES;
}
- NSString *safeName;
- if ([PithosUtilities isContentTypeDirectory:object.contentType])
- safeName = [PithosUtilities safeSubdirNameForPithos:pithos containerName:@"trash" subdirName:object.name];
- else
- safeName = [PithosUtilities safeObjectNameForPithos:pithos containerName:@"trash" objectName:object.name];
- if (safeName) {
- ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
- containerName:containerName
- objectName:object.name
- destinationContainerName:@"trash"
- destinationObjectName:safeName
- checkIfExists:NO];
- if (objectRequest) {
- objectRequest.delegate = self;
- objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
- objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
- PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
- message:[NSString stringWithFormat:@"Sync: Moving to trash '%@'", object.name]
- pithosAccount:pithosAccount];
- dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility updateActivity:activity withMessage:activity.message];
- });
- objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
- object, @"pithosObject",
- activity, @"activity",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@' (stopped)", object.name], @"stoppedActivityMessage",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@' (failed)", object.name], @"failedActivityMessage",
- [NSString stringWithFormat:@"Sync: Moving to trash '%@' (finished)", object.name], @"finishedActivityMessage",
- [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
- [NSNumber numberWithUnsignedInteger:10], @"retries",
- NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector",
- NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
- nil];
- [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ if ([pithosContainer.name isEqualToString:@"trash"]) {
+ // Delete
+ ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name];
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
+ message:[NSString stringWithFormat:@"Sync: Deleting '%@/%@'",
+ pithosContainer.name, object.name]
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ activity, @"activity",
+ [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Deleting '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(deleteObjectFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ } else {
+ // Move to container trash
+ NSString *safeName;
+ if ([PithosUtilities isContentTypeDirectory:object.contentType])
+ safeName = [PithosUtilities safeSubdirNameForPithos:pithos containerName:@"trash" subdirName:object.name];
+ else
+ safeName = [PithosUtilities safeObjectNameForPithos:pithos containerName:@"trash" objectName:object.name];
+ if (safeName) {
+ ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
+ containerName:pithosContainer.name
+ objectName:object.name
+ destinationContainerName:@"trash"
+ destinationObjectName:safeName
+ checkIfExists:NO];
+ if (objectRequest) {
+ objectRequest.delegate = self;
+ objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete
+ message:[NSString stringWithFormat:@"Sync: Moving to trash '%@/%@'",
+ pithosContainer.name, object.name]
+ pithosAccount:pithosAccount];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility updateActivity:activity withMessage:activity.message];
+ });
+ objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
+ object, @"pithosObject",
+ activity, @"activity",
+ [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (stopped)", pithosContainer.name, object.name], @"stoppedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (failed)", pithosContainer.name, object.name], @"failedActivityMessage",
+ [NSString stringWithFormat:@"Sync: Moving to trash '%@/%@' (finished)", pithosContainer.name, object.name], @"finishedActivityMessage",
+ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority",
+ [NSNumber numberWithUnsignedInteger:10], @"retries",
+ NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector",
+ NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector",
+ nil];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
+ } else {
+ [self syncOperationFinishedWithSuccess:NO];
+ }
} else {
[self syncOperationFinishedWithSuccess:NO];
}
- } else {
- [self syncOperationFinishedWithSuccess:NO];
}
} else {
// Upload file to remote object
NSLog(@"contentType detection error: %@", error);
NSArray *hashes = nil;
ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
objectName:object.name
contentType:object.contentType
- blockSize:blockSize
- blockHash:blockHash
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
forFile:filePath
checkIfExists:NO
hashes:&hashes
objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload
- message:[NSString stringWithFormat:@"Sync: Uploading '%@' (0%%)", object.name]
+ message:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (0%%)",
+ pithosContainer.name, object.name]
totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
currentBytes:0
pithosAccount:pithosAccount];
});
[(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
[NSDictionary dictionaryWithObjectsAndKeys:
+ pithosContainer, @"pithosContainer",
object, @"pithosObject",
filePath, @"filePath",
hashes, @"hashes",
[objects addObjectsFromArray:someObjects];
}
if ([someObjects count] < 10000) {
- self.blockHash = [containerRequest blockHash];
- self.blockSize = [containerRequest blockSize];
- self.lastModified = [containerRequest lastModified];
- self.remoteObjects = [NSMutableDictionary dictionaryWithCapacity:[objects count]];
+ ASIPithosContainer *pithosContainer = [pithosContainers objectAtIndex:containersIndex];
+ pithosContainer.blockHash = [containerRequest blockHash];
+ pithosContainer.blockSize = [containerRequest blockSize];
+ pithosContainer.lastModified = [containerRequest lastModified];
+ NSMutableDictionary *containerRemoteObjects = [NSMutableDictionary dictionaryWithCapacity:[objects count]];
for (ASIPithosObject *object in objects) {
- [remoteObjects setObject:object forKey:object.name];
+ [containerRemoteObjects setObject:object forKey:object.name];
}
+ [remoteObjects setObject:containerRemoteObjects forKey:pithosContainer.name];
[objects release];
objects = nil;
} else {
// Do an additional request to fetch more objects
ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
- containerName:containerName
+ containerName:[[pithosContainers objectAtIndex:containersIndex] name]
limit:0
marker:[[someObjects lastObject] name]
prefix:nil
meta:nil
shared:NO
until:nil
- ifModifiedSince:lastModified];
+ ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
newContainerRequest.delegate = self;
newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[pool drain];
return;
}
+ } else {
+ ASIPithosContainer *pithosContainer = [pithosContainers objectAtIndex:containersIndex];
+ NSMutableDictionary *containerRemoteObjects = [previousRemoteObjects objectForKey:pithosContainer.name];
+ if (containerRemoteObjects)
+ [remoteObjects setObject:containerRemoteObjects forKey:pithosContainer.name];
+ }
+ containersIndex++;
+ if (containersIndex < containersCount) {
+ // Do a request for the next container
+ ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithPithos:pithos
+ containerName:[[pithosContainers objectAtIndex:containersIndex] name]
+ limit:0
+ marker:nil
+ prefix:nil
+ delimiter:nil
+ path:nil
+ meta:nil
+ shared:NO
+ until:nil
+ ifModifiedSince:[[pithosContainers objectAtIndex:containersIndex] lastModified]];
+ newContainerRequest.delegate = self;
+ newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+ newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+ newContainerRequest.userInfo = containerRequest.userInfo;
+ [(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
+ [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
+ [pool drain];
+ return;
}
+ self.previousRemoteObjects = remoteObjects;
if (operation.isCancelled) {
[self listRequestFailed:containerRequest];
withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]];
});
NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error = nil;
- NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:containerDirectoryPath error:&error];
- if (error) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
- message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath]
- error:error];
- [activityFacility startAndEndActivityWithType:PithosActivityOther
- message:@"Sync: Failed to read contents of sync directory"
- pithosAccount:pithosAccount];
- });
- // Since the local listing failed, the operation finished and the sync cycle is completeted unsuccessfully
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ NSError *error;
+ NSMutableDictionary *subPaths = [NSMutableDictionary dictionaryWithCapacity:containersCount];
+ NSUInteger subPathsCount = 0;
+ NSString *containerDirectoryPath;
+ NSArray *containerSubPaths;
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ error = nil;
+ containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ containerSubPaths = [fileManager subpathsOfDirectoryAtPath:containerDirectoryPath error:&error];
+ if (error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error"
+ message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath]
+ error:error];
+ [activityFacility startAndEndActivityWithType:PithosActivityOther
+ message:@"Sync: Failed to read contents of sync directory"
+ pithosAccount:pithosAccount];
+ });
+ // Since the local listing failed, the operation finished and the sync cycle is completeted unsuccessfully
+ [self syncOperationFinishedWithSuccess:NO];
+ [pool drain];
+ return;
+ }
+ [subPaths setObject:containerSubPaths forKey:pithosContainer.name];
+ subPathsCount += [containerSubPaths count];
+ }
if (operation.isCancelled) {
operation.completionBlock = nil;
return;
}
- self.currentLocalObjectStates = [NSMutableDictionary dictionaryWithCapacity:[subPaths count]];
- for (NSString *objectName in subPaths) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ self.currentLocalObjectStates = [NSMutableDictionary dictionaryWithCapacity:subPathsCount];
+ NSMutableDictionary *containerStoredLocalObjectStates;
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
+ for (NSString *objectName in [subPaths objectForKey:pithosContainer.name]) {
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self saveLocalState];
+ [self syncOperationFinishedWithSuccess:NO];
+ [pool drain];
+ return;
+ }
- PithosLocalObjectState *storedLocalObjectState = [storedLocalObjectStates objectForKey:objectName];
- NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
- if (!storedLocalObjectState || [storedLocalObjectState isModified]) {
- // New or modified existing local object, compute current state
- if (!storedLocalObjectState)
- // For new local object, also create empty stored state
- [storedLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
- [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:filePath
- blockHash:blockHash
- blockSize:blockSize]
- forKey:filePath];
- } else {
- // Local object hasn't changed, set stored state also to current
- [currentLocalObjectStates setObject:storedLocalObjectState forKey:filePath];
+ PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:objectName];
+ NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
+ if (!storedLocalObjectState || [storedLocalObjectState isModified]) {
+ // New or modified existing local object, compute current state
+ if (!storedLocalObjectState)
+ // For new local object, also create empty stored state
+ [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
+ [currentLocalObjectStates setObject:[PithosLocalObjectState localObjectStateWithFile:filePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize]
+ forKey:filePath];
+ } else {
+ // Local object hasn't changed, set stored state also to current
+ [currentLocalObjectStates setObject:storedLocalObjectState forKey:filePath];
+ }
}
+ [self saveLocalState];
}
- [self saveLocalState];
-
+
if (operation.isCancelled) {
operation.completionBlock = nil;
[self syncOperationFinishedWithSuccess:NO];
return;
}
- for (NSString *objectName in remoteObjects) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self saveLocalState];
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
+ for (NSString *objectName in [remoteObjects objectForKey:pithosContainer.name]) {
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self saveLocalState];
+ [self syncOperationFinishedWithSuccess:NO];
+ [pool drain];
+ return;
+ }
- if (![storedLocalObjectStates objectForKey:objectName])
- [storedLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
+ if (![containerStoredLocalObjectStates objectForKey:objectName])
+ [containerStoredLocalObjectStates setObject:[PithosLocalObjectState localObjectState] forKey:objectName];
+ }
+ [self saveLocalState];
}
- [self saveLocalState];
if (operation.isCancelled) {
operation.completionBlock = nil;
return;
}
- for (NSString *objectName in [[storedLocalObjectStates allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
- if (operation.isCancelled) {
- operation.completionBlock = nil;
- [self syncOperationFinishedWithSuccess:NO];
- [pool drain];
- return;
- }
+ NSMutableDictionary *containerRemoteObjects;
+ for (ASIPithosContainer *pithosContainer in pithosContainers) {
+ containerDirectoryPath = [directoryPath stringByAppendingPathComponent:pithosContainer.name];
+ containerStoredLocalObjectStates = [storedLocalObjectStates objectForKey:pithosContainer.name];
+ containerRemoteObjects = [remoteObjects objectForKey:pithosContainer.name];
+ for (NSString *objectName in [[containerStoredLocalObjectStates allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
+ if (operation.isCancelled) {
+ operation.completionBlock = nil;
+ [self syncOperationFinishedWithSuccess:NO];
+ [pool drain];
+ return;
+ }
- NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
- if ([objectName hasSuffix:@"/"])
- filePath = [filePath stringByAppendingString:@":"];
- ASIPithosObject *object = [ASIPithosObject object];
- object.name = objectName;
- NSLog(@"Sync::object name: %@", objectName);
+ NSString *filePath = [containerDirectoryPath stringByAppendingPathComponent:objectName];
+ if ([objectName hasSuffix:@"/"])
+ filePath = [filePath stringByAppendingString:@":"];
+ ASIPithosObject *object = [ASIPithosObject object];
+ object.name = objectName;
+ NSLog(@"Sync::object name: %@", object.name);
- PithosLocalObjectState *storedLocalObjectState = [storedLocalObjectStates objectForKey:object.name];
- PithosLocalObjectState *currentLocalObjectState = [currentLocalObjectStates objectForKey:filePath];
- if (!currentLocalObjectState)
- currentLocalObjectState = [PithosLocalObjectState localObjectStateWithFile:filePath
- blockHash:blockHash
- blockSize:blockSize];
- if (currentLocalObjectState.isDirectory)
- object.contentType = @"application/directory";
+ PithosLocalObjectState *storedLocalObjectState = [containerStoredLocalObjectStates objectForKey:object.name];
+ PithosLocalObjectState *currentLocalObjectState = [currentLocalObjectStates objectForKey:filePath];
+ if (!currentLocalObjectState)
+ currentLocalObjectState = [PithosLocalObjectState localObjectStateWithFile:filePath
+ blockHash:pithosContainer.blockHash
+ blockSize:pithosContainer.blockSize];
+// if (currentLocalObjectState.isDirectory)
+// object.contentType = @"application/directory";
- PithosLocalObjectState *remoteObjectState = [PithosLocalObjectState localObjectState];
- ASIPithosObject *remoteObject = [remoteObjects objectForKey:objectName];
- if (remoteObject) {
- if ([PithosUtilities isContentTypeDirectory:remoteObject.contentType]) {
- remoteObjectState.isDirectory = YES;
- object.contentType = @"application/directory";
- } else {
- remoteObjectState.hash = remoteObject.objectHash;
+ PithosLocalObjectState *remoteObjectState = [PithosLocalObjectState localObjectState];
+ ASIPithosObject *remoteObject = [containerRemoteObjects objectForKey:object.name];
+ if (remoteObject) {
+ if ([PithosUtilities isContentTypeDirectory:remoteObject.contentType]) {
+ remoteObjectState.isDirectory = YES;
+// object.contentType = @"application/directory";
+ } else {
+ remoteObjectState.hash = remoteObject.objectHash;
+ }
}
- }
- BOOL localStateHasChanged = ![currentLocalObjectState isEqualToState:storedLocalObjectState];
- BOOL serverStateHasChanged = ![remoteObjectState isEqualToState:storedLocalObjectState];
- NSLog(@"Sync::localStateHasChanged: %d, serverStateHasChanged: %d", localStateHasChanged, serverStateHasChanged);
- if (!localStateHasChanged) {
- // Local state hasn't changed
- if (serverStateHasChanged) {
- // Server state has changed
- // Update local state to match that of the server
- object.bytes = remoteObject.bytes;
- object.version = remoteObject.version;
- object.contentType = remoteObject.contentType;
- object.objectHash = remoteObject.objectHash;
- [self updateLocalStateWithObject:object localFilePath:filePath];
- } else if (!remoteObject && ![currentLocalObjectState exists]) {
- // Server state hasn't changed
- // If the object doesn't exist neither in the server or locally, it should be removed from the stored local objects
- [storedLocalObjectStates removeObjectForKey:objectName];
- [self saveLocalState];
- }
- } else {
- // Local state has changed
- if (!serverStateHasChanged) {
- // Server state hasn't changed
- [self updateServerStateWithCurrentState:currentLocalObjectState
- object:object
- localFilePath:filePath];
- } else {
- // Server state has also changed
- if (remoteObjectState.isDirectory && currentLocalObjectState.isDirectory) {
- // Both did the same change (directory)
- storedLocalObjectState.filePath = filePath;
- storedLocalObjectState.isDirectory = YES;
- [self saveLocalState];
- } else if ([remoteObjectState isEqualToState:currentLocalObjectState]) {
- // Both did the same change (object edit or delete)
- if (![remoteObjectState exists]) {
- [storedLocalObjectStates removeObjectForKey:object.name];
- } else {
- storedLocalObjectState.filePath = filePath;
- storedLocalObjectState.hash = remoteObjectState.hash;
- }
+ BOOL localStateHasChanged = ![currentLocalObjectState isEqualToState:storedLocalObjectState];
+ BOOL serverStateHasChanged = ![remoteObjectState isEqualToState:storedLocalObjectState];
+ NSLog(@"Sync::localStateHasChanged: %d, serverStateHasChanged: %d", localStateHasChanged, serverStateHasChanged);
+ if (!localStateHasChanged) {
+ // Local state hasn't changed
+ if (serverStateHasChanged) {
+ // Server state has changed
+ // Update local state to match that of the server
+ object.bytes = remoteObject.bytes;
+ object.version = remoteObject.version;
+ object.contentType = remoteObject.contentType;
+ object.objectHash = remoteObject.objectHash;
+ [self updateLocalStateWithObject:object localFilePath:filePath pithosContainer:pithosContainer];
+ } else if (!remoteObject && ![currentLocalObjectState exists]) {
+ // Server state hasn't changed
+ // If the object doesn't exist neither in the server or locally, it should be removed from the stored local objects
+ [containerStoredLocalObjectStates removeObjectForKey:objectName];
[self saveLocalState];
+ }
+ } else {
+ // Local state has changed
+ if (!serverStateHasChanged) {
+ // Server state hasn't changed
+ if (currentLocalObjectState.isDirectory)
+ object.contentType = @"application/directory";
+ else
+ object.objectHash = currentLocalObjectState.hash;
+ [self updateServerStateWithCurrentState:currentLocalObjectState
+ object:object
+ localFilePath:filePath
+ pithosContainer:pithosContainer];
} else {
- // Conflict, we ask the user which change to keep
- NSString *informativeText;
- NSString *firstButtonText;
- NSString *secondButtonText;
-
- if (![remoteObjectState exists]) {
- // Remote object has been deleted
- informativeText = [NSString stringWithFormat:@"'%@' has been modified locally, while it has been deleted from server.", object.name ];
- firstButtonText = @"Delete local file";
- secondButtonText = @"Upload file to server";
- } else if (![currentLocalObjectState exists]) {
- informativeText = [NSString stringWithFormat:@"'%@' has been modified on the server, while it has been deleted locally.", object.name];
- firstButtonText = @"Download file from server";
- secondButtonText = @"Delete file on server";
+ // Server state has also changed
+ if (remoteObjectState.isDirectory && currentLocalObjectState.isDirectory) {
+ // Both did the same change (directory)
+ storedLocalObjectState.filePath = filePath;
+ storedLocalObjectState.isDirectory = YES;
+ [self saveLocalState];
+ } else if ([remoteObjectState isEqualToState:currentLocalObjectState]) {
+ // Both did the same change (object edit or delete)
+ if (![remoteObjectState exists]) {
+ [containerStoredLocalObjectStates removeObjectForKey:object.name];
+ } else {
+ storedLocalObjectState.filePath = filePath;
+ storedLocalObjectState.hash = remoteObjectState.hash;
+ }
+ [self saveLocalState];
} else {
- informativeText = [NSString stringWithFormat:@"'%@' has been modifed both locally and on the server.", object.name];
- firstButtonText = @"Keep server version";
- secondButtonText = @"Keep local version";
- }
- NSAlert *alert = [[[NSAlert alloc] init] autorelease];
- [alert setMessageText:@"Conflict"];
- [alert setInformativeText:informativeText];
- [alert addButtonWithTitle:firstButtonText];
- [alert addButtonWithTitle:secondButtonText];
- [alert addButtonWithTitle:@"Do nothing"];
- NSInteger choice = [alert runModal];
- if (choice == NSAlertFirstButtonReturn) {
- object.bytes = remoteObject.bytes;
- object.version = remoteObject.version;
- object.contentType = remoteObject.contentType;
- object.objectHash = remoteObject.objectHash;
- [self updateLocalStateWithObject:object localFilePath:filePath];
- } if (choice == NSAlertSecondButtonReturn) {
- [self updateServerStateWithCurrentState:currentLocalObjectState
- object:object
- localFilePath:filePath];
+ // Conflict, we ask the user which change to keep
+ NSString *informativeText;
+ NSString *firstButtonText;
+ NSString *secondButtonText;
+
+ if (![remoteObjectState exists]) {
+ // Remote object has been deleted
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified locally, while it has been deleted from server.",
+ pithosContainer.name, object.name ];
+ firstButtonText = @"Delete local file";
+ secondButtonText = @"Upload file to server";
+ } else if (![currentLocalObjectState exists]) {
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified on the server, while it has been deleted locally.",
+ pithosContainer.name, object.name];
+ firstButtonText = @"Download file from server";
+ secondButtonText = @"Delete file on server";
+ } else {
+ informativeText = [NSString stringWithFormat:@"'%@/%@' has been modified both locally and on the server.",
+ pithosContainer.name, object.name];
+ firstButtonText = @"Keep server version";
+ secondButtonText = @"Keep local version";
+ }
+ NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+ [alert setMessageText:@"Conflict"];
+ [alert setInformativeText:informativeText];
+ [alert addButtonWithTitle:firstButtonText];
+ [alert addButtonWithTitle:secondButtonText];
+ [alert addButtonWithTitle:@"Do nothing"];
+ NSInteger choice = [alert runModal];
+ if (choice == NSAlertFirstButtonReturn) {
+ object.bytes = remoteObject.bytes;
+ object.version = remoteObject.version;
+ object.contentType = remoteObject.contentType;
+ object.objectHash = remoteObject.objectHash;
+ [self updateLocalStateWithObject:object localFilePath:filePath pithosContainer:pithosContainer];
+ } if (choice == NSAlertSecondButtonReturn) {
+ if (currentLocalObjectState.isDirectory)
+ object.contentType = @"application/directory";
+ else
+ object.objectHash = currentLocalObjectState.hash;
+ [self updateServerStateWithCurrentState:currentLocalObjectState
+ object:object
+ localFilePath:filePath
+ pithosContainer:pithosContainer];
+ }
}
}
}
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 206) {
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
return;
}
- PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:object.name];
+ PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:pithosContainer.name] objectForKey:object.name];
if ((storedState.tmpFilePath == nil) || ![fileManager fileExistsAtPath:storedState.tmpFilePath]) {
NSString *tempFileTemplate = [downloadsDirPath stringByAppendingPathComponent:@"download.XXXXXX"];
const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
NSUInteger missingBlockIndex = [[objectRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue];
NSFileHandle *tempFileHandle = [NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath];
- [tempFileHandle seekToFileOffset:missingBlockIndex*blockSize];
+ [tempFileHandle seekToFileOffset:missingBlockIndex*pithosContainer.blockSize];
[tempFileHandle writeData:[objectRequest responseData]];
[tempFileHandle closeFile];
if (missingBlockIndex == NSNotFound) {
NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
NSString *dirPath = [filePath stringByDeletingLastPathComponent];
- if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath]) {
+ if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath pithosContainer:pithosContainer]) {
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility endActivity:activity
withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]];
[self requestFailed:objectRequest];
} else {
__block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
object:object
blockIndex:missingBlockIndex
- blockSize:blockSize];
+ blockSize:pithosContainer.blockSize];
newObjectRequest.delegate = self;
newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
[newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)",
- object.name,
+ withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
+ newObjectRequest.containerName, object.name,
(100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
currentBytes:(activity.currentBytes + size)];
if (newSyncRequested || syncLate || operation.isCancelled) {
[self requestFailed:objectRequest];
} else {
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
- PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:object.name];
+ PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:pithosContainer.name] objectForKey:object.name];
if ([PithosUtilities bytesOfFile:storedState.tmpFilePath] > object.bytes)
[[NSFileHandle fileHandleForWritingAtPath:storedState.tmpFilePath] truncateFileAtOffset:object.bytes];
PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForFile:storedState.tmpFilePath
- blockSize:blockSize
- blockHash:blockHash
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
withHashes:[objectRequest hashes]];
NSUInteger missingBlockIndex = [missingBlocks firstIndex];
dispatch_async(dispatch_get_main_queue(), ^{
- [activityFacility endActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)",
- object.name,
- (100*(activity.totalBytes - [missingBlocks count]*blockSize + 0.0)/(activity.totalBytes + 0.0))]
- totalBytes:activity.totalBytes
- currentBytes:(activity.totalBytes - [missingBlocks count]*blockSize)];
+ [activityFacility updateActivity:activity
+ withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
+ pithosContainer.name, object.name,
+ (100*(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize + 0.0)/(activity.totalBytes + 0.0))]
+ totalBytes:activity.totalBytes
+ currentBytes:(activity.totalBytes - [missingBlocks count]*pithosContainer.blockSize)];
});
__block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
object:object
blockIndex:missingBlockIndex
- blockSize:blockSize];
+ blockSize:pithosContainer.blockSize];
newObjectRequest.delegate = self;
newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
[(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(downloadObjectBlockFinished:)) forKey:@"didFinishSelector"];
[newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)",
- object.name,
+ withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@/%@' (%.0f%%)",
+ newObjectRequest.containerName, object.name,
(100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
currentBytes:(activity.currentBytes + size)];
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 201) {
- PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ objectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
storedState.isDirectory = YES;
[self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
if (operation.isCancelled) {
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 201) {
- [storedLocalObjectStates removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
+ [self saveLocalState];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
+ withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
+ });
+ [self syncOperationFinishedWithSuccess:YES];
+ } else {
+ [self requestFailed:objectRequest];
+ }
+ [pool drain];
+}
+
+- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
+ NSLog(@"Sync::delete object finished: %@", objectRequest.url);
+ if (operation.isCancelled) {
+ [self requestFailed:objectRequest];
+ } else if (objectRequest.responseStatusCode == 204) {
+ [[storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosContainer"] name]]
+ removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]];
[self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"]
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
NSLog(@"Sync::upload using hashmap finished: %@", objectRequest.url);
+ ASIPithosContainer *pithosContainer = [objectRequest.userInfo objectForKey:@"pithosContainer"];
ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"];
- PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:object.name];
+ PithosLocalObjectState *storedState = [[storedLocalObjectStates objectForKey:pithosContainer.name] objectForKey:object.name];
PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
NSUInteger totalBytes = activity.totalBytes;
NSUInteger currentBytes = activity.currentBytes;
[self requestFailed:objectRequest];
} else if (objectRequest.responseStatusCode == 201) {
NSLog(@"Sync::object created: %@", objectRequest.url);
- storedState.hash = [objectRequest objectHash];
+ storedState.filePath = [objectRequest.userInfo objectForKey:@"filePath"];
+ storedState.hash = object.objectHash;
[self saveLocalState];
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility endActivity:activity
NSLog(@"Sync::object is missing hashes: %@", objectRequest.url);
NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
withMissingHashes:[objectRequest hashes]];
- if (totalBytes >= [missingBlocks count]*blockSize)
- currentBytes = totalBytes - [missingBlocks count]*blockSize;
+ if (totalBytes >= [missingBlocks count]*pithosContainer.blockSize)
+ currentBytes = totalBytes - [missingBlocks count]*pithosContainer.blockSize;
dispatch_async(dispatch_get_main_queue(), ^{
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
+ withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (%.0f%%)",
+ pithosContainer.name, object.name, (100*(currentBytes + 0.0)/(totalBytes + 0.0))]
totalBytes:totalBytes
currentBytes:currentBytes];
});
NSUInteger missingBlockIndex = [missingBlocks firstIndex];
__block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
- containerName:containerName
- blockSize:blockSize
+ containerName:pithosContainer.name
+ blockSize:pithosContainer.blockSize
forFile:[objectRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex
sharingAccount:nil];
[(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"];
[newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (%.0f%%)",
+ newContainerRequest.containerName, object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
currentBytes:(activity.currentBytes + size)];
}];
if (operation.isCancelled) {
[self requestFailed:containerRequest];
} else if (containerRequest.responseStatusCode == 202) {
+ ASIPithosContainer *pithosContainer = [containerRequest.userInfo objectForKey:@"pithosContainer"];
ASIPithosObject *object = [containerRequest.userInfo objectForKey:@"pithosObject"];
PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"];
NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"];
} else if (missingBlockIndex == NSNotFound) {
NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"];
ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
- containerName:containerName
+ containerName:pithosContainer.name
objectName:object.name
contentType:object.contentType
- blockSize:blockSize
- blockHash:blockHash
+ blockSize:pithosContainer.blockSize
+ blockHash:pithosContainer.blockHash
forFile:[containerRequest.userInfo objectForKey:@"filePath"]
checkIfExists:NO
hashes:&hashes
[self requestFailed:containerRequest];
} else {
__block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos
- containerName:containerName
- blockSize:blockSize
+ containerName:pithosContainer.name
+ blockSize:pithosContainer.blockSize
forFile:[containerRequest.userInfo objectForKey:@"filePath"]
missingBlockIndex:missingBlockIndex
sharingAccount:nil];
[(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
[newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
[activityFacility updateActivity:activity
- withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
+ withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@/%@' (%.0f%%)",
+ newContainerRequest.containerName, object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))]
totalBytes:activity.totalBytes
currentBytes:(activity.currentBytes + size)];
}];
- (void)requestFailed:(ASIPithosRequest *)request {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSOperation *operation = [request.userInfo objectForKey:@"operation"];
+ NSLog(@"Sync::request failed: %@", request.url);
if (operation.isCancelled) {
[pool drain];
return;
[pool drain];
}
-
@end