From: Antony Chazapis Date: Sat, 15 Oct 2011 12:55:05 +0000 (+0300) Subject: Merge branch 'master' of https://code.grnet.gr/git/pithos-macos X-Git-Tag: v0.7~5 X-Git-Url: https://code.grnet.gr/git/pithos-macos/commitdiff_plain/9114e962a437ed185e52d4d209451fc4e7de722c?hp=677a1e3d312f3e4550fc6b732cef2e5d624e4d63 Merge branch 'master' of https://code.grnet.gr/git/pithos-macos --- diff --git a/pithos-macos.xcodeproj/project.pbxproj b/pithos-macos.xcodeproj/project.pbxproj index a85a486..54aac14 100644 --- a/pithos-macos.xcodeproj/project.pbxproj +++ b/pithos-macos.xcodeproj/project.pbxproj @@ -64,7 +64,7 @@ 61C24BBB1410D350007004DC /* PublicURLTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BBA1410D350007004DC /* PublicURLTransformer.m */; }; 61C24BBE1410E031007004DC /* SharingDictionaryTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BBD1410E031007004DC /* SharingDictionaryTransformer.m */; }; 61C24BC114110BDB007004DC /* SharingNameFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BC014110BDB007004DC /* SharingNameFormatter.m */; }; - 61C24BEC14161EC7007004DC /* PithosFileUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BEB14161EC3007004DC /* PithosFileUtilities.m */; }; + 61C24BEC14161EC7007004DC /* PithosUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C24BEB14161EC3007004DC /* PithosUtilities.m */; }; 61C65ADF1428C578002597C2 /* CountTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65ADE1428C578002597C2 /* CountTransformer.m */; }; 61C65AE31428D41C002597C2 /* PolicyVersioningTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65AE21428D41C002597C2 /* PolicyVersioningTransformer.m */; }; 61C65AE6142918DD002597C2 /* PithosObjectNodeInfoController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */; }; @@ -183,8 +183,8 @@ 61C24BBD1410E031007004DC /* SharingDictionaryTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingDictionaryTransformer.m; path = "pithos-macos/SharingDictionaryTransformer.m"; sourceTree = ""; }; 61C24BBF14110BDB007004DC /* SharingNameFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingNameFormatter.h; path = "pithos-macos/SharingNameFormatter.h"; sourceTree = ""; }; 61C24BC014110BDB007004DC /* SharingNameFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingNameFormatter.m; path = "pithos-macos/SharingNameFormatter.m"; sourceTree = ""; }; - 61C24BEA14161EC0007004DC /* PithosFileUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosFileUtilities.h; sourceTree = ""; }; - 61C24BEB14161EC3007004DC /* PithosFileUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosFileUtilities.m; sourceTree = ""; }; + 61C24BEA14161EC0007004DC /* PithosUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosUtilities.h; sourceTree = ""; }; + 61C24BEB14161EC3007004DC /* PithosUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosUtilities.m; sourceTree = ""; }; 61C65ADD1428C578002597C2 /* CountTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CountTransformer.h; path = "pithos-macos/CountTransformer.h"; sourceTree = ""; }; 61C65ADE1428C578002597C2 /* CountTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CountTransformer.m; path = "pithos-macos/CountTransformer.m"; sourceTree = ""; }; 61C65AE11428D41C002597C2 /* PolicyVersioningTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PolicyVersioningTransformer.h; path = "pithos-macos/PolicyVersioningTransformer.h"; sourceTree = ""; }; @@ -253,41 +253,21 @@ 610DD2FB13E6BB2000ED982F /* pithos-macos */ = { isa = PBXGroup; children = ( + 61F1C5DB1444A8CF00C1E6EB /* PithosNodes */, + 61F1C5DD1444A92B00C1E6EB /* PithosNodeInfoControllers */, + 610DD2FC13E6BB2000ED982F /* Supporting Files */, 610DD30713E6BB2000ED982F /* pithos_macosAppDelegate.h */, 610DD30813E6BB2000ED982F /* pithos_macosAppDelegate.m */, 610DD30A13E6BB2000ED982F /* MainMenu.xib */, - 610DD2FC13E6BB2000ED982F /* Supporting Files */, 610DD34C13E6BEF400ED982F /* PithosBrowserController.h */, 610DD34D13E6BEF400ED982F /* PithosBrowserController.m */, 610DD34F13E6C00E00ED982F /* PithosBrowserController.xib */, 6121250813F033F400063041 /* PithosBrowserPreviewController.xib */, - 616FC0B113F97D0800140A33 /* PithosNodeInfoController.h */, - 616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */, - 611405CD1428BEBD00637170 /* PithosContainerNodeInfoController.h */, - 611405CE1428BEBE00637170 /* PithosContainerNodeInfoController.m */, - 611405CF1428BEC000637170 /* PithosContainerNodeInfoController.xib */, - 61C65AE4142918DC002597C2 /* PithosObjectNodeInfoController.h */, - 61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */, - 616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */, 619B85D213F8076F00C9371F /* PithosPreferencesController.h */, 619B85D313F8077100C9371F /* PithosPreferencesController.m */, 619B85D413F8077300C9371F /* PithosPreferencesController.xib */, - 610DD35713E6C3D100ED982F /* PithosNode.h */, - 610DD35813E6C3D100ED982F /* PithosNode.m */, - 610DD36213E6E2E400ED982F /* PithosAccountNode.h */, - 610DD36313E6E2E400ED982F /* PithosAccountNode.m */, - 610DD36513E6E69D00ED982F /* PithosContainerNode.h */, - 610DD36613E6E69D00ED982F /* PithosContainerNode.m */, - 610DD37313E7064E00ED982F /* PithosSubdirNode.h */, - 610DD37413E7064F00ED982F /* PithosSubdirNode.m */, - 610DD37013E7059800ED982F /* PithosObjectNode.h */, - 610DD37113E7059900ED982F /* PithosObjectNode.m */, - 6152D08A143200CB00803874 /* PithosSharingAccountsNode.h */, - 6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */, - 611FFCAD13EBF0B800E43E18 /* PithosEmptyNode.h */, - 611FFCAE13EBF0B900E43E18 /* PithosEmptyNode.m */, - 61C24BEA14161EC0007004DC /* PithosFileUtilities.h */, - 61C24BEB14161EC3007004DC /* PithosFileUtilities.m */, + 61C24BEA14161EC0007004DC /* PithosUtilities.h */, + 61C24BEB14161EC3007004DC /* PithosUtilities.m */, 618A7FD61438CE5D0040F043 /* PithosActivityFacility.h */, 618A7FD71438CE5D0040F043 /* PithosActivityFacility.m */, 618A7FF4143A20830040F043 /* PithosActivity.h */, @@ -432,6 +412,42 @@ name = "Value Transformers"; sourceTree = ""; }; + 61F1C5DB1444A8CF00C1E6EB /* PithosNodes */ = { + isa = PBXGroup; + children = ( + 610DD35713E6C3D100ED982F /* PithosNode.h */, + 610DD35813E6C3D100ED982F /* PithosNode.m */, + 610DD36213E6E2E400ED982F /* PithosAccountNode.h */, + 610DD36313E6E2E400ED982F /* PithosAccountNode.m */, + 610DD36513E6E69D00ED982F /* PithosContainerNode.h */, + 610DD36613E6E69D00ED982F /* PithosContainerNode.m */, + 610DD37313E7064E00ED982F /* PithosSubdirNode.h */, + 610DD37413E7064F00ED982F /* PithosSubdirNode.m */, + 610DD37013E7059800ED982F /* PithosObjectNode.h */, + 610DD37113E7059900ED982F /* PithosObjectNode.m */, + 6152D08A143200CB00803874 /* PithosSharingAccountsNode.h */, + 6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */, + 611FFCAD13EBF0B800E43E18 /* PithosEmptyNode.h */, + 611FFCAE13EBF0B900E43E18 /* PithosEmptyNode.m */, + ); + name = PithosNodes; + sourceTree = ""; + }; + 61F1C5DD1444A92B00C1E6EB /* PithosNodeInfoControllers */ = { + isa = PBXGroup; + children = ( + 616FC0B113F97D0800140A33 /* PithosNodeInfoController.h */, + 616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */, + 611405CD1428BEBD00637170 /* PithosContainerNodeInfoController.h */, + 611405CE1428BEBE00637170 /* PithosContainerNodeInfoController.m */, + 611405CF1428BEC000637170 /* PithosContainerNodeInfoController.xib */, + 61C65AE4142918DC002597C2 /* PithosObjectNodeInfoController.h */, + 61C65AE5142918DD002597C2 /* PithosObjectNodeInfoController.m */, + 616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */, + ); + name = PithosNodeInfoControllers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -536,7 +552,7 @@ 61C24BBB1410D350007004DC /* PublicURLTransformer.m in Sources */, 61C24BBE1410E031007004DC /* SharingDictionaryTransformer.m in Sources */, 61C24BC114110BDB007004DC /* SharingNameFormatter.m in Sources */, - 61C24BEC14161EC7007004DC /* PithosFileUtilities.m in Sources */, + 61C24BEC14161EC7007004DC /* PithosUtilities.m in Sources */, 614592BC1417CE70002E7A8C /* ASIPithosAccount.m in Sources */, 61433BC9141BA1CE00CD978D /* HashMapHash.m in Sources */, 611405D01428BEC000637170 /* PithosContainerNodeInfoController.m in Sources */, diff --git a/pithos-macos/PithosAccountNode.m b/pithos-macos/PithosAccountNode.m index 639e344..e45b6d7 100644 --- a/pithos-macos/PithosAccountNode.m +++ b/pithos-macos/PithosAccountNode.m @@ -41,7 +41,7 @@ #import "ASIPithosAccount.h" #import "ASIPithosContainer.h" #import "ASIDownloadCache.h" -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" static NSImage *sharedIcon = nil; @@ -97,7 +97,7 @@ static NSImage *sharedIcon = nil; accountRequest.didFailSelector = @selector(accountRequestFailed:); if (!forcedRefresh) accountRequest.downloadCache = [ASIDownloadCache sharedCache]; - [accountRequest startAsynchronous]; + [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; break; case PithosNodeStateRefreshing: break; @@ -194,12 +194,12 @@ static NSImage *sharedIcon = nil; accountRequest.delegate = self; if (!forcedRefresh) accountRequest.downloadCache = [ASIDownloadCache sharedCache]; - [accountRequest startAsynchronous]; + [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } - (void)accountRequestFailed:(ASIPithosAccountRequest *)request { - [PithosFileUtilities httpRequestErrorAlertWithRequest:request]; + [PithosUtilities httpRequestErrorAlertWithRequest:request]; [newChildren release]; newChildren = nil; [accountRequest release]; @@ -233,13 +233,13 @@ static NSImage *sharedIcon = nil; - (void)accountMetadataRequestFailed:(ASIPithosAccountRequest *)request { if ([request isEqualTo:applyMetadataAccountRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest]; @synchronized(self) { [applyMetadataAccountRequest release]; applyMetadataAccountRequest = nil; } } else if ([request isEqualTo:refreshMetadataAccountRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest]; @synchronized(self) { [refreshMetadataAccountRequest release]; refreshMetadataAccountRequest = nil; @@ -262,7 +262,7 @@ static NSImage *sharedIcon = nil; applyMetadataAccountRequest.delegate = self; applyMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:); applyMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:); - [applyMetadataAccountRequest startAsynchronous]; + [[PithosUtilities prepareRequest:applyMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } @@ -275,7 +275,7 @@ static NSImage *sharedIcon = nil; refreshMetadataAccountRequest.didFinishSelector = @selector(accountMetadataRequestFinished:); refreshMetadataAccountRequest.didFailSelector = @selector(accountMetadataRequestFailed:); refreshMetadataAccountRequest.downloadCache = [ASIDownloadCache sharedCache]; - [refreshMetadataAccountRequest startAsynchronous]; + [[PithosUtilities prepareRequest:refreshMetadataAccountRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } diff --git a/pithos-macos/PithosActivity.h b/pithos-macos/PithosActivity.h index 44aa504..c94b751 100644 --- a/pithos-macos/PithosActivity.h +++ b/pithos-macos/PithosActivity.h @@ -38,8 +38,12 @@ #import typedef enum { - PithosActivityUpload, - PithosActivityDownload + PithosActivityUpload, + PithosActivityDownload, + PithosActivityCopy, + PithosActivityMove, + PithosActivityCreateDirectory, + PithosActivityDelete } PithosActivityType; @interface PithosActivity : NSObject { diff --git a/pithos-macos/PithosActivityFacility.h b/pithos-macos/PithosActivityFacility.h index ce71d16..8006962 100644 --- a/pithos-macos/PithosActivityFacility.h +++ b/pithos-macos/PithosActivityFacility.h @@ -66,13 +66,19 @@ message:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes; +- (PithosActivity *)startActivityWithType:(PithosActivityType)type + message:(NSString *)message; - (void)updateActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes; +- (void)updateActivity:(PithosActivity *)activity + withMessage:(NSString *)message; - (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes; +- (void)endActivity:(PithosActivity *)activity + withMessage:(NSString *)message; @end \ No newline at end of file diff --git a/pithos-macos/PithosActivityFacility.m b/pithos-macos/PithosActivityFacility.m index b3b0a52..168476c 100644 --- a/pithos-macos/PithosActivityFacility.m +++ b/pithos-macos/PithosActivityFacility.m @@ -117,7 +117,7 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil; pickedRunning = NO; - timer = [[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain]; + timer = [[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain]; } } @@ -223,10 +223,17 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil; return activity; } +- (PithosActivity *)startActivityWithType:(PithosActivityType)type + message:(NSString *)message { + return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0]; +} + - (void)updateActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes { + if (!activity) + return; NSLog(@"PithosActivityFacility updatedActivity %@", activity); @synchronized(self) { activity.message = message; @@ -250,10 +257,17 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil; NSLog(@"PithosActivityFacility %@", self); } +- (void)updateActivity:(PithosActivity *)activity + withMessage:(NSString *)message { + [self updateActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes]; +} + - (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes { + if (!activity) + return; @synchronized(self) { [runningActivities removeObject:activity]; activity.message = message; @@ -279,4 +293,9 @@ static PithosActivityFacility *defaultPithosActivityFacility = nil; NSLog(@"PithosActivityFacility %@", self); } +- (void)endActivity:(PithosActivity *)activity + withMessage:(NSString *)message { + [self endActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes]; +} + @end diff --git a/pithos-macos/PithosBrowserController.h b/pithos-macos/PithosBrowserController.h index 3e107df..c3e1e85 100644 --- a/pithos-macos/PithosBrowserController.h +++ b/pithos-macos/PithosBrowserController.h @@ -54,15 +54,14 @@ NSViewController *sharedPreviewController; - NSMenu *browserMenu; - NSMenu *outlineViewMenu; - NSSplitView *verticalSplitView; NSSplitView *horizontalSplitView; NSView *leftTopView; NSView *leftBottomView; NSOutlineView *outlineView; NSBrowser *browser; + NSMenu *outlineViewMenu; + NSMenu *browserMenu; NSArray *draggedNodes; PithosNode *draggedParentNode; @@ -84,6 +83,8 @@ @property (nonatomic, assign) IBOutlet NSView *leftBottomView; @property (nonatomic, assign) IBOutlet NSOutlineView *outlineView; @property (nonatomic, assign) IBOutlet NSBrowser *browser; +@property (nonatomic, assign) IBOutlet NSMenu *outlineViewMenu; +@property (nonatomic, assign) IBOutlet NSMenu *browserMenu; @property (nonatomic, retain) NSArray *draggedNodes; @property (nonatomic, retain) PithosNode *draggedParentNode; @@ -95,6 +96,7 @@ @property (nonatomic, assign) IBOutlet NSTextField *activityTextField; @property (nonatomic, assign) IBOutlet NSProgressIndicator *activityProgressIndicator; +- (IBAction)forceRefresh:(id)sender; - (IBAction)refresh:(id)sender; @end diff --git a/pithos-macos/PithosBrowserController.m b/pithos-macos/PithosBrowserController.m index dc5832d..0b42490 100644 --- a/pithos-macos/PithosBrowserController.m +++ b/pithos-macos/PithosBrowserController.m @@ -51,8 +51,8 @@ #import "ASIPithosAccount.h" #import "ASIPithosContainer.h" #import "ASIPithosObject.h" -#import "PithosFileUtilities.h" -#import "BytesExtendedSizeTransformer.h" +#import "PithosUtilities.h" +#import "BytesSizeTransformer.h" @interface PithosBrowserCell : FileSystemBrowserCell {} @end @@ -106,7 +106,7 @@ @implementation PithosBrowserController @synthesize accountNode; -@synthesize verticalSplitView, horizontalSplitView, leftTopView, leftBottomView, outlineView, browser; +@synthesize verticalSplitView, horizontalSplitView, leftTopView, leftBottomView, outlineView, browser, outlineViewMenu, browserMenu; @synthesize draggedNodes, draggedParentNode; @synthesize clipboardNodes, clipboardParentNode, clipboardCopy; @synthesize activityTextField, activityProgressIndicator; @@ -124,8 +124,6 @@ [clipboardNodes release]; [draggedParentNode release]; [draggedNodes release]; - [outlineViewMenu release]; - [browserMenu release]; [sharedPreviewController release]; [othersSharedNode release]; [mySharedNode release]; @@ -149,14 +147,6 @@ [outlineView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO]; [browser setCellClass:[PithosBrowserCell class]]; - - browserMenu = [[NSMenu alloc] init]; - [browserMenu setDelegate:self]; - [browser setMenu:browserMenu]; - - outlineViewMenu = [[NSMenu alloc] init]; - [outlineViewMenu setDelegate:self]; - [outlineView setMenu:outlineViewMenu]; } - (void)resetContainers:(NSNotification *)notification { @@ -283,9 +273,12 @@ if (!containerPithosFound) { // Create pithos node ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"]; - [containerRequest startSynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + while (![containerRequest isFinished]) { + sleep(1); + } if ([containerRequest error]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; } else { refreshAccountNode = YES; } @@ -293,9 +286,12 @@ if (!containerTrashFound) { // Create trash node ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"]; - [containerRequest startSynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + while (![containerRequest isFinished]) { + sleep(1); + } if ([containerRequest error]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; } else { refreshAccountNode = YES; } @@ -325,24 +321,28 @@ #pragma mark - #pragma mark Actions +- (IBAction)forceRefresh:(id)sender { + if (sender) + [accountNode forceRefresh]; + for (NSInteger column = [browser lastColumn]; column >= 0; column--) { + PithosNode *node = (PithosNode *)[browser parentForItemsInColumn:column]; + node.forcedRefresh = YES; + [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren]; + } + [browser validateVisibleColumns]; +} + - (IBAction)refresh:(id)sender { if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) { - if (sender) - [accountNode forceRefresh]; - for (NSInteger column = [browser lastColumn]; column >= 0; column--) { - PithosNode *node = (PithosNode *)[browser parentForItemsInColumn:column]; - node.forcedRefresh = YES; - [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren]; - //[(PithosNode *)[browser parentForItemsInColumn:column] forceRefresh]; - } + [self forceRefresh:sender]; } else { if (sender) [accountNode refresh]; for (NSInteger column = [browser lastColumn]; column >= 0; column--) { [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren]; } + [browser validateVisibleColumns]; } - [browser validateVisibleColumns]; } #pragma mark - @@ -413,9 +413,7 @@ return; } if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && - !node.pithosObject.subdir && - [node.pithosObject.name hasSuffix:@"/"])) { + (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName]; @@ -423,11 +421,11 @@ destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; NSError *error = nil; BOOL isDirectory; - if ([PithosFileUtilities objectExistsAtContainerName:node.pithosContainer.name - objectName:destinationObjectName - error:&error - isDirectory:&isDirectory - sharingAccount:nil]) { + if ([PithosUtilities objectExistsAtContainerName:node.pithosContainer.name + objectName:destinationObjectName + error:&error + isDirectory:&isDirectory + sharingAccount:nil]) { NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"Name Taken"]; [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]]; @@ -437,19 +435,29 @@ } else if (error) { return; } - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:node.pithosContainer.name - destinationObjectName:destinationObjectName - checkIfExists:NO]; + ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:node.pithosContainer.name + objectName:node.pithosObject.name + destinationContainerName:node.pithosContainer.name + destinationObjectName:destinationObjectName + checkIfExists:NO]; if (objectRequest) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(moveFinished:); objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } }); } else if ([node class] == [PithosSubdirNode class]) { @@ -460,11 +468,11 @@ NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName]; NSError *error = nil; BOOL isDirectory; - if ([PithosFileUtilities objectExistsAtContainerName:node.pithosContainer.name - objectName:destinationObjectName - error:&error - isDirectory:&isDirectory - sharingAccount:nil]) { + if ([PithosUtilities objectExistsAtContainerName:node.pithosContainer.name + objectName:destinationObjectName + error:&error + isDirectory:&isDirectory + sharingAccount:nil]) { NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"Name Taken"]; [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]]; @@ -476,20 +484,30 @@ } if (node.pithosObject.subdir) destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:node.pithosContainer.name - destinationObjectName:destinationObjectName - checkIfExists:NO]; + NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name + objectName:node.pithosObject.name + destinationContainerName:node.pithosContainer.name + destinationObjectName:destinationObjectName + checkIfExists:NO]; if (objectRequests) { for (ASIPithosObjectRequest *objectRequest in objectRequests) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(moveFinished:); objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } }); @@ -545,13 +563,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (choice == NSAlertFirstButtonReturn) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSArray *objectRequests = [PithosFileUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name + NSArray *objectRequests = [PithosUtilities objectDataRequestsForSubdirWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name toDirectory:[dropDestination path] checkIfExists:YES sharingAccount:node.sharingAccount]; if (objectRequests) { - for (ASIPithosObjectRequest *objectRequest in objectRequests) { + for (__block ASIPithosObjectRequest *objectRequest in objectRequests) { [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]]; objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(downloadObjectFinished:); @@ -560,18 +578,28 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { message:[NSString stringWithFormat:@"Downloading '%@' (0%%)", [objectRequest.userInfo objectForKey:@"fileName"]] totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue] currentBytes:0]; - [(NSMutableDictionary *)objectRequest.userInfo setObject:activity forKey:@"activity"]; - [objectRequest startAsynchronous]; + [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){ + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Downloading '%@' (%.0f%%)", [objectRequest.userInfo valueForKey:@"fileName"], (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] + totalBytes:activity.totalBytes + currentBytes:(activity.currentBytes + size)]; + }]; + [[PithosUtilities prepareRequest:objectRequest] startAsynchronous]; } } }); } } else { - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities objectDataRequestWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - toDirectory:[dropDestination path] - checkIfExists:YES - sharingAccount:node.sharingAccount]; + __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectDataRequestWithContainerName:node.pithosContainer.name + objectName:node.pithosObject.name + toDirectory:[dropDestination path] + checkIfExists:YES + sharingAccount:node.sharingAccount]; if (objectRequest) { [names addObject:[objectRequest.userInfo valueForKey:@"fileName"]]; objectRequest.delegate = self; @@ -581,8 +609,18 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { message:[NSString stringWithFormat:@"Downloading '%@' (0%%)", [objectRequest.userInfo valueForKey:@"fileName"]] totalBytes:node.pithosObject.bytes currentBytes:0]; - [(NSMutableDictionary *)objectRequest.userInfo setObject:activity forKey:@"activity"]; - [objectRequest startAsynchronous]; + [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){ + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Downloading '%@' (%.0f%%)", [objectRequest.userInfo valueForKey:@"fileName"], (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] + totalBytes:activity.totalBytes + currentBytes:(activity.currentBytes + size)]; + }]; + [[PithosUtilities prepareRequest:objectRequest] startAsynchronous]; } } } @@ -671,7 +709,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSArray *filenames = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType]; NSLog(@"drag in operation: %lu filenames: %@", [info draggingSourceOperationMask], filenames); if ((column != -1) && (filenames != nil)) { - PithosNode *node = nil; + PithosNode *node; if (row != -1) node = [browser itemAtRow:row inColumn:column]; else @@ -682,7 +720,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else if ([[[info draggingPasteboard] types] containsObject:NSFilesPromisePboardType]) { NSLog(@"drag local operation: %lu nodes: %@", [info draggingSourceOperationMask], draggedNodes); if ((column != -1) && (draggedNodes != nil)) { - PithosNode *node = nil; + PithosNode *node; if (row != -1) node = [browser itemAtRow:row inColumn:column]; else @@ -712,12 +750,15 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { objectNamePrefix = [NSString string]; if ((destinationNode.pithosContainer.blockHash == nil) || (destinationNode.pithosContainer.blockSize == 0)) { ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest containerMetadataRequestWithContainerName:containerName]; - [containerRequest startSynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + while (![containerRequest isFinished]) { + sleep(1); + } if ([containerRequest error]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; return NO; } else if (containerRequest.responseStatusCode != 200) { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:containerRequest]; return NO; } destinationNode.pithosContainer.blockHash = [containerRequest blockHash]; @@ -735,21 +776,21 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSError *error = nil; - NSString *contentType = [PithosFileUtilities contentTypeOfFile:filePath error:&error]; + NSString *contentType = [PithosUtilities contentTypeOfFile:filePath error:&error]; if (contentType == nil) contentType = @"application/octet-stream"; if (error) NSLog(@"contentType detection error: %@", error); NSArray *hashes = nil; - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:containerName - objectName:objectName - contentType:contentType - blockSize:blockSize - blockHash:blockHash - forFile:filePath - checkIfExists:YES - hashes:&hashes - sharingAccount:destinationNode.sharingAccount]; + ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithContainerName:containerName + objectName:objectName + contentType:contentType + blockSize:blockSize + blockHash:blockHash + forFile:filePath + checkIfExists:YES + hashes:&hashes + sharingAccount:destinationNode.sharingAccount]; if (objectRequest) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); @@ -767,13 +808,15 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { blockHash, @"blockHash", filePath, @"filePath", hashes, @"hashes", - destinationNode, @"node", + [NSArray arrayWithObject:destinationNode], @"refreshNodes", + [NSNumber numberWithBool:YES], @"refresh", [NSNumber numberWithUnsignedInteger:10], @"iteration", activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", nil]]; if (destinationNode.sharingAccount) [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"]; - [objectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:objectRequest] startAsynchronous]; } }); } else { @@ -793,7 +836,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSMutableArray *filePaths = nil; NSMutableArray *hashesArrays = nil; NSMutableArray *directoryObjectRequests = nil; - NSArray *objectRequests = [PithosFileUtilities writeObjectDataRequestsWithContainerName:containerName + NSArray *objectRequests = [PithosUtilities writeObjectDataRequestsWithContainerName:containerName objectName:objectName blockSize:blockSize blockHash:blockHash @@ -809,7 +852,15 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:); - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory + message:[NSString stringWithFormat:@"Creating directory '%@'", [objectRequest.userInfo valueForKey:@"fileName"]]]; + [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest] startAsynchronous]; } if (objectRequests) { for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) { @@ -830,12 +881,14 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { blockHash, @"blockHash", [filePaths objectAtIndex:i], @"filePath", [hashesArrays objectAtIndex:i], @"hashes", + [NSNumber numberWithBool:YES], @"refresh", [NSNumber numberWithUnsignedInteger:10], @"iteration", activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", nil]]; if (destinationNode.sharingAccount) [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"]; - [objectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:objectRequest] startAsynchronous]; } } }); @@ -847,7 +900,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } - (BOOL)moveNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode { - if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) + if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) || + (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) return NO; NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name]; NSString *objectNamePrefix; @@ -858,15 +912,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { for (PithosNode *node in nodes) { if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && - !node.pithosObject.subdir && - [node.pithosObject.name hasSuffix:@"/"])) { + (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; if ([node.pithosObject.name hasSuffix:@"/"]) destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name + ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:containerName destinationObjectName:destinationObjectName @@ -875,11 +927,19 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(moveFinished:); objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - destinationNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } }); } else if ([node class] == [PithosSubdirNode class]) { @@ -888,7 +948,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; if (node.pithosObject.subdir) destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name + NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:containerName destinationObjectName:destinationObjectName @@ -898,11 +958,20 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(moveFinished:); objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - destinationNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } }); @@ -912,7 +981,8 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } - (BOOL)copyNodes:(NSArray *)nodes toNode:(PithosNode *)destinationNode { - if (([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) + if ((([destinationNode class] != [PithosSubdirNode class]) && ([destinationNode class] != [PithosContainerNode class])) || + (([destinationNode class] == [PithosSubdirNode class]) && !destinationNode.pithosObject.subdir && [destinationNode.pithosObject.name hasSuffix:@"/"])) return NO; NSString *containerName = [NSString stringWithString:destinationNode.pithosContainer.name]; NSString *objectNamePrefix; @@ -923,9 +993,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { for (PithosNode *node in nodes) { if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && - !node.pithosObject.subdir && - [node.pithosObject.name hasSuffix:@"/"])) { + (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSString *destinationObjectName; @@ -934,23 +1002,32 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if ([node.pithosObject.name hasSuffix:@"/"]) destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; } else { - destinationObjectName = [PithosFileUtilities safeObjectNameForContainerName:containerName - objectName:node.pithosObject.name]; + destinationObjectName = [PithosUtilities safeObjectNameForContainerName:containerName + objectName:node.pithosObject.name]; } - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities copyObjectRequestWithContainerName:node.pithosContainer.name + ASIPithosObjectRequest *objectRequest = [PithosUtilities copyObjectRequestWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:containerName destinationObjectName:destinationObjectName checkIfExists:YES - sharingAccount:nil]; + sharingAccount:node.sharingAccount]; if (objectRequest) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(copyFinished:); objectRequest.didFailSelector = @selector(copyFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - destinationNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy + message:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } }); } else if ([node class] == [PithosSubdirNode class]) { @@ -962,24 +1039,33 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (node.pithosObject.subdir) destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; } else { - destinationObjectName = [PithosFileUtilities safeSubdirNameForContainerName:containerName + destinationObjectName = [PithosUtilities safeSubdirNameForContainerName:containerName subdirName:node.pithosObject.name]; } - NSArray *objectRequests = [PithosFileUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name + NSArray *objectRequests = [PithosUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:containerName destinationObjectName:destinationObjectName checkIfExists:YES - sharingAccount:nil]; + sharingAccount:node.sharingAccount]; if (objectRequests) { for (ASIPithosObjectRequest *objectRequest in objectRequests) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(copyFinished:); objectRequest.didFailSelector = @selector(copyFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - destinationNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy + message:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } }); @@ -992,16 +1078,13 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { #pragma mark ASIHTTPRequestDelegate - (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Download completed: %@", [objectRequest url]); - - NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"]; - NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"]; - PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; - NSString *activityMessage; - NSUInteger totalBytes = activity.totalBytes; - NSUInteger currentBytes = activity.currentBytes; - + NSLog(@"Download finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 200) { + NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"]; + PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; + NSUInteger totalBytes = activity.totalBytes; + NSUInteger currentBytes = activity.currentBytes; + // XXX change contentLength to objectContentLength if it is fixed in the server if (([objectRequest contentLength] == 0) && (![[objectRequest contentType] isEqualToString:@"application/directory"])) { NSLog(@"Downloaded 0 bytes"); @@ -1020,68 +1103,116 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { currentBytes = [objectRequest objectContentLength]; if (currentBytes == 0) currentBytes = totalBytes; - activityMessage = [NSString stringWithFormat:@"Downloading '%@' (100%%)", fileName]; - + [activityFacility endActivity:activity + withMessage:[NSString stringWithFormat:@"Downloading '%@' (100%%)", + [objectRequest.userInfo objectForKey:@"fileName"]] + totalBytes:totalBytes + currentBytes:currentBytes]; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; - - activityMessage = [NSString stringWithFormat:@"Downloading '%@' (failed)", fileName]; + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } } - - [activityFacility endActivity:activity withMessage:activityMessage totalBytes:totalBytes currentBytes:currentBytes]; } - (void)downloadObjectFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Download failed"); - NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"]; - PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; - [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", fileName] - totalBytes:activity.totalBytes - currentBytes:activity.currentBytes]; + NSLog(@"Download failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Downloading '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } } - (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Upload directory object completed: %@", [objectRequest url]); + NSLog(@"Upload directory object finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 201) { - NSLog(@"Directory object created: %@", [objectRequest url]); - [self refresh:nil]; + NSLog(@"Directory object created: %@", objectRequest.url); + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Creating directory '%@' (finished)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) { + [node forceRefresh]; + } + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) { + [node refresh]; + } + if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue]) + [self forceRefresh:self]; + else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue]) + [self refresh:self]; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Creating directory '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } } } - (void)uploadDirectoryObjectFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Upload directory object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; + NSLog(@"Upload directory object failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Creating directory '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } } - (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Upload using hashmap completed: %@", [objectRequest url]); + NSLog(@"Upload using hashmap finished: %@", objectRequest.url); NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"]; PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; NSUInteger totalBytes = activity.totalBytes; NSUInteger currentBytes = activity.currentBytes; if (objectRequest.responseStatusCode == 201) { - NSLog(@"Object created: %@", [objectRequest url]); + NSLog(@"Object created: %@", objectRequest.url); [activityFacility endActivity:activity withMessage:[NSString stringWithFormat:@"Uploading '%@' (100%%)", fileName] totalBytes:totalBytes currentBytes:totalBytes]; - PithosNode *node = [objectRequest.userInfo objectForKey:@"node"]; - if (node) + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) { + [node forceRefresh]; + } + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) { [node refresh]; - else - [self refresh:nil]; + } + if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue]) + [self forceRefresh:self]; + else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue]) + [self refresh:self]; } else if (objectRequest.responseStatusCode == 409) { - NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue] - 1; + NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue]; if (iteration == 0) { - NSLog(@"Upload iteration limit reached: %@", [objectRequest url]); + NSLog(@"Upload iteration limit reached: %@", objectRequest.url); [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] - totalBytes:totalBytes - currentBytes:currentBytes]; + withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]]; NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"Upload Timeout"]; [alert setInformativeText:[NSString stringWithFormat:@"Upload iteration limit reached for object with path '%@'", @@ -1090,48 +1221,68 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { [alert runModal]; return; } - NSLog(@"object is missing hashes: %@", [objectRequest url]); - NSIndexSet *missingBlocks = [PithosFileUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"] - withMissingHashesResponse:[objectRequest responseString]]; + NSLog(@"object is missing hashes: %@", objectRequest.url); + NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"] + withMissingHashesResponse:[objectRequest responseString]]; NSUInteger blockSize = [[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]; if (totalBytes >= [missingBlocks count]*blockSize) currentBytes = totalBytes - [missingBlocks count]*blockSize; + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] + totalBytes:totalBytes + currentBytes:currentBytes]; NSUInteger missingBlockIndex = [missingBlocks firstIndex]; - ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] - blockSize:blockSize - forFile:[objectRequest.userInfo objectForKey:@"filePath"] - missingBlockIndex:missingBlockIndex - sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]]; + __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithContainerName:[objectRequest.userInfo objectForKey:@"containerName"] + blockSize:blockSize + forFile:[objectRequest.userInfo objectForKey:@"filePath"] + missingBlockIndex:missingBlockIndex + sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]]; newContainerRequest.delegate = self; newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:); newContainerRequest.didFailSelector = @selector(uploadMissingBlockFailed:); newContainerRequest.userInfo = objectRequest.userInfo; - [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:iteration] forKey:@"iteration"]; + [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"]; + [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; - [activityFacility updateActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] - totalBytes:totalBytes - currentBytes:currentBytes]; - [newContainerRequest startAsynchronous]; + [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){ + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] + totalBytes:activity.totalBytes + currentBytes:(activity.currentBytes + size)]; + }]; + [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } } } - (void)uploadObjectUsingHashMapFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Upload using hashmap failed"); - NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"]; - PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; - [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] - totalBytes:activity.totalBytes - currentBytes:activity.currentBytes]; - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; + NSLog(@"Upload using hashmap failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } } - (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest { - NSLog(@"Upload of missing block completed: %@", [containerRequest url]); + NSLog(@"Upload of missing block finished: %@", containerRequest.url); NSUInteger blockSize = [[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue]; NSString *fileName = [containerRequest.userInfo objectForKey:@"fileName"]; PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"]; @@ -1140,105 +1291,235 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (currentBytes > totalBytes) currentBytes = totalBytes; if (containerRequest.responseStatusCode == 202) { + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] + totalBytes:totalBytes + currentBytes:currentBytes]; NSIndexSet *missingBlocks = [containerRequest.userInfo objectForKey:@"missingBlocks"]; NSUInteger missingBlockIndex = [[containerRequest.userInfo objectForKey:@"missingBlockIndex"] unsignedIntegerValue]; missingBlockIndex = [missingBlocks indexGreaterThanIndex:missingBlockIndex]; if (missingBlockIndex == NSNotFound) { NSArray *hashes = [containerRequest.userInfo objectForKey:@"hashes"]; - ASIPithosObjectRequest *newObjectRequest = [PithosFileUtilities writeObjectDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] - objectName:[containerRequest.userInfo objectForKey:@"objectName"] - contentType:[containerRequest.userInfo objectForKey:@"contentType"] - blockSize:blockSize - blockHash:[containerRequest.userInfo objectForKey:@"blockHash"] - forFile:[containerRequest.userInfo objectForKey:@"filePath"] - checkIfExists:NO - hashes:&hashes - sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]]; + ASIPithosObjectRequest *newObjectRequest = [PithosUtilities writeObjectDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] + objectName:[containerRequest.userInfo objectForKey:@"objectName"] + contentType:[containerRequest.userInfo objectForKey:@"contentType"] + blockSize:blockSize + blockHash:[containerRequest.userInfo objectForKey:@"blockHash"] + forFile:[containerRequest.userInfo objectForKey:@"filePath"] + checkIfExists:NO + hashes:&hashes + sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]]; newObjectRequest.delegate = self; newObjectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); newObjectRequest.didFailSelector = @selector(uploadObjectUsingHashMapFailed:); newObjectRequest.userInfo = containerRequest.userInfo; + [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"]; - [activityFacility updateActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] - totalBytes:totalBytes - currentBytes:currentBytes]; - [newObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { - ASIPithosContainerRequest *newContainerRequest = [PithosFileUtilities updateContainerDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] - blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue] - forFile:[containerRequest.userInfo objectForKey:@"filePath"] - missingBlockIndex:missingBlockIndex - sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]]; + __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithContainerName:[containerRequest.userInfo objectForKey:@"containerName"] + blockSize:[[containerRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue] + forFile:[containerRequest.userInfo objectForKey:@"filePath"] + missingBlockIndex:missingBlockIndex + sharingAccount:[containerRequest.userInfo objectForKey:@"sharingAccount"]]; newContainerRequest.delegate = self; newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:); newContainerRequest.didFailSelector = @selector(uploadMissingBlockFailed:); newContainerRequest.userInfo = containerRequest.userInfo; + [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; - [activityFacility updateActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.2f%%)", fileName, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] - totalBytes:totalBytes - currentBytes:currentBytes]; - [newContainerRequest startAsynchronous]; + [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){ + [activityFacility updateActivity:activity + withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] + totalBytes:activity.totalBytes + currentBytes:(activity.currentBytes + size)]; + }]; + [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; } } else { - [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] - totalBytes:activity.totalBytes - currentBytes:activity.currentBytes]; - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:containerRequest]; + NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:containerRequest]; + } } } - (void)uploadMissingBlockFailed:(ASIPithosContainerRequest *)containerRequest { - NSLog(@"Upload of missing block failed"); - NSString *fileName = [containerRequest.userInfo objectForKey:@"fileName"]; - PithosActivity *activity = [containerRequest.userInfo objectForKey:@"activity"]; - [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", fileName] - totalBytes:activity.totalBytes - currentBytes:activity.currentBytes]; - [PithosFileUtilities httpRequestErrorAlertWithRequest:containerRequest]; + NSLog(@"Upload of missing block failed: %@", containerRequest.url); + NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; + } else { + [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Uploading '%@' (failed)", + [containerRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; + } } - (void)moveFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Move object completed: %@", [objectRequest url]); + NSLog(@"Move object finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 201) { - PithosNode *node = [objectRequest.userInfo objectForKey:@"node"]; - PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"]; - if (node) + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' (finished)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) { + [node forceRefresh]; + } + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) { [node refresh]; - if (dropNode) - [dropNode refresh]; - if (!node || !dropNode) - [self refresh:nil]; + } + if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue]) + [self forceRefresh:self]; + else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue]) + [self refresh:self]; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' (failed)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } } } - (void)moveFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Move object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; + NSLog(@"Move object failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@' (failed)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } } - (void)copyFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Copy object completed: %@", [objectRequest url]); + NSLog(@"Copy object finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 201) { - PithosNode *dropNode = [objectRequest.userInfo objectForKey:@"dropNode"]; - if (dropNode) - [dropNode refresh]; - else - [self refresh:nil]; + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' (finished)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) { + [node forceRefresh]; + } + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) { + [node refresh]; + } + if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue]) + [self forceRefresh:self]; + else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue]) + [self refresh:self]; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' (failed)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } } } - (void)copyFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Copy object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; + NSLog(@"Copy object failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@' (failed)", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } +} + +- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest { + NSLog(@"Delete object finished: %@", objectRequest.url); + if (objectRequest.responseStatusCode == 204) { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Deleting '%@' (finished)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) { + [node forceRefresh]; + } + for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) { + [node refresh]; + } + if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue]) + [self forceRefresh:self]; + else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue]) + [self refresh:self]; + } else { + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Deleting '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; + } + } +} + +- (void)deleteObjectFailed:(ASIPithosObjectRequest *)objectRequest { + NSLog(@"Delete object failed: %@", objectRequest.url); + NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + } else { + [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[NSString stringWithFormat:@"Deleting '%@' (failed)", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [PithosUtilities httpRequestErrorAlertWithRequest:objectRequest]; + } } #pragma mark - @@ -1248,14 +1529,14 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (splitView == verticalSplitView) return 120; else - return ([horizontalSplitView bounds].size.height - 101); + return ([horizontalSplitView bounds].size.height - 108); } - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex { if (splitView == verticalSplitView) return 220; else - return ([horizontalSplitView bounds].size.height - 101); + return ([horizontalSplitView bounds].size.height - 108); } - (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex { @@ -1267,7 +1548,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { else return proposedPosition; } else { - return ([horizontalSplitView bounds].size.height - 101); + return ([horizontalSplitView bounds].size.height - 108); } } @@ -1546,8 +1827,9 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if ([node class] == [PithosContainerNode class]) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name + NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:node.pithosContainer.name subdirName:@"untitled folder"]; + NSString *fileName = [safeObjectName lastPathComponent]; ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name objectName:safeObjectName eTag:nil @@ -1560,20 +1842,26 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { metadata:nil data:[NSData data]]; objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(newFolderFinished:); - objectRequest.didFailSelector = @selector(newFolderFailed:); + objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); + objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:); + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory + message:[NSString stringWithFormat:@"Creating directory '%@'", fileName]]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node, @"node", + fileName, @"fileName", + [NSArray arrayWithObject:node], @"refreshNodes", + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", nil]; - [objectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; }); } else if (([node class] == [PithosSubdirNode class]) && - (node.pithosObject.subdir || - ![node.pithosObject.name hasSuffix:@"/"])) { + (node.pithosObject.subdir || ![node.pithosObject.name hasSuffix:@"/"])) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:node.pithosContainer.name + NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:node.pithosContainer.name subdirName:[node.pithosObject.name stringByAppendingPathComponent:@"untitled folder"]]; + NSString *fileName = [safeObjectName lastPathComponent]; ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:node.pithosContainer.name objectName:safeObjectName eTag:nil @@ -1586,12 +1874,18 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { metadata:nil data:[NSData data]]; objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(newFolderFinished:); - objectRequest.didFailSelector = @selector(newFolderFailed:); + objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); + objectRequest.didFailSelector = @selector(uploadDirectoryObjectFailed:); + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory + message:[NSString stringWithFormat:@"Creating directory '%@'", fileName]]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node, @"node", - nil]; - [objectRequest startAsynchronous]; + fileName, @"fileName", + [NSArray arrayWithObject:node], @"refreshNodes", + [NSNumber numberWithBool:YES], @"refresh", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; }); } } @@ -1605,26 +1899,42 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { - (void)menuDelete:(NSMenuItem *)sender { for (PithosNode *node in ((NSArray *)[sender representedObject])) { if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && - !node.pithosObject.subdir && - [node.pithosObject.name hasSuffix:@"/"])) { + (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name]; objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(deleteObjectFinished:); objectRequest.didFailSelector = @selector(deleteObjectFailed:); - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete + message:[NSString stringWithFormat:@"Deleting '%@'", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else if ([node class] == [PithosSubdirNode class]) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSArray *objectRequests = [PithosFileUtilities deleteObjectRequestsForSubdirWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name]; + NSArray *objectRequests = [PithosUtilities deleteObjectRequestsForSubdirWithContainerName:node.pithosContainer.name + objectName:node.pithosObject.name]; if (objectRequests) { for (ASIPithosObjectRequest *objectRequest in objectRequests) { objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(deleteObjectFinished:); objectRequest.didFailSelector = @selector(deleteObjectFailed:); - [objectRequest startAsynchronous]; + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete + message:[NSString stringWithFormat:@"Deleting '%@'", + [objectRequest.userInfo objectForKey:@"fileName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } }); @@ -1640,29 +1950,41 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { [node.pithosObject.name hasSuffix:@"/"])) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSString *safeObjectName = [PithosFileUtilities safeObjectNameForContainerName:@"trash" + NSString *safeObjectName = [PithosUtilities safeObjectNameForContainerName:@"trash" objectName:node.pithosObject.name]; if (safeObjectName) { - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name + ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:@"trash" destinationObjectName:safeObjectName checkIfExists:NO]; if (objectRequest) { objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(moveToTrashFinished:); - objectRequest.didFailSelector = @selector(moveToTrashFailed:); - [objectRequest startAsynchronous]; + objectRequest.didFinishSelector = @selector(moveFinished:); + objectRequest.didFailSelector = @selector(moveFailed:); + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } }); } else if ([node class] == [PithosSubdirNode class]) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ - NSString *safeObjectName = [PithosFileUtilities safeSubdirNameForContainerName:@"trash" + NSString *safeObjectName = [PithosUtilities safeSubdirNameForContainerName:@"trash" subdirName:node.pithosObject.name]; if (safeObjectName) { - NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name + NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name objectName:node.pithosObject.name destinationContainerName:@"trash" destinationObjectName:safeObjectName @@ -1670,9 +1992,21 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (objectRequests) { for (ASIPithosObjectRequest *objectRequest in objectRequests) { objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(moveToTrashFinished:); - objectRequest.didFailSelector = @selector(moveToTrashFailed:); - [objectRequest startAsynchronous]; + objectRequest.didFinishSelector = @selector(moveFinished:); + objectRequest.didFailSelector = @selector(moveFailed:); + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove + message:[NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", + [objectRequest.userInfo objectForKey:@"sourceContainerName"], + [objectRequest.userInfo objectForKey:@"sourceObjectName"], + [objectRequest.userInfo objectForKey:@"destinationContainerName"], + [objectRequest.userInfo objectForKey:@"destinationObjectName"]]]; + [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", + activity, @"activity", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } } @@ -1697,187 +2031,17 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (!clipboardNodes || ![clipboardNodes count]) return; PithosNode *dropNode = (PithosNode *)[sender representedObject]; - if ((([dropNode class] != [PithosSubdirNode class]) && ([dropNode class] != [PithosContainerNode class])) || - (([dropNode class] == [PithosSubdirNode class]) && !dropNode.pithosObject.subdir && [dropNode.pithosObject.name hasSuffix:@"/"])) - return; - - NSString *containerName = [NSString stringWithString:dropNode.pithosContainer.name]; - NSString *objectNamePrefix; - if ([dropNode class] == [PithosSubdirNode class]) - objectNamePrefix = [NSString stringWithString:dropNode.pithosObject.name]; - else - objectNamePrefix = [NSString string]; - NSArray *localClipboardNodes = [NSArray arrayWithArray:clipboardNodes]; if (!clipboardCopy && ![dropNode isEqualTo:clipboardParentNode]) { self.clipboardNodes = nil; self.clipboardParentNode = nil; - for (PithosNode *node in localClipboardNodes) { - if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; - if ([node.pithosObject.name hasSuffix:@"/"]) - destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities moveObjectRequestWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:containerName - destinationObjectName:destinationObjectName - checkIfExists:YES]; - if (objectRequest) { - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(moveFinished:); - objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - dropNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; - } - }); - } else if ([node class] == [PithosSubdirNode class]) { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; - if (node.pithosObject.subdir) - destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - NSArray *objectRequests = [PithosFileUtilities moveObjectRequestsForSubdirWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:containerName - destinationObjectName:destinationObjectName - checkIfExists:YES]; - if (objectRequests) { - for (ASIPithosObjectRequest *objectRequest in objectRequests) { - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(moveFinished:); - objectRequest.didFailSelector = @selector(moveFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - node.parent, @"node", - dropNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; - } - } - }); - } - } + [self moveNodes:localClipboardNodes toNode:dropNode]; } else { - for (PithosNode *node in localClipboardNodes) { - if (([node class] == [PithosObjectNode class]) || - (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSString *destinationObjectName; - if (![dropNode isEqualTo:node.parent]) { - destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; - if ([node.pithosObject.name hasSuffix:@"/"]) - destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - } else { - destinationObjectName = [PithosFileUtilities safeObjectNameForContainerName:containerName - objectName:node.pithosObject.name]; - } - ASIPithosObjectRequest *objectRequest = [PithosFileUtilities copyObjectRequestWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:containerName - destinationObjectName:destinationObjectName - checkIfExists:YES - sharingAccount:node.sharingAccount]; - if (objectRequest) { - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(copyFinished:); - objectRequest.didFailSelector = @selector(copyFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - dropNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; - } - }); - } else if ([node class] == [PithosSubdirNode class]) { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_async(queue, ^{ - NSString *destinationObjectName; - if (![dropNode isEqualTo:node.parent]) { - destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName]; - if (node.pithosObject.subdir) - destinationObjectName = [destinationObjectName stringByAppendingString:@"/"]; - } else { - destinationObjectName = [PithosFileUtilities safeSubdirNameForContainerName:containerName - subdirName:node.pithosObject.name]; - } - NSArray *objectRequests = [PithosFileUtilities copyObjectRequestsForSubdirWithContainerName:node.pithosContainer.name - objectName:node.pithosObject.name - destinationContainerName:containerName - destinationObjectName:destinationObjectName - checkIfExists:YES - sharingAccount:node.sharingAccount]; - if (objectRequests) { - for (ASIPithosObjectRequest *objectRequest in objectRequests) { - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(copyFinished:); - objectRequest.didFailSelector = @selector(copyFailed:); - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - dropNode, @"dropNode", - nil]; - [objectRequest startAsynchronous]; - } - } - }); - } - } + [self copyNodes:localClipboardNodes toNode:dropNode]; } } #pragma mark - -#pragma mark Menu Actions ASIHTTPRequestDelegate - -- (void)newFolderFinished:(ASIPithosObjectRequest *)objectRequest { - if (objectRequest.responseStatusCode == 201) { - NSLog(@"New application/directory object created: %@", [objectRequest url]); - PithosNode *node = [objectRequest.userInfo objectForKey:@"node"]; - if (node) - [node refresh]; - else - [self refresh:nil]; - } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; - } -} - -- (void)newFolderFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Creation of new application/directory object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; -} - -- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest { - if (objectRequest.responseStatusCode == 204) { - NSLog(@"Object deleted: %@", [objectRequest url]); - [self refresh:nil]; - } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; - } -} - -- (void)deleteObjectFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Delete of object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; -} - -- (void)moveToTrashFinished:(ASIPithosObjectRequest *)objectRequest { - if (objectRequest.responseStatusCode == 201) { - NSLog(@"Object moved: %@", [objectRequest url]); - [self refresh:nil]; - } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:objectRequest]; - } -} - -- (void)moveToTrashFailed:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Move of object failed"); - [PithosFileUtilities httpRequestErrorAlertWithRequest:objectRequest]; -} - -#pragma mark - #pragma mark PithosActivityFacilityDelegate - (void)activityUpdate:(NSDictionary *)info { @@ -1899,7 +2063,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { if (!message) message = [NSString stringWithFormat:@"%@ used", - [[[[BytesExtendedSizeTransformer alloc] init] autorelease] transformedValue: + [[[[BytesSizeTransformer alloc] init] autorelease] transformedValue: [NSNumber numberWithUnsignedInteger:accountNode.pithosAccount.bytesUsed]]]; [activityTextField setStringValue:message]; } diff --git a/pithos-macos/PithosBrowserController.xib b/pithos-macos/PithosBrowserController.xib index 98d1970..add5c42 100755 --- a/pithos-macos/PithosBrowserController.xib +++ b/pithos-macos/PithosBrowserController.xib @@ -12,6 +12,7 @@ YES + NSMenu NSToolbarItem NSButton NSToolbarFlexibleSpaceItem @@ -339,7 +340,7 @@ 4352 - {180, 299} + {180, 292} YES @@ -437,7 +438,7 @@ 14 - {180, 299} + {180, 292} @@ -466,7 +467,7 @@ 0.97959183673469385 - {180, 299} + {180, 292} 528 @@ -476,7 +477,7 @@ QSAAAEEgAABBoAAAQaAAAA - {180, 299} + {180, 292} NSView @@ -490,18 +491,18 @@ 1290 - {{7, 35}, {166, 12}} + {{7, 49}, {166, 12}} - + 16648 100 266 - {{5, 6}, {170, 28}} + {{5, 13}, {170, 35}} - + YES 67239424 @@ -509,8 +510,8 @@ LucidaGrande-Bold - 11 - 3357 + 9 + 16 YES @@ -546,9 +547,9 @@ NeXT TIFF v4.0 pasteboard type - {{69, 52}, {42, 42}} + {{69, 66}, {42, 42}} - + YES 130560 @@ -565,7 +566,7 @@ YES - {{0, 300}, {180, 100}} + {{0, 293}, {180, 107}} NSView @@ -638,6 +639,18 @@ YES + + + + YES + + + + + + YES + + @@ -762,6 +775,54 @@ 177 + + + browserMenu + + + + 186 + + + + outlineViewMenu + + + + 187 + + + + menu + + + + 188 + + + + menu + + + + 189 + + + + delegate + + + + 190 + + + + delegate + + + + 191 + @@ -1036,6 +1097,24 @@ + + 178 + + + YES + + + Menu (Browser) + + + 182 + + + YES + + + Menu (Outline View) + @@ -1063,7 +1142,9 @@ 162.IBPluginDependency 165.IBPluginDependency 166.IBPluginDependency + 178.IBPluginDependency 18.IBPluginDependency + 182.IBPluginDependency 19.IBPluginDependency 2.IBPluginDependency 20.IBPluginDependency @@ -1119,6 +1200,8 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin @@ -1133,7 +1216,7 @@ - 177 + 193 0 diff --git a/pithos-macos/PithosContainerNode.m b/pithos-macos/PithosContainerNode.m index 0fa0e2a..820456a 100644 --- a/pithos-macos/PithosContainerNode.m +++ b/pithos-macos/PithosContainerNode.m @@ -42,7 +42,7 @@ #import "ASIPithosContainer.h" #import "ASIPithosObject.h" #import "ASIDownloadCache.h" -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" #import "PithosContainerNodeInfoController.h" static NSImage *sharedIcon = nil; @@ -134,7 +134,7 @@ static NSImage *sharedIcon = nil; containerRequest.didFailSelector = @selector(containerRequestFailed:); if (!forcedRefresh) containerRequest.downloadCache = [ASIDownloadCache sharedCache]; - [containerRequest startAsynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; break; case PithosNodeStateRefreshing: break; @@ -307,12 +307,12 @@ static NSImage *sharedIcon = nil; containerRequest.delegate = self; if (!forcedRefresh) containerRequest.downloadCache = [ASIDownloadCache sharedCache]; - [containerRequest startAsynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } - (void)containerRequestFailed:(ASIPithosContainerRequest *)request { - [PithosFileUtilities httpRequestErrorAlertWithRequest:request]; + [PithosUtilities httpRequestErrorAlertWithRequest:request]; [newChildren release]; newChildren = nil; [containerRequest release]; @@ -347,13 +347,13 @@ static NSImage *sharedIcon = nil; - (void)containerMetadataRequestFailed:(ASIPithosContainerRequest *)request { if ([request isEqualTo:applyMetadataContainerRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest]; @synchronized(self) { [applyMetadataContainerRequest release]; applyMetadataContainerRequest = nil; } } else if ([request isEqualTo:refreshMetadataContainerRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest]; @synchronized(self) { [refreshMetadataContainerRequest release]; refreshMetadataContainerRequest = nil; @@ -378,7 +378,7 @@ static NSImage *sharedIcon = nil; applyMetadataContainerRequest.delegate = self; applyMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:); applyMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:); - [applyMetadataContainerRequest startAsynchronous]; + [[PithosUtilities prepareRequest:applyMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } @@ -391,7 +391,7 @@ static NSImage *sharedIcon = nil; refreshMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:); refreshMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:); refreshMetadataContainerRequest.downloadCache = [ASIDownloadCache sharedCache]; - [refreshMetadataContainerRequest startAsynchronous]; + [[PithosUtilities prepareRequest:refreshMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } diff --git a/pithos-macos/PithosObjectNode.m b/pithos-macos/PithosObjectNode.m index 7688f79..2c1919f 100644 --- a/pithos-macos/PithosObjectNode.m +++ b/pithos-macos/PithosObjectNode.m @@ -41,7 +41,7 @@ #import "ASIPithosContainer.h" #import "ASIPithosObject.h" #import "ASIDownloadCache.h" -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" #import "PithosObjectNodeInfoController.h" @implementation PithosObjectNode @@ -127,7 +127,7 @@ if ([request isEqualTo:applyMetadataObjectRequest]) { int responseStatusCode = applyMetadataObjectRequest.responseStatusCode; if (responseStatusCode != 202) - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; @@ -146,13 +146,13 @@ - (void)objectRequestFailed:(ASIPithosObjectRequest *)request { if ([request isEqualTo:applyMetadataObjectRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; } } else if ([request isEqualTo:refreshMetadataObjectRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; @synchronized(self) { [refreshMetadataObjectRequest release]; refreshMetadataObjectRequest = nil; @@ -192,7 +192,7 @@ applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); - [applyMetadataObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } @@ -208,7 +208,7 @@ refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; - [refreshMetadataObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } diff --git a/pithos-macos/PithosSharingAccountsNode.m b/pithos-macos/PithosSharingAccountsNode.m index 76868ce..9802260 100644 --- a/pithos-macos/PithosSharingAccountsNode.m +++ b/pithos-macos/PithosSharingAccountsNode.m @@ -40,7 +40,7 @@ #import "ASIPithosRequest.h" #import "ASIPithosAccount.h" #import "ASIDownloadCache.h" -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" @implementation PithosSharingAccountsNode @@ -84,7 +84,7 @@ sharingAccountsRequest.didFailSelector = @selector(sharingAccountsRequestFailed:); if (!forcedRefresh) sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache]; - [sharingAccountsRequest startAsynchronous]; + [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; break; case PithosNodeStateRefreshing: break; @@ -170,12 +170,12 @@ sharingAccountsRequest.delegate = self; if (!forcedRefresh) sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache]; - [sharingAccountsRequest startAsynchronous]; + [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } } - (void)accountRequestFailed:(ASIPithosRequest *)request { - [PithosFileUtilities httpRequestErrorAlertWithRequest:request]; + [PithosUtilities httpRequestErrorAlertWithRequest:request]; [newChildren release]; newChildren = nil; [sharingAccountsRequest release]; diff --git a/pithos-macos/PithosSubdirNode.m b/pithos-macos/PithosSubdirNode.m index bed0011..8188c46 100644 --- a/pithos-macos/PithosSubdirNode.m +++ b/pithos-macos/PithosSubdirNode.m @@ -41,7 +41,7 @@ #import "ASIPithosContainer.h" #import "ASIPithosObject.h" #import "ASIDownloadCache.h" -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" #import "PithosObjectNodeInfoController.h" static NSImage *sharedIcon = nil; @@ -136,7 +136,7 @@ static NSImage *sharedIcon = nil; if ([request isEqualTo:applyMetadataObjectRequest]) { int responseStatusCode = applyMetadataObjectRequest.responseStatusCode; if ((responseStatusCode != 201) && (responseStatusCode != 202)) - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; @@ -161,13 +161,13 @@ static NSImage *sharedIcon = nil; - (void)objectRequestFailed:(ASIPithosObjectRequest *)request { if ([request isEqualTo:applyMetadataObjectRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; } } else if ([request isEqualTo:refreshMetadataObjectRequest]) { - [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; + [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; @synchronized(self) { [refreshMetadataObjectRequest release]; refreshMetadataObjectRequest = nil; @@ -186,7 +186,10 @@ static NSImage *sharedIcon = nil; NSAlert *alert; ASIPithosObjectRequest *request = [ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name objectName:prefix]; - [request startSynchronous]; + [[PithosUtilities prepareRequest:request] startAsynchronous]; + while (![request isFinished]) { + sleep(1); + } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"HTTP Request Error"]; @@ -204,7 +207,10 @@ static NSImage *sharedIcon = nil; if (choice == NSAlertFirstButtonReturn) { request = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:pithosContainer.name objectName:prefix]; - [request startSynchronous]; + [[PithosUtilities prepareRequest:request] startAsynchronous]; + while (![request isFinished]) { + sleep(1); + } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"HTTP Request Error"]; @@ -213,7 +219,7 @@ static NSImage *sharedIcon = nil; [alert runModal]; return; } else if (request.responseStatusCode != 204) { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:request]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:request]; return; } refreshParent = YES; @@ -224,7 +230,7 @@ static NSImage *sharedIcon = nil; } else if (request.responseStatusCode == 404) { createObject = YES; } else { - [PithosFileUtilities unexpectedResponseStatusAlertWithRequest:request]; + [PithosUtilities unexpectedResponseStatusAlertWithRequest:request]; return; } if (createObject) { @@ -244,7 +250,7 @@ static NSImage *sharedIcon = nil; applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); - [applyMetadataObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } else { [[pithosNodeInfoController window] makeFirstResponder:nil]; @@ -273,7 +279,7 @@ static NSImage *sharedIcon = nil; applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); - [applyMetadataObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } @@ -292,7 +298,7 @@ static NSImage *sharedIcon = nil; refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; - [refreshMetadataObjectRequest startAsynchronous]; + [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } diff --git a/pithos-macos/PithosFileUtilities.h b/pithos-macos/PithosUtilities.h similarity index 96% rename from pithos-macos/PithosFileUtilities.h rename to pithos-macos/PithosUtilities.h index caf666b..ff7fcc0 100644 --- a/pithos-macos/PithosFileUtilities.h +++ b/pithos-macos/PithosUtilities.h @@ -1,5 +1,5 @@ // -// PithosFileUtilities.h +// PithosUtilities.h // pithos-macos // // Copyright 2011 GRNET S.A. All rights reserved. @@ -39,7 +39,7 @@ @class ASIPithosContainerRequest; @class ASIPithosObjectRequest; -@interface PithosFileUtilities : NSObject +@interface PithosUtilities : NSObject + (ASIPithosObjectRequest *)objectDataRequestWithContainerName:(NSString *)containerName objectName:(NSString *)objectName @@ -129,4 +129,8 @@ + (NSInteger)httpRequestErrorAlertWithRequest:(ASIPithosRequest *)request; + (NSInteger)unexpectedResponseStatusAlertWithRequest:(ASIPithosRequest *)request; ++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request priority:(NSOperationQueuePriority)priority; ++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request; ++ (ASIPithosRequest *)copyRequest:(ASIPithosRequest *)request; + @end diff --git a/pithos-macos/PithosFileUtilities.m b/pithos-macos/PithosUtilities.m similarity index 85% rename from pithos-macos/PithosFileUtilities.m rename to pithos-macos/PithosUtilities.m index dd1ee20..e69dfa5 100644 --- a/pithos-macos/PithosFileUtilities.m +++ b/pithos-macos/PithosUtilities.m @@ -1,5 +1,5 @@ // -// PithosFileUtilities.m +// PithosUtilities.m // pithos-macos // // Copyright 2011 GRNET S.A. All rights reserved. @@ -35,13 +35,13 @@ // interpreted as representing official policies, either expressed // or implied, of GRNET S.A. -#import "PithosFileUtilities.h" +#import "PithosUtilities.h" #import "ASIPithosContainerRequest.h" #import "ASIPithosObjectRequest.h" #import "ASIPithosObject.h" #import "HashMapHash.h" -@implementation PithosFileUtilities +@implementation PithosUtilities #pragma mark - #pragma mark Download @@ -93,6 +93,7 @@ if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; objectRequest.downloadDestinationPath = destinationPath; + objectRequest.allowResumeForFileDownloads = YES; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: fileName, @"fileName", destinationPath, @"filePath", @@ -360,6 +361,9 @@ data:[NSData data]]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [directoryPath lastPathComponent], @"fileName", + nil]; [*directoryObjectRequests addObject:objectRequest]; NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:[subPaths count]]; @@ -419,6 +423,7 @@ } else { subObjectName = [objectName stringByAppendingPathComponent:objectNameSuffix]; + fileName = [filePath lastPathComponent]; objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName objectName:subObjectName eTag:nil @@ -432,6 +437,9 @@ data:[NSData data]]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + fileName, @"fileName", + nil]; [*directoryObjectRequests addObject:objectRequest]; } } @@ -449,11 +457,24 @@ return nil; NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:([objects count] + 1)]; - - if (![objectName hasSuffix:@"/"]) - [objectRequests addObject:[ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:objectName]]; + ASIPithosObjectRequest *objectRequest; + if (![objectName hasSuffix:@"/"]) { + objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:objectName]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [objectName lastPathComponent], @"fileName", + nil]; + [objectRequests addObject:objectRequest]; + } + NSString *fileName; for (ASIPithosObject *object in objects) { - [objectRequests addObject:[ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:object.name]]; + fileName = [object.name lastPathComponent]; + if ([object.name hasSuffix:@"/"]) + fileName = [fileName stringByAppendingString:@"/"]; + objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName objectName:object.name]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + fileName, @"fileName", + nil]; + [objectRequests addObject:objectRequest]; } if ([objectRequests count] == 0) @@ -486,6 +507,12 @@ destinationObjectName:destinationObjectName destinationAccount:nil sourceVersion:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + destinationObjectName, @"destinationObjectName", + nil]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; return objectRequest; @@ -522,6 +549,12 @@ destinationObjectName:objectName destinationAccount:nil sourceVersion:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + objectName, @"destinationObjectName", + nil]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; [objectRequests addObject:objectRequest]; @@ -540,6 +573,12 @@ destinationObjectName:object.name destinationAccount:nil sourceVersion:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + object.name, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + object.name, @"destinationObjectName", + nil]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; [objectRequests addObject:objectRequest]; @@ -559,6 +598,12 @@ destinationObjectName:destinationObjectName destinationAccount:nil sourceVersion:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + destinationObjectName, @"destinationObjectName", + nil]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; [objectRequests addObject:objectRequest]; @@ -583,6 +628,12 @@ destinationObjectName:newObjectName destinationAccount:nil sourceVersion:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + object.name, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + newObjectName, @"destinationObjectName", + nil]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; [objectRequests addObject:objectRequest]; @@ -617,6 +668,12 @@ destinationContainerName:destinationContainerName destinationObjectName:destinationObjectName destinationAccount:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + destinationObjectName, @"destinationObjectName", + nil]; return objectRequest; } @@ -632,49 +689,72 @@ if (objects == nil) return nil; + ASIPithosObjectRequest *objectRequest; NSMutableArray *objectRequests = [NSMutableArray arrayWithCapacity:([objects count] + 1)]; if ([objectName isEqualToString:destinationObjectName]) { - if (![objectName hasSuffix:@"/"]) - [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName - objectName:objectName - contentType:nil - contentEncoding:nil - contentDisposition:nil - manifest:nil - sharing:nil - isPublic:ASIPithosObjectRequestPublicIgnore - metadata:nil - destinationContainerName:destinationContainerName - destinationObjectName:objectName - destinationAccount:nil]]; + if (![objectName hasSuffix:@"/"]) { + objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName + objectName:objectName + contentType:nil + contentEncoding:nil + contentDisposition:nil + manifest:nil + sharing:nil + isPublic:ASIPithosObjectRequestPublicIgnore + metadata:nil + destinationContainerName:destinationContainerName + destinationObjectName:objectName + destinationAccount:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + objectName, @"destinationObjectName", + nil]; + [objectRequests addObject:objectRequest]; + } for (ASIPithosObject *object in objects) { - [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName - objectName:object.name - contentType:nil - contentEncoding:nil - contentDisposition:nil - manifest:nil - sharing:nil - isPublic:ASIPithosObjectRequestPublicIgnore - metadata:nil - destinationContainerName:destinationContainerName - destinationObjectName:object.name - destinationAccount:nil]]; + objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName + objectName:object.name + contentType:nil + contentEncoding:nil + contentDisposition:nil + manifest:nil + sharing:nil + isPublic:ASIPithosObjectRequestPublicIgnore + metadata:nil + destinationContainerName:destinationContainerName + destinationObjectName:object.name + destinationAccount:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + object.name, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + object.name, @"destinationObjectName", + nil]; + [objectRequests addObject:objectRequest]; } } else { if (![objectName hasSuffix:@"/"]) { - [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName - objectName:objectName - contentType:nil - contentEncoding:nil - contentDisposition:nil - manifest:nil - sharing:nil - isPublic:ASIPithosObjectRequestPublicIgnore - metadata:nil - destinationContainerName:destinationContainerName - destinationObjectName:destinationObjectName - destinationAccount:nil]]; + objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName + objectName:objectName + contentType:nil + contentEncoding:nil + contentDisposition:nil + manifest:nil + sharing:nil + isPublic:ASIPithosObjectRequestPublicIgnore + metadata:nil + destinationContainerName:destinationContainerName + destinationObjectName:destinationObjectName + destinationAccount:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + objectName, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + destinationObjectName, @"destinationObjectName", + nil]; + [objectRequests addObject:objectRequest]; } NSRange prefixRange = NSMakeRange(0, [objectName length]); NSString *newObjectName; @@ -683,18 +763,25 @@ withString:destinationObjectName options:NSAnchoredSearch range:prefixRange]; - [objectRequests addObject:[ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName - objectName:object.name - contentType:nil - contentEncoding:nil - contentDisposition:nil - manifest:nil - sharing:nil - isPublic:ASIPithosObjectRequestPublicIgnore - metadata:nil - destinationContainerName:destinationContainerName - destinationObjectName:newObjectName - destinationAccount:nil]]; + objectRequest = [ASIPithosObjectRequest moveObjectDataRequestWithContainerName:containerName + objectName:object.name + contentType:nil + contentEncoding:nil + contentDisposition:nil + manifest:nil + sharing:nil + isPublic:ASIPithosObjectRequestPublicIgnore + metadata:nil + destinationContainerName:destinationContainerName + destinationObjectName:newObjectName + destinationAccount:nil]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + containerName, @"sourceContainerName", + object.name, @"sourceObjectName", + destinationContainerName, @"destinationContainerName", + newObjectName, @"destinationObjectName", + nil]; + [objectRequests addObject:objectRequest]; } } @@ -733,7 +820,10 @@ objectName:objectName]; if (sharingAccount) [objectRequest setRequestUserFromDefaultTo:sharingAccount]; - [objectRequest startSynchronous]; + [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + while (![objectRequest isFinished]) { + sleep(1); + } *error = [objectRequest error]; if (*error) { [self httpRequestErrorAlertWithRequest:objectRequest]; @@ -800,7 +890,10 @@ until:nil]; if (sharingAccount) [containerRequest setRequestUserFromDefaultTo:sharingAccount]; - [containerRequest startSynchronous]; + [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; + while (![containerRequest isFinished]) { + sleep(1); + } if ([containerRequest error]) { [self httpRequestErrorAlertWithRequest:containerRequest]; return nil; @@ -964,4 +1057,26 @@ return [alert runModal]; } +#pragma mark - +#pragma mark Request Helper Methods + ++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request priority:(NSOperationQueuePriority)priority { + [request setTimeOutSeconds:60]; + request.numberOfTimesToRetryOnTimeout = 10; + [request setQueuePriority:priority]; + return request; +} + ++ (ASIPithosRequest *)prepareRequest:(ASIPithosRequest *)request { + return [self prepareRequest:request priority:NSOperationQueuePriorityNormal]; +} + ++ (ASIPithosRequest *)copyRequest:(ASIPithosRequest *)request { + NSMutableDictionary *userInfo = [[request.userInfo retain] autorelease]; + request.userInfo = nil; + ASIPithosRequest *newRequest = [request copy]; + newRequest.userInfo = userInfo; + return newRequest; +} + @end diff --git a/pithos-macos/pithos_macosAppDelegate.m b/pithos-macos/pithos_macosAppDelegate.m index 76944c3..5188f15 100644 --- a/pithos-macos/pithos_macosAppDelegate.m +++ b/pithos-macos/pithos_macosAppDelegate.m @@ -192,6 +192,7 @@ NSLog(@"Authentication - storageURLPrefix:%@, authUser:%@, authToken:%@", storageURLPrefix, authUser, authToken); if ([authUser length] && [authToken length]) { [[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy]; + [[ASIPithosRequest sharedQueue] cancelAllOperations]; [ASIPithosRequest setAuthURL:storageURLPrefix]; [ASIPithosRequest setStorageURLPrefix:storageURLPrefix]; [ASIPithosRequest setAuthUser:authUser];