Revision b58ff732 pithos-macos/PithosBrowserController.m

b/pithos-macos/PithosBrowserController.m
615 615
        (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
616 616
        // Operation: Rename (move) an object or subdir/ node
617 617
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
618
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
619
            if (operation.isCancelled) {
620
                [pool drain];
621
                return;
622
            }
623
            NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
624
            if ([newName hasSuffix:@"/"])
625
                destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
626
            NSError *error = nil;
627
            BOOL isDirectory;
628
            if ([PithosUtilities objectExistsAtPithos:pithos 
629
                                        containerName:node.pithosContainer.name 
630
                                           objectName:destinationObjectName 
631
                                                error:&error 
632
                                          isDirectory:&isDirectory 
633
                                       sharingAccount:nil]) {
634
                dispatch_async(dispatch_get_main_queue(), ^{
635
                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
636
                    [alert setMessageText:@"Name Taken"];
637
                    [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
638
                    [alert addButtonWithTitle:@"OK"];
639
                    [alert runModal];
640
                });
641
                [pool drain];
642
                return;
643
            } else if (error) {
644
                [pool drain];
645
                return;
646
            }
647
            if (operation.isCancelled) {
648
                [pool drain];
649
                return;
650
            }
651
            ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos 
652
                                                                                   containerName:node.pithosContainer.name 
653
                                                                                      objectName:node.pithosObject.name 
654
                                                                        destinationContainerName:node.pithosContainer.name 
655
                                                                           destinationObjectName:destinationObjectName 
656
                                                                                   checkIfExists:NO];
657
            if (!operation.isCancelled && objectRequest) {
658
                objectRequest.delegate = self;
659
                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
660
                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
661
                NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
662
                                           [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
663
                                           [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
664
                                           [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
665
                                           [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
666
                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
667
                                                                           message:messagePrefix];
668
                [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
669
                 [NSDictionary dictionaryWithObjectsAndKeys:
670
                  [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
671
                  [NSNumber numberWithBool:YES], @"refresh", 
672
                  activity, @"activity", 
673
                  [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
674
                  [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
675
                  [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
676
                  [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
677
                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
678
                  NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
679
                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
680
                  moveNetworkQueue, @"networkQueue", 
681
                  @"move", @"operationType", 
682
                  nil]];
683
                [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
684
            }
685
            [pool drain];
686
        }];
687
        [moveQueue addOperation:operation];
688
    } else if ([node class] == [PithosSubdirNode class]) {
689
        if (firstSlashRange.length == 1)
690
            return;
691
        // Operation: Rename (move) a subdir node and its descendants
692
        // The resulting ASIPithosObjectRequests are chained through dependencies
693
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
694
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
695
            if (operation.isCancelled) {
696
                [pool drain];
697
                return;
698
            }
699
            NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
700
            NSError *error = nil;
701
            BOOL isDirectory;
702
            if ([PithosUtilities objectExistsAtPithos:pithos 
703
                                        containerName:node.pithosContainer.name 
704
                                           objectName:destinationObjectName 
705
                                                error:&error 
706
                                          isDirectory:&isDirectory 
707
                                       sharingAccount:nil]) {
708
                dispatch_async(dispatch_get_main_queue(), ^{
709
                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
710
                    [alert setMessageText:@"Name Taken"];
711
                    [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
712
                    [alert addButtonWithTitle:@"OK"];
713
                    [alert runModal];
714
                });
715
                [pool drain];
716
                return;
717
            } else if (error) {
718
                [pool drain];
719
                return;
720
            }
721
            if (operation.isCancelled) {
722
                [pool drain];
723
                return;
724
            }
725
            if (node.pithosObject.subdir)
726
                destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
727
            NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithos 
728
                                                                               containerName:node.pithosContainer.name 
729
                                                                                  objectName:node.pithosObject.name 
730
                                                                    destinationContainerName:node.pithosContainer.name 
731
                                                                       destinationObjectName:destinationObjectName 
732
                                                                               checkIfExists:NO];
733
            if (!operation.isCancelled && objectRequests) {
734
                ASIPithosObjectRequest *previousObjectRequest = nil;
735
                for (ASIPithosObjectRequest *objectRequest in objectRequests) {
736
                    if (operation.isCancelled) {
737
                        [pool drain];
738
                        return;
739
                    }
618
            @autoreleasepool {
619
                if (operation.isCancelled)
620
                    return;
621
                NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
622
                if ([newName hasSuffix:@"/"])
623
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
624
                NSError *error = nil;
625
                BOOL isDirectory;
626
                if ([PithosUtilities objectExistsAtPithos:pithos 
627
                                            containerName:node.pithosContainer.name 
628
                                               objectName:destinationObjectName 
629
                                                    error:&error 
630
                                              isDirectory:&isDirectory 
631
                                           sharingAccount:nil]) {
632
                    dispatch_async(dispatch_get_main_queue(), ^{
633
                        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
634
                        [alert setMessageText:@"Name Taken"];
635
                        [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
636
                        [alert addButtonWithTitle:@"OK"];
637
                        [alert runModal];
638
                    });
639
                    return;
640
                } else if (error) {
641
                    return;
642
                }
643
                if (operation.isCancelled)
644
                    return;
645
                ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos
646
                                                                                       containerName:node.pithosContainer.name 
647
                                                                                          objectName:node.pithosObject.name 
648
                                                                            destinationContainerName:node.pithosContainer.name 
649
                                                                               destinationObjectName:destinationObjectName 
650
                                                                                       checkIfExists:NO];
651
                if (!operation.isCancelled && objectRequest) {
740 652
                    objectRequest.delegate = self;
741 653
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
742 654
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
......
762 674
                      moveNetworkQueue, @"networkQueue", 
763 675
                      @"move", @"operationType", 
764 676
                      nil]];
765
                    if (previousObjectRequest)
766
                        [objectRequest addDependency:previousObjectRequest];
767
                    previousObjectRequest = objectRequest;
768 677
                    [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
769 678
                }
770 679
            }
771
            [pool drain];
680
        }];
681
        [moveQueue addOperation:operation];
682
    } else if ([node class] == [PithosSubdirNode class]) {
683
        if (firstSlashRange.length == 1)
684
            return;
685
        // Operation: Rename (move) a subdir node and its descendants
686
        // The resulting ASIPithosObjectRequests are chained through dependencies
687
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
688
            @autoreleasepool {
689
                if (operation.isCancelled)
690
                    return;
691
                NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
692
                NSError *error = nil;
693
                BOOL isDirectory;
694
                if ([PithosUtilities objectExistsAtPithos:pithos 
695
                                            containerName:node.pithosContainer.name 
696
                                               objectName:destinationObjectName 
697
                                                    error:&error 
698
                                              isDirectory:&isDirectory 
699
                                           sharingAccount:nil]) {
700
                    dispatch_async(dispatch_get_main_queue(), ^{
701
                        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
702
                        [alert setMessageText:@"Name Taken"];
703
                        [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
704
                        [alert addButtonWithTitle:@"OK"];
705
                        [alert runModal];
706
                    });
707
                    return;
708
                } else if (error) {
709
                    return;
710
                }
711
                if (operation.isCancelled)
712
                    return;
713
                if (node.pithosObject.subdir)
714
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
715
                NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithos 
716
                                                                                   containerName:node.pithosContainer.name 
717
                                                                                      objectName:node.pithosObject.name 
718
                                                                        destinationContainerName:node.pithosContainer.name 
719
                                                                           destinationObjectName:destinationObjectName 
720
                                                                                   checkIfExists:NO];
721
                if (!operation.isCancelled && objectRequests) {
722
                    ASIPithosObjectRequest *previousObjectRequest = nil;
723
                    for (ASIPithosObjectRequest *objectRequest in objectRequests) {
724
                        if (operation.isCancelled)
725
                            return;
726
                        objectRequest.delegate = self;
727
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
728
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
729
                        NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
730
                                                   [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
731
                                                   [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
732
                                                   [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
733
                                                   [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
734
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
735
                                                                                   message:messagePrefix];
736
                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
737
                         [NSDictionary dictionaryWithObjectsAndKeys:
738
                          [NSArray arrayWithObject:node.parent], @"forceRefreshNodes", 
739
                          [NSNumber numberWithBool:YES], @"refresh", 
740
                          activity, @"activity", 
741
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
742
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
743
                          [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
744
                          [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
745
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
746
                          NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
747
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
748
                          moveNetworkQueue, @"networkQueue", 
749
                          @"move", @"operationType", 
750
                          nil]];
751
                        if (previousObjectRequest)
752
                            [objectRequest addDependency:previousObjectRequest];
753
                        previousObjectRequest = objectRequest;
754
                        [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
755
                    }
756
                }
757
            }
772 758
        }];
773 759
        [moveQueue addOperation:operation];
774 760
    }
......
971 957
        // Operation: Download a subdir node and its descendants
972 958
        // The resulting ASIPithosObjectRequests are chained through dependencies
973 959
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
974
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
975
            if (operation.isCancelled) {
976
                [pool drain];
977
                return;
978
            }
979
            NSArray *objectRequests = [PithosUtilities objectDataRequestsForSubdirWithPithos:pithos 
980
                                                                               containerName:node.pithosContainer.name 
981
                                                                                  objectName:node.pithosObject.name 
982
                                                                                 toDirectory:dirPath 
983
                                                                               checkIfExists:checkIfExists 
984
                                                                              sharingAccount:node.sharingAccount];
985
            if (!operation.isCancelled && objectRequests) {
986
                ASIPithosObjectRequest *previousObjectRequest = nil;
987
                for (__block ASIPithosObjectRequest *objectRequest in objectRequests) {
988
                    if (operation.isCancelled) {
989
                        [pool drain];
990
                        return;
960
            @autoreleasepool {
961
                if (operation.isCancelled)
962
                    return;
963
                NSArray *objectRequests = [PithosUtilities objectDataRequestsForSubdirWithPithos:pithos 
964
                                                                                   containerName:node.pithosContainer.name 
965
                                                                                      objectName:node.pithosObject.name 
966
                                                                                     toDirectory:dirPath 
967
                                                                                   checkIfExists:checkIfExists 
968
                                                                                  sharingAccount:node.sharingAccount];
969
                if (!operation.isCancelled && objectRequests) {
970
                    ASIPithosObjectRequest *previousObjectRequest = nil;
971
                    for (__block ASIPithosObjectRequest *objectRequest in objectRequests) {
972
                        if (operation.isCancelled)
973
                            return;
974
                        objectRequest.delegate = self;
975
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
976
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
977
                        NSString *messagePrefix = [NSString stringWithFormat:@"Downloading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
978
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload 
979
                                                                                   message:[messagePrefix stringByAppendingString:@" (0%)"]
980
                                                                                totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue] 
981
                                                                              currentBytes:0];
982
                        dispatch_async(dispatch_get_main_queue(), ^{
983
                            [activityFacility updateActivity:activity withMessage:activity.message];  
984
                        });
985
                        [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
986
                         [NSDictionary dictionaryWithObjectsAndKeys:
987
                          activity, @"activity", 
988
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
989
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
990
                          [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
991
                          [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
992
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
993
                          NSStringFromSelector(@selector(downloadObjectFinished:)), @"didFinishSelector", 
994
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
995
                          downloadNetworkQueue, @"networkQueue", 
996
                          @"download", @"operationType", 
997
                          nil]];
998
                        [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
999
                            [activityFacility updateActivity:activity 
1000
                                                 withMessage:[messagePrefix stringByAppendingFormat:@" (%.0f%%)", (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1001
                                                  totalBytes:activity.totalBytes 
1002
                                                currentBytes:(activity.currentBytes + size)];
1003
                        }];
1004
                        if (previousObjectRequest)
1005
                            [objectRequest addDependency:previousObjectRequest];
1006
                        previousObjectRequest = objectRequest;
1007
                        [downloadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
991 1008
                    }
1009
                }
1010
            }
1011
        }];
1012
        [downloadQueue addOperation:operation];
1013
    } else if ([node class] == [PithosObjectNode class]) {
1014
        // Operation: Download an object node
1015
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1016
            @autoreleasepool {
1017
                if (operation.isCancelled)
1018
                    return;
1019
                __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectDataRequestWithPithos:pithos
1020
                                                                                               containerName:node.pithosContainer.name 
1021
                                                                                                  objectName:node.pithosObject.name 
1022
                                                                                                     version:version 
1023
                                                                                                toDirectory:dirPath 
1024
                                                                                             withNewFileName:newFileName 
1025
                                                                                               checkIfExists:checkIfExists 
1026
                                                                                              sharingAccount:node.sharingAccount];
1027
                if (!operation.isCancelled && objectRequest) {
992 1028
                    objectRequest.delegate = self;
993 1029
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
994 1030
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
995 1031
                    NSString *messagePrefix = [NSString stringWithFormat:@"Downloading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
996 1032
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload 
997 1033
                                                                               message:[messagePrefix stringByAppendingString:@" (0%)"]
998
                                                                            totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue] 
1034
                                                                            totalBytes:node.pithosObject.bytes 
999 1035
                                                                          currentBytes:0];
1000 1036
                    dispatch_async(dispatch_get_main_queue(), ^{
1001 1037
                        [activityFacility updateActivity:activity withMessage:activity.message];  
......
1019 1055
                                              totalBytes:activity.totalBytes 
1020 1056
                                            currentBytes:(activity.currentBytes + size)];
1021 1057
                    }];
1022
                    if (previousObjectRequest)
1023
                        [objectRequest addDependency:previousObjectRequest];
1024
                    previousObjectRequest = objectRequest;
1025 1058
                    [downloadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1026 1059
                }
1027 1060
            }
1028
            [pool drain];
1029
        }];
1030
        [downloadQueue addOperation:operation];
1031
    } else if ([node class] == [PithosObjectNode class]) {
1032
        // Operation: Download an object node
1033
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1034
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1035
            if (operation.isCancelled) {
1036
                [pool drain];
1037
                return;
1038
            }
1039
            __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectDataRequestWithPithos:pithos 
1040
                                                                                           containerName:node.pithosContainer.name 
1041
                                                                                              objectName:node.pithosObject.name 
1042
                                                                                                 version:version 
1043
                                                                                            toDirectory:dirPath 
1044
                                                                                         withNewFileName:newFileName 
1045
                                                                                           checkIfExists:checkIfExists 
1046
                                                                                          sharingAccount:node.sharingAccount];
1047
            if (!operation.isCancelled && objectRequest) {
1048
                objectRequest.delegate = self;
1049
                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1050
                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1051
                NSString *messagePrefix = [NSString stringWithFormat:@"Downloading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1052
                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload 
1053
                                                                           message:[messagePrefix stringByAppendingString:@" (0%)"]
1054
                                                                        totalBytes:node.pithosObject.bytes 
1055
                                                                      currentBytes:0];
1056
                dispatch_async(dispatch_get_main_queue(), ^{
1057
                    [activityFacility updateActivity:activity withMessage:activity.message];  
1058
                });
1059
                [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1060
                 [NSDictionary dictionaryWithObjectsAndKeys:
1061
                  activity, @"activity", 
1062
                  [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1063
                  [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1064
                  [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1065
                  [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1066
                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
1067
                  NSStringFromSelector(@selector(downloadObjectFinished:)), @"didFinishSelector", 
1068
                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1069
                  downloadNetworkQueue, @"networkQueue", 
1070
                  @"download", @"operationType", 
1071
                  nil]];
1072
                [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){
1073
                    [activityFacility updateActivity:activity 
1074
                                         withMessage:[messagePrefix stringByAppendingFormat:@" (%.0f%%)", (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1075
                                          totalBytes:activity.totalBytes 
1076
                                        currentBytes:(activity.currentBytes + size)];
1077
                }];
1078
                [downloadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1079
                [pool drain];
1080
            }
1081 1061
        }];
1082 1062
        [downloadQueue addOperation:operation];
1083 1063
    }
......
1121 1101
                                        precomposedStringWithCanonicalMapping];
1122 1102
                // Operation: Upload a local file
1123 1103
                __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1124
                    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1125
                    if (operation.isCancelled) {
1126
                        [pool drain];
1127
                        return;
1128
                    }
1129
                    NSError *error = nil;
1130
                    NSString *contentType = [PithosUtilities contentTypeOfFile:filePath error:&error];
1131
                    if (contentType == nil)
1132
                        contentType = @"application/octet-stream";
1133
                    #if DEBUG_PITHOS
1134
                    if (error)
1135
                        DLog(@"contentType detection error: %@", error);
1136
                    #endif
1137
                    NSArray *hashes = nil;
1138
                    if (operation.isCancelled) {
1139
                        [pool drain];
1140
                        return;
1141
                    }
1142
                    ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos 
1143
                                                                                                containerName:containerName 
1144
                                                                                                   objectName:objectName 
1145
                                                                                                  contentType:contentType 
1146
                                                                                                    blockSize:blockSize 
1147
                                                                                                    blockHash:blockHash 
1148
                                                                                                      forFile:filePath 
1149
                                                                                                checkIfExists:YES 
1150
                                                                                                       hashes:&hashes 
1151
                                                                                               sharingAccount:destinationNode.sharingAccount];
1152
                    if (!operation.isCancelled && objectRequest) {
1153
                        objectRequest.delegate = self;
1154
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1155
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1156
                        NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1157
                        PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1158
                                                                                   message:[messagePrefix stringByAppendingString:@" (0%)"]
1159
                                                                                totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1160
                                                                              currentBytes:0];
1161
                        [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1162
                         [NSDictionary dictionaryWithObjectsAndKeys:
1163
                          containerName, @"containerName", 
1164
                          objectName, @"objectName", 
1165
                          contentType, @"contentType", 
1166
                          [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1167
                          blockHash, @"blockHash", 
1168
                          filePath, @"filePath", 
1169
                          hashes, @"hashes", 
1170
                          [NSArray arrayWithObject:destinationNode], @"refreshNodes", 
1171
                          [NSNumber numberWithBool:YES], @"refresh", 
1172
                          [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1173
                          activity, @"activity", 
1174
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1175
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1176
                          [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1177
                          [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1178
                          [NSNumber numberWithUnsignedInteger:10], @"retries", 
1179
                          NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1180
                          NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1181
                          uploadNetworkQueue, @"networkQueue", 
1182
                          @"upload", @"operationType", 
1183
                          nil]];
1184
                        if (destinationNode.sharingAccount)
1185
                            [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1186
                        [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1187
                    }
1188
                    [pool drain];
1189
                }];
1190
                [uploadQueue addOperation:operation];
1191
            } else {
1192
                // Upload directory, confirm first
1193
                NSAlert *alert = [[[NSAlert alloc] init] autorelease];
1194
                [alert setMessageText:@"Upload directory"];
1195
                [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to upload it and its contents?", filePath]];
1196
                [alert addButtonWithTitle:@"OK"];
1197
                [alert addButtonWithTitle:@"Cancel"];
1198
                NSInteger choice = [alert runModal];
1199
                if (choice == NSAlertFirstButtonReturn) {
1200
                    NSString *objectName = [[objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]] 
1201
                                            precomposedStringWithCanonicalMapping];
1202
                    // Operation: Upload a local directory and its descendants
1203
                    // The resulting ASIPithosObjectRequests are chained through dependencies
1204
                    __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1205
                        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1206
                        if (operation.isCancelled) {
1207
                            [pool drain];
1104
                    @autoreleasepool {
1105
                        if (operation.isCancelled)
1208 1106
                            return;
1209
                        }
1210
                        NSMutableArray *objectNames = nil;
1211
                        NSMutableArray *contentTypes = nil;
1212
                        NSMutableArray *filePaths = nil;
1213
                        NSMutableArray *hashesArrays = nil;
1214
                        NSMutableArray *directoryObjectRequests = nil;
1215
                        NSArray *objectRequests = [PithosUtilities writeObjectDataRequestsWithPithos:pithos 
1216
                                                                                       containerName:containerName 
1217
                                                                                          objectName:objectName 
1218
                                                                                           blockSize:blockSize 
1219
                                                                                           blockHash:blockHash 
1220
                                                                                        forDirectory:filePath 
1221
                                                                                       checkIfExists:YES 
1222
                                                                                         objectNames:&objectNames
1223
                                                                                        contentTypes:&contentTypes
1224
                                                                                           filePaths:&filePaths
1225
                                                                                        hashesArrays:&hashesArrays 
1226
                                                                             directoryObjectRequests:&directoryObjectRequests 
1227
                                                                                      sharingAccount:destinationNode.sharingAccount];
1228
                        if (operation.isCancelled) {
1229
                            [pool drain];
1107
                        NSError *error = nil;
1108
                        NSString *contentType = [PithosUtilities contentTypeOfFile:filePath error:&error];
1109
                        if (contentType == nil)
1110
                            contentType = @"application/octet-stream";
1111
                        #if DEBUG_PITHOS
1112
                        if (error)
1113
                            DLog(@"contentType detection error: %@", error);
1114
                        #endif
1115
                        NSArray *hashes = nil;
1116
                        if (operation.isCancelled)
1230 1117
                            return;
1231
                        }
1232
                        ASIPithosObjectRequest *previousObjectRequest = nil;
1233
                        for (ASIPithosObjectRequest *objectRequest in directoryObjectRequests) {
1234
                            if (operation.isCancelled) {
1235
                                [pool drain];
1236
                                return;
1237
                            }
1118
                        ASIPithosObjectRequest *objectRequest = [PithosUtilities writeObjectDataRequestWithPithos:pithos
1119
                                                                                                    containerName:containerName 
1120
                                                                                                       objectName:objectName 
1121
                                                                                                      contentType:contentType 
1122
                                                                                                        blockSize:blockSize 
1123
                                                                                                        blockHash:blockHash 
1124
                                                                                                          forFile:filePath 
1125
                                                                                                    checkIfExists:YES 
1126
                                                                                                           hashes:&hashes 
1127
                                                                                                   sharingAccount:destinationNode.sharingAccount];
1128
                        if (!operation.isCancelled && objectRequest) {
1238 1129
                            objectRequest.delegate = self;
1239 1130
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1240 1131
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1241
                            NSString *messagePrefix = [NSString stringWithFormat:@"Creating directory '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1242
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory 
1243
                                                                                       message:messagePrefix];
1132
                            NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1133
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1134
                                                                                       message:[messagePrefix stringByAppendingString:@" (0%)"]
1135
                                                                                    totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1136
                                                                                  currentBytes:0];
1244 1137
                            [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1245 1138
                             [NSDictionary dictionaryWithObjectsAndKeys:
1139
                              containerName, @"containerName", 
1140
                              objectName, @"objectName", 
1141
                              contentType, @"contentType", 
1142
                              [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1143
                              blockHash, @"blockHash", 
1144
                              filePath, @"filePath", 
1145
                              hashes, @"hashes", 
1146
                              [NSArray arrayWithObject:destinationNode], @"refreshNodes", 
1246 1147
                              [NSNumber numberWithBool:YES], @"refresh", 
1148
                              [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1247 1149
                              activity, @"activity", 
1248 1150
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1249 1151
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1250
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1152
                              [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1251 1153
                              [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1252 1154
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1253
                              NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", 
1155
                              NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1254 1156
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1255 1157
                              uploadNetworkQueue, @"networkQueue", 
1256 1158
                              @"upload", @"operationType", 
1257 1159
                              nil]];
1258
                            if (previousObjectRequest)
1259
                                [objectRequest addDependency:previousObjectRequest];
1260
                            previousObjectRequest = objectRequest;
1160
                            if (destinationNode.sharingAccount)
1161
                                [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1261 1162
                            [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1262 1163
                        }
1263
                        if (!operation.isCancelled && objectRequests) {
1264
                            for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) {
1265
                                if (operation.isCancelled) {
1266
                                    [pool drain];
1164
                    }
1165
                }];
1166
                [uploadQueue addOperation:operation];
1167
            } else {
1168
                // Upload directory, confirm first
1169
                NSAlert *alert = [[[NSAlert alloc] init] autorelease];
1170
                [alert setMessageText:@"Upload directory"];
1171
                [alert setInformativeText:[NSString stringWithFormat:@"'%@' is a directory, do you want to upload it and its contents?", filePath]];
1172
                [alert addButtonWithTitle:@"OK"];
1173
                [alert addButtonWithTitle:@"Cancel"];
1174
                NSInteger choice = [alert runModal];
1175
                if (choice == NSAlertFirstButtonReturn) {
1176
                    NSString *objectName = [[objectNamePrefix stringByAppendingPathComponent:[filePath lastPathComponent]] 
1177
                                            precomposedStringWithCanonicalMapping];
1178
                    // Operation: Upload a local directory and its descendants
1179
                    // The resulting ASIPithosObjectRequests are chained through dependencies
1180
                    __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1181
                        @autoreleasepool {
1182
                            if (operation.isCancelled)
1183
                                return;
1184
                            NSMutableArray *objectNames = nil;
1185
                            NSMutableArray *contentTypes = nil;
1186
                            NSMutableArray *filePaths = nil;
1187
                            NSMutableArray *hashesArrays = nil;
1188
                            NSMutableArray *directoryObjectRequests = nil;
1189
                            NSArray *objectRequests = [PithosUtilities writeObjectDataRequestsWithPithos:pithos 
1190
                                                                                           containerName:containerName 
1191
                                                                                              objectName:objectName 
1192
                                                                                               blockSize:blockSize 
1193
                                                                                               blockHash:blockHash 
1194
                                                                                            forDirectory:filePath 
1195
                                                                                           checkIfExists:YES 
1196
                                                                                             objectNames:&objectNames
1197
                                                                                            contentTypes:&contentTypes
1198
                                                                                               filePaths:&filePaths
1199
                                                                                            hashesArrays:&hashesArrays 
1200
                                                                                 directoryObjectRequests:&directoryObjectRequests 
1201
                                                                                          sharingAccount:destinationNode.sharingAccount];
1202
                            if (operation.isCancelled)
1203
                                return;
1204
                            ASIPithosObjectRequest *previousObjectRequest = nil;
1205
                            for (ASIPithosObjectRequest *objectRequest in directoryObjectRequests) {
1206
                                if (operation.isCancelled)
1267 1207
                                    return;
1268
                                }
1269
                                ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i];
1270 1208
                                objectRequest.delegate = self;
1271 1209
                                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1272 1210
                                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1273
                                NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1274
                                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1275
                                                                                           message:[messagePrefix stringByAppendingString:@" (0%)"]
1276
                                                                                        totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1277
                                                                                      currentBytes:0];
1211
                                NSString *messagePrefix = [NSString stringWithFormat:@"Creating directory '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1212
                                PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory 
1213
                                                                                           message:messagePrefix];
1278 1214
                                [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1279 1215
                                 [NSDictionary dictionaryWithObjectsAndKeys:
1280
                                  containerName, @"containerName", 
1281
                                  [objectNames objectAtIndex:i], @"objectName", 
1282
                                  [contentTypes objectAtIndex:i], @"contentType", 
1283
                                  [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1284
                                  blockHash, @"blockHash", 
1285
                                  [filePaths objectAtIndex:i], @"filePath", 
1286
                                  [hashesArrays objectAtIndex:i], @"hashes", 
1287 1216
                                  [NSNumber numberWithBool:YES], @"refresh", 
1288
                                  [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1289 1217
                                  activity, @"activity", 
1290 1218
                                  [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1291 1219
                                  [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1292
                                  [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1220
                                  [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1293 1221
                                  [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1294 1222
                                  [NSNumber numberWithUnsignedInteger:10], @"retries", 
1295
                                  NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1223
                                  NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", 
1296 1224
                                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1297 1225
                                  uploadNetworkQueue, @"networkQueue", 
1298 1226
                                  @"upload", @"operationType", 
1299 1227
                                  nil]];
1300
                                if (destinationNode.sharingAccount)
1301
                                    [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1302 1228
                                if (previousObjectRequest)
1303 1229
                                    [objectRequest addDependency:previousObjectRequest];
1304 1230
                                previousObjectRequest = objectRequest;
1305 1231
                                [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1306 1232
                            }
1307
                        }
1308
                        [pool drain];
1309
                    }];
1310
                    [uploadQueue addOperation:operation];
1311
                }
1312
            }
1233
                            if (!operation.isCancelled && objectRequests) {
1234
                                for (NSUInteger i = 0 ; i < [objectRequests count] ; i++) {
1235
                                    if (operation.isCancelled)
1236
                                        return;
1237
                                    ASIPithosObjectRequest *objectRequest = [objectRequests objectAtIndex:i];
1238
                                    objectRequest.delegate = self;
1239
                                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1240
                                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1241
                                    NSString *messagePrefix = [NSString stringWithFormat:@"Uploading '%@'", [objectRequest.userInfo objectForKey:@"fileName"]];
1242
                                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload 
1243
                                                                                               message:[messagePrefix stringByAppendingString:@" (0%)"]
1244
                                                                                            totalBytes:[[objectRequest.userInfo objectForKey:@"bytes"] unsignedIntegerValue]
1245
                                                                                          currentBytes:0];
1246
                                    [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary:
1247
                                     [NSDictionary dictionaryWithObjectsAndKeys:
1248
                                      containerName, @"containerName", 
1249
                                      [objectNames objectAtIndex:i], @"objectName", 
1250
                                      [contentTypes objectAtIndex:i], @"contentType", 
1251
                                      [NSNumber numberWithUnsignedInteger:blockSize], @"blockSize", 
1252
                                      blockHash, @"blockHash", 
1253
                                      [filePaths objectAtIndex:i], @"filePath", 
1254
                                      [hashesArrays objectAtIndex:i], @"hashes", 
1255
                                      [NSNumber numberWithBool:YES], @"refresh", 
1256
                                      [NSNumber numberWithUnsignedInteger:10], @"iteration", 
1257
                                      activity, @"activity", 
1258
                                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1259
                                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1260
                                      [messagePrefix stringByAppendingString:@" (100%)"], @"finishedActivityMessage", 
1261
                                      [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", 
1262
                                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
1263
                                      NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", 
1264
                                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1265
                                      uploadNetworkQueue, @"networkQueue", 
1266
                                      @"upload", @"operationType", 
1267
                                      nil]];
1268
                                    if (destinationNode.sharingAccount)
1269
                                        [(NSMutableDictionary *)objectRequest.userInfo setObject:destinationNode.sharingAccount forKey:@"sharingAccount"];
1270
                                    if (previousObjectRequest)
1271
                                        [objectRequest addDependency:previousObjectRequest];
1272
                                    previousObjectRequest = objectRequest;
1273
                                    [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest]];
1274
                                }
1275
                            }
1276
                        }
1277
                    }];
1278
                    [uploadQueue addOperation:operation];
1279
                }
1280
            }
1313 1281
        }
1314 1282
    }
1315 1283
    return YES;
......
1331 1299
            (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
1332 1300
            // Operation: Move an object or subdir/ node
1333 1301
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1334
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1335
                if (operation.isCancelled) {
1336
                    [pool drain];
1337
                    return;
1338
                }
1339
                NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1340
                if ([node.pithosObject.name hasSuffix:@"/"])
1341
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1342
                ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos 
1343
                                                                                       containerName:node.pithosContainer.name 
1344
                                                                                          objectName:node.pithosObject.name 
1345
                                                                            destinationContainerName:containerName 
1346
                                                                               destinationObjectName:destinationObjectName 
1347
                                                                                       checkIfExists:YES];
1348
                if (!operation.isCancelled && objectRequest) {
1349
                    objectRequest.delegate = self;
1350
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1351
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1352
                    NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
1353
                                               [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1354
                                               [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1355
                                               [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1356
                                               [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1357
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
1358
                                                                               message:messagePrefix];
1359
                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1360
                     [NSDictionary dictionaryWithObjectsAndKeys:
1361
                      [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
1362
                      activity, @"activity", 
1363
                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1364
                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1365
                      [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1366
                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1367
                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
1368
                      NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
1369
                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1370
                      moveNetworkQueue, @"networkQueue", 
1371
                      @"move", @"operationType", 
1372
                      nil]];
1373
                    [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1374
                }
1375
                [pool drain];
1376
            }];
1377
            [moveQueue addOperation:operation];
1378
        } else if ([node class] == [PithosSubdirNode class]) {
1379
            // Operation: Move a subdir node and its descendants
1380
            // The resulting ASIPithosObjectRequests are chained through dependencies
1381
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1382
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1383
                if (operation.isCancelled) {
1384
                    [pool drain];
1385
                    return;
1386
                }
1387
                NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1388
                if (node.pithosObject.subdir)
1389
                    destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1390
                NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithos 
1391
                                                                                   containerName:node.pithosContainer.name 
1392
                                                                                      objectName:node.pithosObject.name 
1393
                                                                        destinationContainerName:containerName 
1394
                                                                           destinationObjectName:destinationObjectName 
1395
                                                                                   checkIfExists:YES];
1396
                if (!operation.isCancelled && objectRequests) {
1397
                    ASIPithosObjectRequest *previousObjectRequest = nil;
1398
                    for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1399
                        if (operation.isCancelled) {
1400
                            [pool drain];
1401
                            return;
1402
                        }
1302
                @autoreleasepool {
1303
                    if (operation.isCancelled)
1304
                        return;
1305
                    NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1306
                    if ([node.pithosObject.name hasSuffix:@"/"])
1307
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1308
                    ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos 
1309
                                                                                           containerName:node.pithosContainer.name 
1310
                                                                                              objectName:node.pithosObject.name 
1311
                                                                                destinationContainerName:containerName 
1312
                                                                                   destinationObjectName:destinationObjectName 
1313
                                                                                           checkIfExists:YES];
1314
                    if (!operation.isCancelled && objectRequest) {
1403 1315
                        objectRequest.delegate = self;
1404 1316
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1405 1317
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
......
1413 1325
                        [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1414 1326
                         [NSDictionary dictionaryWithObjectsAndKeys:
1415 1327
                          [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
1416
                          [NSNumber numberWithBool:YES], @"refresh", 
1417 1328
                          activity, @"activity", 
1418 1329
                          [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1419 1330
                          [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
......
1425 1336
                          moveNetworkQueue, @"networkQueue", 
1426 1337
                          @"move", @"operationType", 
1427 1338
                          nil]];
1428
                        if (previousObjectRequest)
1429
                            [objectRequest addDependency:previousObjectRequest];
1430
                        previousObjectRequest = objectRequest;
1431 1339
                        [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1432 1340
                    }
1433 1341
                }
1434
                [pool drain];
1342
            }];
1343
            [moveQueue addOperation:operation];
1344
        } else if ([node class] == [PithosSubdirNode class]) {
1345
            // Operation: Move a subdir node and its descendants
1346
            // The resulting ASIPithosObjectRequests are chained through dependencies
1347
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1348
                @autoreleasepool {
1349
                    if (operation.isCancelled)
1350
                        return;
1351
                    NSString *destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1352
                    if (node.pithosObject.subdir)
1353
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1354
                    NSArray *objectRequests = [PithosUtilities moveObjectRequestsForSubdirWithPithos:pithos 
1355
                                                                                       containerName:node.pithosContainer.name 
1356
                                                                                          objectName:node.pithosObject.name 
1357
                                                                            destinationContainerName:containerName 
1358
                                                                               destinationObjectName:destinationObjectName 
1359
                                                                                       checkIfExists:YES];
1360
                    if (!operation.isCancelled && objectRequests) {
1361
                        ASIPithosObjectRequest *previousObjectRequest = nil;
1362
                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1363
                            if (operation.isCancelled)
1364
                                return;
1365
                            objectRequest.delegate = self;
1366
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1367
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1368
                            NSString *messagePrefix = [NSString stringWithFormat:@"Moving '%@/%@' to '%@/%@'", 
1369
                                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1370
                                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1371
                                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1372
                                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1373
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityMove 
1374
                                                                                       message:messagePrefix];
1375
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1376
                             [NSDictionary dictionaryWithObjectsAndKeys:
1377
                              [NSArray arrayWithObjects:node.parent, destinationNode, nil], @"forceRefreshNodes", 
1378
                              [NSNumber numberWithBool:YES], @"refresh", 
1379
                              activity, @"activity", 
1380
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1381
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1382
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1383
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1384
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1385
                              NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
1386
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1387
                              moveNetworkQueue, @"networkQueue", 
1388
                              @"move", @"operationType", 
1389
                              nil]];
1390
                            if (previousObjectRequest)
1391
                                [objectRequest addDependency:previousObjectRequest];
1392
                            previousObjectRequest = objectRequest;
1393
                            [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1394
                        }
1395
                    }
1396
                }
1435 1397
            }];
1436 1398
            [moveQueue addOperation:operation];
1437 1399
        }
......
1455 1417
            (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
1456 1418
            // Operation: Copy an object or subdir/ node
1457 1419
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1458
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1459
                if (operation.isCancelled) {
1460
                    [pool drain];
1461
                    return;
1462
                }
1463
                NSString *destinationObjectName;
1464
                if (![destinationNode isEqualTo:node.parent]) {
1465
                    destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1466
                    if ([node.pithosObject.name hasSuffix:@"/"])
1467
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1468
                } else {
1469
                    destinationObjectName = [PithosUtilities safeObjectNameForPithos:pithos 
1470
                                                                       containerName:containerName 
1471
                                                                          objectName:node.pithosObject.name];
1472
                }
1473
                if (operation.isCancelled) {
1474
                    [pool drain];
1475
                    return;
1476
                }
1477
                ASIPithosObjectRequest *objectRequest = [PithosUtilities copyObjectRequestWithPithos:pithos 
1478
                                                                                       containerName:node.pithosContainer.name 
1479
                                                                                          objectName:node.pithosObject.name 
1480
                                                                            destinationContainerName:containerName 
1481
                                                                               destinationObjectName:destinationObjectName 
1482
                                                                                       checkIfExists:YES 
1483
                                                                                      sharingAccount:node.sharingAccount];
1484
                if (!operation.isCancelled && objectRequest) {
1485
                    objectRequest.delegate = self;
1486
                    objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1487
                    objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1488
                    NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
1489
                                               [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1490
                                               [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1491
                                               [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1492
                                               [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1493
                    PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
1494
                                                                               message:messagePrefix];
1495
                    [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1496
                     [NSDictionary dictionaryWithObjectsAndKeys:
1497
                      [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
1498
                      activity, @"activity", 
1499
                      [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1500
                      [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1501
                      [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1502
                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1503
                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
1504
                      NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector", 
1505
                      NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1506
                      copyNetworkQueue, @"networkQueue", 
1507
                      @"copy", @"operationType", 
1508
                      nil]];
1509
                    [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1510
                }
1511
                [pool drain];
1512
            }];
1513
            [copyQueue addOperation:operation];
1514
        } else if ([node class] == [PithosSubdirNode class]) {
1515
            // Operation: Copy a subdir node and its descendants
1516
            // The resulting ASIPithosObjectRequests are chained through dependencies
1517
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1518
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1519
                if (operation.isCancelled) {
1520
                    [pool drain];
1521
                    return;
1522
                }
1523
                NSString *destinationObjectName;
1524
                if (![destinationNode isEqualTo:node.parent]) {
1525
                    destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1526
                    if (node.pithosObject.subdir)
1527
                        destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1528
                } else {
1529
                    destinationObjectName = [PithosUtilities safeSubdirNameForPithos:pithos 
1530
                                                                       containerName:containerName 
1531
                                                                          subdirName:node.pithosObject.name];
1532
                }
1533
                if (operation.isCancelled) {
1534
                    [pool drain];
1535
                    return;
1536
                }
1537
                NSArray *objectRequests = [PithosUtilities copyObjectRequestsForSubdirWithPithos:pithos 
1538
                                                                                   containerName:node.pithosContainer.name 
1539
                                                                                      objectName:node.pithosObject.name 
1540
                                                                        destinationContainerName:containerName 
1541
                                                                           destinationObjectName:destinationObjectName 
1542
                                                                                   checkIfExists:YES 
1543
                                                                                  sharingAccount:node.sharingAccount];
1544
                if (!operation.isCancelled && objectRequests) {
1545
                    ASIPithosObjectRequest *previousObjectRequest = nil;
1546
                    for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1547
                        if (operation.isCancelled) {
1548
                            [pool drain];
1549
                            return;
1550
                        }
1420
                @autoreleasepool {
1421
                    if (operation.isCancelled)
1422
                        return;
1423
                    NSString *destinationObjectName;
1424
                    if (![destinationNode isEqualTo:node.parent]) {
1425
                        destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1426
                        if ([node.pithosObject.name hasSuffix:@"/"])
1427
                            destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1428
                    } else {
1429
                        destinationObjectName = [PithosUtilities safeObjectNameForPithos:pithos 
1430
                                                                           containerName:containerName 
1431
                                                                              objectName:node.pithosObject.name];
1432
                    }
1433
                    if (operation.isCancelled)
1434
                        return;
1435
                    ASIPithosObjectRequest *objectRequest = [PithosUtilities copyObjectRequestWithPithos:pithos
1436
                                                                                           containerName:node.pithosContainer.name 
1437
                                                                                              objectName:node.pithosObject.name 
1438
                                                                                destinationContainerName:containerName 
1439
                                                                                   destinationObjectName:destinationObjectName 
1440
                                                                                           checkIfExists:YES 
1441
                                                                                          sharingAccount:node.sharingAccount];
1442
                    if (!operation.isCancelled && objectRequest) {
1551 1443
                        objectRequest.delegate = self;
1552 1444
                        objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1553 1445
                        objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
......
1572 1464
                          copyNetworkQueue, @"networkQueue", 
1573 1465
                          @"copy", @"operationType", 
1574 1466
                          nil]];
1575
                        if (previousObjectRequest)
1576
                            [objectRequest addDependency:previousObjectRequest];
1577
                        previousObjectRequest = objectRequest;
1578 1467
                        [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1579 1468
                    }
1580 1469
                }
1581
                [pool drain];
1470
            }];
1471
            [copyQueue addOperation:operation];
1472
        } else if ([node class] == [PithosSubdirNode class]) {
1473
            // Operation: Copy a subdir node and its descendants
1474
            // The resulting ASIPithosObjectRequests are chained through dependencies
1475
            __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
1476
                @autoreleasepool {
1477
                    if (operation.isCancelled)
1478
                        return;
1479
                    NSString *destinationObjectName;
1480
                    if (![destinationNode isEqualTo:node.parent]) {
1481
                        destinationObjectName = [objectNamePrefix stringByAppendingPathComponent:node.displayName];
1482
                        if (node.pithosObject.subdir)
1483
                            destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
1484
                    } else {
1485
                        destinationObjectName = [PithosUtilities safeSubdirNameForPithos:pithos 
1486
                                                                           containerName:containerName 
1487
                                                                              subdirName:node.pithosObject.name];
1488
                    }
1489
                    if (operation.isCancelled)
1490
                        return;
1491
                    NSArray *objectRequests = [PithosUtilities copyObjectRequestsForSubdirWithPithos:pithos
1492
                                                                                       containerName:node.pithosContainer.name 
1493
                                                                                          objectName:node.pithosObject.name 
1494
                                                                            destinationContainerName:containerName 
1495
                                                                               destinationObjectName:destinationObjectName 
1496
                                                                                       checkIfExists:YES 
1497
                                                                                      sharingAccount:node.sharingAccount];
1498
                    if (!operation.isCancelled && objectRequests) {
1499
                        ASIPithosObjectRequest *previousObjectRequest = nil;
1500
                        for (ASIPithosObjectRequest *objectRequest in objectRequests) {
1501
                            if (operation.isCancelled)
1502
                                return;
1503
                            objectRequest.delegate = self;
1504
                            objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1505
                            objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1506
                            NSString *messagePrefix = [NSString stringWithFormat:@"Copying '%@/%@' to '%@/%@'", 
1507
                                                       [objectRequest.userInfo objectForKey:@"sourceContainerName"], 
1508
                                                       [objectRequest.userInfo objectForKey:@"sourceObjectName"], 
1509
                                                       [objectRequest.userInfo objectForKey:@"destinationContainerName"], 
1510
                                                       [objectRequest.userInfo objectForKey:@"destinationObjectName"]];
1511
                            PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCopy 
1512
                                                                                       message:messagePrefix];
1513
                            [(NSMutableDictionary *)(objectRequest.userInfo) addEntriesFromDictionary:
1514
                             [NSDictionary dictionaryWithObjectsAndKeys:
1515
                              [NSArray arrayWithObject:destinationNode], @"forceRefreshNodes", 
1516
                              activity, @"activity", 
1517
                              [messagePrefix stringByAppendingString:@" (stopped)"], @"stoppedActivityMessage", 
1518
                              [messagePrefix stringByAppendingString:@" (failed)"], @"failedActivityMessage", 
1519
                              [messagePrefix stringByAppendingString:@" (finished)"], @"finishedActivityMessage", 
1520
                              [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
1521
                              [NSNumber numberWithUnsignedInteger:10], @"retries", 
1522
                              NSStringFromSelector(@selector(copyFinished:)), @"didFinishSelector", 
1523
                              NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
1524
                              copyNetworkQueue, @"networkQueue", 
1525
                              @"copy", @"operationType", 
1526
                              nil]];
1527
                            if (previousObjectRequest)
1528
                                [objectRequest addDependency:previousObjectRequest];
1529
                            previousObjectRequest = objectRequest;
1530
                            [copyNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
1531
                        }
1532
                    }
1533
                }
1582 1534
            }];
1583 1535
            [copyQueue addOperation:operation];
1584 1536
        }
......
1614 1566
                                                                             selector:NSSelectorFromString([request.userInfo objectForKey:@"didFinishSelector"]) 
1615 1567
                                                                               object:request] autorelease];
1616 1568
    operation.completionBlock = ^{
1617
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1618
        if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1619
            dispatch_async(dispatch_get_main_queue(), ^{
1620
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1621
                                  withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1622
            });
1569
        @autoreleasepool {
1570
            if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1571
                dispatch_async(dispatch_get_main_queue(), ^{
1572
                    [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1573
                                      withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1574
                });
1575
            }
1623 1576
        }
1624
        [pool drain];
1625 1577
    };
1626 1578
    [(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
1627 1579
    [callbackQueue addOperation:operation];
......
1658 1610
                                                                                 selector:NSSelectorFromString([request.userInfo objectForKey:@"didFailSelector"]) 
1659 1611
                                                                                   object:request] autorelease];
1660 1612
        operation.completionBlock = ^{
1661
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1662
            if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1663
                dispatch_async(dispatch_get_main_queue(), ^{
1664
                    [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1665
                                      withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1666
                });
1613
            @autoreleasepool {
1614
                if ([[request.userInfo objectForKey:@"operation"] isCancelled]) {
1615
                    dispatch_async(dispatch_get_main_queue(), ^{
1616
                        [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1617
                                          withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1618
                    });
1619
                }
1667 1620
            }
1668
            [pool drain];
1669 1621
        };
1670 1622
        [(NSMutableDictionary *)request.userInfo setObject:operation forKey:@"operation"];
1671 1623
        [callbackQueue addOperation:operation];
......
1673 1625
}
1674 1626

  
1675 1627
- (void)requestFailed:(ASIPithosRequest *)request {
1676
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1677
    NSOperation *operation = [request.userInfo objectForKey:@"operation"];
1678
    DLog(@"Request failed: %@", request.url);
1679
    if (operation.isCancelled) {
1680
        [pool drain];
1681
        return;        
1682
    }
1683
    if (request.isCancelled) {
1684
        dispatch_async(dispatch_get_main_queue(), ^{
1685
            [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1686
                              withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1687
        });
1688
        [pool drain];
1689
        return;
1690
    }
1691
    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
1692
    if (retries > 0) {
1693
        ASIPithosRequest *newRequest = (ASIPithosRequest *)[[PithosUtilities copyRequest:request] autorelease];
1694
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
1695
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithBool:NO] forKey:@"unexpectedResponseStatus"];
1696
        [[newRequest.userInfo objectForKey:@"networkQueue"] addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]];
1697
    } else {
1698
        dispatch_async(dispatch_get_main_queue(), ^{
1699
            [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1700
                              withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]];
1701
        });
1702
        if ([[request.userInfo objectForKey:@"unexpectedResponseStatus"] boolValue])
1703
            [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
1704
        else
1705
            [PithosUtilities httpRequestErrorAlertWithRequest:request];
1628
    @autoreleasepool {
1629
        NSOperation *operation = [request.userInfo objectForKey:@"operation"];
1630
        DLog(@"Request failed: %@", request.url);
1631
        if (operation.isCancelled)
1632
            return;
1633
        if (request.isCancelled) {
1634
            dispatch_async(dispatch_get_main_queue(), ^{
1635
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1636
                                  withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]];
1637
            });
1638
            return;
1639
        }
1640
        NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
1641
        if (retries > 0) {
1642
            ASIPithosRequest *newRequest = (ASIPithosRequest *)[[PithosUtilities copyRequest:request] autorelease];
1643
            [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
1644
            [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithBool:NO] forKey:@"unexpectedResponseStatus"];
1645
            [[newRequest.userInfo objectForKey:@"networkQueue"] addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]];
1646
        } else {
1647
            dispatch_async(dispatch_get_main_queue(), ^{
1648
                [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] 
1649
                                  withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]];
1650
            });
1651
            if ([[request.userInfo objectForKey:@"unexpectedResponseStatus"] boolValue])
1652
                [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
1653
            else
1654
                [PithosUtilities httpRequestErrorAlertWithRequest:request];
1655
        }
1706 1656
    }
1707
    [pool drain];
1708 1657
}
1709 1658

  
1710 1659
- (void)downloadObjectFinished:(ASIPithosObjectRequest *)objectRequest {
1711
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1712
    NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1713
    DLog(@"Download finished: %@", objectRequest.url);
1714
    if (operation.isCancelled) {
1715
        [self requestFailed:objectRequest];
1716
    } else if (objectRequest.responseStatusCode == 200) {
1717
        NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
1718
        PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1719
        NSUInteger totalBytes = activity.totalBytes;
1720
        
1721
        // XXX change contentLength to objectContentLength if it is fixed in the server
1722
        if ([objectRequest contentLength] == 0) {
1723
            // The check above was:
1724
            // if (([objectRequest contentLength] == 0) && ![PithosUtilities isContentTypeDirectory:[objectRequest contentType]]) {
1725
            // I checked for directory content types in order not to create a file in place of a directory,
1726
            // but this callback method is not called in the case of a directory download.
1727
            // It maybe the case though, when downloading an old version of an object, is of a directory content type.
1728
            // In this case, a file should be created. This is actually a feature that allows you to hide data in a directory object.
1729
            DLog(@"Downloaded  0 bytes");
1730
            NSFileManager *fileManager = [NSFileManager defaultManager];
1731
            if (![fileManager fileExistsAtPath:filePath]) {
1732
                if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) {
1733
                    dispatch_async(dispatch_get_main_queue(), ^{
1734
                        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
1735
                        [alert setMessageText:@"Create File Error"];
1736
                        [alert setInformativeText:[NSString stringWithFormat:@"Cannot create zero length file at %@", filePath]];
1737
                        [alert addButtonWithTitle:@"OK"];
1738
                        [alert runModal];
1739
                    });
1660
    @autoreleasepool {
1661
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1662
        DLog(@"Download finished: %@", objectRequest.url);
1663
        if (operation.isCancelled) {
1664
            [self requestFailed:objectRequest];
1665
        } else if (objectRequest.responseStatusCode == 200) {
1666
            NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"];
1667
            PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1668
            NSUInteger totalBytes = activity.totalBytes;
1669
            
1670
            // XXX change contentLength to objectContentLength if it is fixed in the server
1671
            if ([objectRequest contentLength] == 0) {
1672
                // The check above was:
1673
                // if (([objectRequest contentLength] == 0) && ![PithosUtilities isContentTypeDirectory:[objectRequest contentType]]) {
1674
                // I checked for directory content types in order not to create a file in place of a directory,
1675
                // but this callback method is not called in the case of a directory download.
1676
                // It maybe the case though, when downloading an old version of an object, is of a directory content type.
1677
                // In this case, a file should be created. This is actually a feature that allows you to hide data in a directory object.
1678
                DLog(@"Downloaded  0 bytes");
1679
                NSFileManager *fileManager = [NSFileManager defaultManager];
1680
                if (![fileManager fileExistsAtPath:filePath]) {
1681
                    if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) {
1682
                        dispatch_async(dispatch_get_main_queue(), ^{
1683
                            NSAlert *alert = [[[NSAlert alloc] init] autorelease];
1684
                            [alert setMessageText:@"Create File Error"];
1685
                            [alert setInformativeText:[NSString stringWithFormat:@"Cannot create zero length file at %@", filePath]];
1686
                            [alert addButtonWithTitle:@"OK"];
1687
                            [alert runModal];
1688
                        });
1689
                    }
1740 1690
                }
1741 1691
            }
1692
            
1693
            NSUInteger currentBytes = [objectRequest objectContentLength];
1694
            if (currentBytes == 0)
1695
                currentBytes = totalBytes;
1696
            dispatch_async(dispatch_get_main_queue(), ^{
1697
                [activityFacility endActivity:activity 
1698
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1699
                                   totalBytes:totalBytes 
1700
                                 currentBytes:currentBytes];
1701
            });
1702
        } else {
1703
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1704
            [self requestFailed:objectRequest];
1742 1705
        }
1743
        
1744
        NSUInteger currentBytes = [objectRequest objectContentLength];
1745
        if (currentBytes == 0)
1746
            currentBytes = totalBytes;
1747
        dispatch_async(dispatch_get_main_queue(), ^{
1748
            [activityFacility endActivity:activity 
1749
                              withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1750
                               totalBytes:totalBytes 
1751
                             currentBytes:currentBytes];
1752
        });
1753
    } else {
1754
        [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1755
        [self requestFailed:objectRequest];
1756 1706
    }
1757
    [pool drain];
1758 1707
}
1759 1708

  
1760 1709
- (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest {
1761
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1762
    NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1763
    DLog(@"Upload directory object finished: %@", objectRequest.url);
1764
    if (operation.isCancelled) {
1765
        [self requestFailed:objectRequest];
1766
    } else if (objectRequest.responseStatusCode == 201) {
1767
        DLog(@"Directory object created: %@", objectRequest.url);
1768
        dispatch_async(dispatch_get_main_queue(), ^{
1769
            [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1770
                              withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1771
            for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1772
                [node forceRefresh];
1773
            }
1774
            for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1775
                [node refresh];
1776
            }
1777
            if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1778
                [self forceRefresh:self];
1779
            else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1780
                [self refresh:self];
1781
        });
1782
    } else {
1783
        [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1784
        [self requestFailed:objectRequest];
1710
    @autoreleasepool {
1711
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1712
        DLog(@"Upload directory object finished: %@", objectRequest.url);
1713
        if (operation.isCancelled) {
1714
            [self requestFailed:objectRequest];
1715
        } else if (objectRequest.responseStatusCode == 201) {
1716
            DLog(@"Directory object created: %@", objectRequest.url);
1717
            dispatch_async(dispatch_get_main_queue(), ^{
1718
                [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] 
1719
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]];
1720
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1721
                    [node forceRefresh];
1722
                }
1723
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1724
                    [node refresh];
1725
                }
1726
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1727
                    [self forceRefresh:self];
1728
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1729
                    [self refresh:self];
1730
            });
1731
        } else {
1732
            [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1733
            [self requestFailed:objectRequest];
1734
        }
1785 1735
    }
1786
    [pool drain];
1787 1736
}
1788 1737

  
1789 1738
- (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest {
1790
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1791
    NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1792
    DLog(@"Upload using hashmap finished: %@", objectRequest.url);
1793
    NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
1794
    PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1795
    NSUInteger totalBytes = activity.totalBytes;
1796
    NSUInteger currentBytes = activity.currentBytes;
1797
    if (operation.isCancelled) {
1798
        [self requestFailed:objectRequest];
1799
    } else if (objectRequest.responseStatusCode == 201) {
1800
        DLog(@"Object created: %@", objectRequest.url);
1801
        dispatch_async(dispatch_get_main_queue(), ^{
1802
            [activityFacility endActivity:activity 
1803
                              withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1804
                               totalBytes:totalBytes 
1805
                             currentBytes:totalBytes];
1806
            for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1807
                [node forceRefresh];
1808
            }
1809
            for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1810
                [node refresh];
1811
            }
1812
            if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1813
                [self forceRefresh:self];
1814
            else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1815
                [self refresh:self];        
1816
        });
1817
    } else if (objectRequest.responseStatusCode == 409) {
1818
        NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue];
1819
        if (iteration == 0) {
1820
            DLog(@"Upload iteration limit reached: %@", objectRequest.url);
1739
    @autoreleasepool {
1740
        NSOperation *operation = [objectRequest.userInfo objectForKey:@"operation"];
1741
        DLog(@"Upload using hashmap finished: %@", objectRequest.url);
1742
        NSString *fileName = [objectRequest.userInfo objectForKey:@"fileName"];
1743
        PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"];
1744
        NSUInteger totalBytes = activity.totalBytes;
1745
        NSUInteger currentBytes = activity.currentBytes;
1746
        if (operation.isCancelled) {
1747
            [self requestFailed:objectRequest];
1748
        } else if (objectRequest.responseStatusCode == 201) {
1749
            DLog(@"Object created: %@", objectRequest.url);
1821 1750
            dispatch_async(dispatch_get_main_queue(), ^{
1822 1751
                [activityFacility endActivity:activity 
1823
                                  withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; 
1824
                NSAlert *alert = [[[NSAlert alloc] init] autorelease];
1825
                [alert setMessageText:@"Upload Timeout"];
1826
                [alert setInformativeText:[NSString stringWithFormat:@"Upload iteration limit reached for object with path '%@'", 
1827
                                           [objectRequest.userInfo objectForKey:@"objectName"]]];
1828
                [alert addButtonWithTitle:@"OK"];
1829
                [alert runModal];
1752
                                  withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] 
1753
                                   totalBytes:totalBytes 
1754
                                 currentBytes:totalBytes];
1755
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"forceRefreshNodes"]) {
1756
                    [node forceRefresh];
1757
                }
1758
                for (PithosNode *node in [objectRequest.userInfo objectForKey:@"refreshNodes"]) {
1759
                    [node refresh];
1760
                }
1761
                if ([[objectRequest.userInfo objectForKey:@"forceRefresh"] boolValue])
1762
                    [self forceRefresh:self];
1763
                else if ([[objectRequest.userInfo objectForKey:@"refresh"] boolValue])
1764
                    [self refresh:self];        
1830 1765
            });
1831
            [pool drain];
1832
            return;
1833
        }
1834
        DLog(@"object is missing hashes: %@", objectRequest.url);
1835
        NSIndexSet *missingBlocks = [PithosUtilities missingBlocksForHashes:[objectRequest.userInfo objectForKey:@"hashes"]
1836
                                                          withMissingHashes:[objectRequest hashes]];
1837
        NSUInteger blockSize = [[objectRequest.userInfo objectForKey:@"blockSize"] unsignedIntegerValue];
1838
        if (totalBytes >= [missingBlocks count]*blockSize)
1839
            currentBytes = totalBytes - [missingBlocks count]*blockSize;
1840
        dispatch_async(dispatch_get_main_queue(), ^{
1841
            [activityFacility updateActivity:activity 
1842
                                 withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (totalBytes ? (100*(currentBytes + 0.0)/(totalBytes + 0.0)) : 100)] 
1843
                                  totalBytes:totalBytes 
1844
                                currentBytes:currentBytes];
1845
        });
1846
        NSUInteger missingBlockIndex = [missingBlocks firstIndex];
1847
        __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithPithos:pithos 
1848
                                                                                                         containerName:[objectRequest.userInfo objectForKey:@"containerName"] 
1849
                                                                                                             blockSize:blockSize 
1850
                                                                                                               forFile:[objectRequest.userInfo objectForKey:@"filePath"] 
1851
                                                                                                     missingBlockIndex:missingBlockIndex 
1852
                                                                                                        sharingAccount:[objectRequest.userInfo objectForKey:@"sharingAccount"]];
1853
        newContainerRequest.delegate = self;
1854
        newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
1855
        newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
1856
        newContainerRequest.userInfo = objectRequest.userInfo;
1857
        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"];
1858
        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"];
1859
        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"];
1860
        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"];
1861
        [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"];
1862
        [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){
1863
            [activityFacility updateActivity:activity 
1864
                                 withMessage:[NSString stringWithFormat:@"Uploading '%@' (%.0f%%)", fileName, (activity.totalBytes ? (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0)) : 100)] 
1865
                                  totalBytes:activity.totalBytes 
1866
                                currentBytes:(activity.currentBytes + size)];
1867
        }];
1868
        [uploadNetworkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]];
1869
    } else {
1870
        [(NSMutableDictionary *)(objectRequest.userInfo)setObject:[NSNumber numberWithBool:YES] forKey:@"unexpectedResponseStatus"];
1871
        [self requestFailed:objectRequest];
1872
    }
1873
    [pool drain];
1874
}
1875

  
1876
- (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest {
1877
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff