From: Miltiadis Vasilakis Date: Fri, 21 Oct 2011 17:56:56 +0000 (+0300) Subject: Sync is saving the last completed date. X-Git-Tag: v0.1~36 X-Git-Url: https://code.grnet.gr/git/pithos-macos/commitdiff_plain/3812626f878f66ea4fbe3570f473dfed84eb91ce Sync is saving the last completed date. Remote objects that are deleted in sync are moved to trash instead. Dates shown in descriptive format. --- diff --git a/pithos-macos.xcodeproj/project.pbxproj b/pithos-macos.xcodeproj/project.pbxproj index e45a1c5..b9787d3 100644 --- a/pithos-macos.xcodeproj/project.pbxproj +++ b/pithos-macos.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 615615DD140CECDB00017BD4 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 615615DC140CECDB00017BD4 /* libz.dylib */; }; 615A444E140F8A5700308614 /* MetadataKeyTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 615A444D140F8A5700308614 /* MetadataKeyTransformer.m */; }; 615A4451140F8A7F00308614 /* MetadataKeyFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 615A4450140F8A7F00308614 /* MetadataKeyFormatter.m */; }; + 6164B2DD1450E55C00D4C1AB /* LastCompletedSyncTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6164B2DC1450E55C00D4C1AB /* LastCompletedSyncTransformer.m */; }; 616FC0AF13F91BA400140A33 /* PithosObjectNodeInfoController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */; }; 616FC0B313F97D0800140A33 /* PithosNodeInfoController.m in Sources */ = {isa = PBXBuildFile; fileRef = 616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */; }; 617460F1140BE45C00D333A1 /* BytesExtendedSizeTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 617460F0140BE45C00D333A1 /* BytesExtendedSizeTransformer.m */; }; @@ -164,6 +165,8 @@ 615A444D140F8A5700308614 /* MetadataKeyTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MetadataKeyTransformer.m; path = "pithos-macos/MetadataKeyTransformer.m"; sourceTree = ""; }; 615A444F140F8A7F00308614 /* MetadataKeyFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MetadataKeyFormatter.h; path = "pithos-macos/MetadataKeyFormatter.h"; sourceTree = ""; }; 615A4450140F8A7F00308614 /* MetadataKeyFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MetadataKeyFormatter.m; path = "pithos-macos/MetadataKeyFormatter.m"; sourceTree = ""; }; + 6164B2DB1450E55C00D4C1AB /* LastCompletedSyncTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LastCompletedSyncTransformer.h; path = "pithos-macos/LastCompletedSyncTransformer.h"; sourceTree = ""; }; + 6164B2DC1450E55C00D4C1AB /* LastCompletedSyncTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LastCompletedSyncTransformer.m; path = "pithos-macos/LastCompletedSyncTransformer.m"; sourceTree = ""; }; 616FC0AE13F91BA400140A33 /* PithosObjectNodeInfoController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PithosObjectNodeInfoController.xib; sourceTree = ""; }; 616FC0B113F97D0800140A33 /* PithosNodeInfoController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosNodeInfoController.h; sourceTree = ""; }; 616FC0B213F97D0800140A33 /* PithosNodeInfoController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosNodeInfoController.m; sourceTree = ""; }; @@ -408,6 +411,8 @@ 6152D091143334CC00803874 /* AllowedToBoolTransformer.m */, 613629B3143E0F8B00363787 /* GroupMembersDictionaryTransformer.h */, 613629B4143E0F8B00363787 /* GroupMembersDictionaryTransformer.m */, + 6164B2DB1450E55C00D4C1AB /* LastCompletedSyncTransformer.h */, + 6164B2DC1450E55C00D4C1AB /* LastCompletedSyncTransformer.m */, ); name = "Value Transformers"; sourceTree = ""; @@ -616,6 +621,7 @@ 61F040F31448547000A0C788 /* FileMD5Hash.c in Sources */, 61F04132144DB97200A0C788 /* PithosLocalObjectState.m in Sources */, 61F04133144DB97600A0C788 /* PithosSyncDaemon.m in Sources */, + 6164B2DD1450E55C00D4C1AB /* LastCompletedSyncTransformer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/pithos-macos/LastCompletedSyncTransformer.h b/pithos-macos/LastCompletedSyncTransformer.h new file mode 100644 index 0000000..af6c41d --- /dev/null +++ b/pithos-macos/LastCompletedSyncTransformer.h @@ -0,0 +1,39 @@ +// +// LastCompletedSyncTransformer.h +// pithos-macos +// +// Copyright 2011 GRNET S.A. All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and +// documentation are those of the authors and should not be +// interpreted as representing official policies, either expressed +// or implied, of GRNET S.A. + +@interface LastCompletedSyncTransformer : NSValueTransformer +@end diff --git a/pithos-macos/LastCompletedSyncTransformer.m b/pithos-macos/LastCompletedSyncTransformer.m new file mode 100644 index 0000000..ecdaf44 --- /dev/null +++ b/pithos-macos/LastCompletedSyncTransformer.m @@ -0,0 +1,81 @@ +// +// LastCompletedSyncTransformer.m +// pithos-macos +// +// Copyright 2011 GRNET S.A. All rights reserved. +// +// Redistribution and use in source and binary forms, with or +// without modification, are permitted provided that the following +// conditions are met: +// +// 1. Redistributions of source code must retain the above +// copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and +// documentation are those of the authors and should not be +// interpreted as representing official policies, either expressed +// or implied, of GRNET S.A. + +#import "LastCompletedSyncTransformer.h" + +@implementation LastCompletedSyncTransformer + ++ (Class)transformedValueClass { + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation { + return NO; +} + +- (id)transformedValue:(id)value { + if (value == nil) + return @"Last Sync: -"; + + NSCalendar *calendar = [NSCalendar currentCalendar]; + NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]]; + [comps setHour:23]; + [comps setMinute:59]; + [comps setSecond:59]; + NSTimeInterval timeInterval = [[calendar dateFromComponents:comps] timeIntervalSinceDate:(NSDate *)value]; + if (timeInterval < 86400) { + // Today + return [NSString stringWithFormat:@"Last Sync: Today %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterNoStyle + timeStyle:NSDateFormatterShortStyle]]; + } else if (timeInterval < 172800) { + // Yesterday + return [NSString stringWithFormat:@"Last Sync: Yesterday %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterNoStyle + timeStyle:NSDateFormatterShortStyle]]; + } else { + return [NSString stringWithFormat:@"Last Sync: %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterShortStyle + timeStyle:NSDateFormatterShortStyle]]; + } +} + ++ (void)initialize { + [[NSValueTransformer class] setValueTransformer:[self new] forName:@"LastCompletedSyncTransformer"]; +} + +@end diff --git a/pithos-macos/LastModifiedDateTransformer.m b/pithos-macos/LastModifiedDateTransformer.m index a5420b4..b14fda6 100644 --- a/pithos-macos/LastModifiedDateTransformer.m +++ b/pithos-macos/LastModifiedDateTransformer.m @@ -51,10 +51,28 @@ - (id)transformedValue:(id)value { if (value == nil) return nil; - // XXX make it more like finder - return [NSDateFormatter localizedStringFromDate:(NSDate *)value - dateStyle:NSDateFormatterShortStyle - timeStyle:NSDateFormatterShortStyle]; + + NSCalendar *calendar = [NSCalendar currentCalendar]; + NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]]; + [comps setHour:23]; + [comps setMinute:59]; + [comps setSecond:59]; + NSTimeInterval timeInterval = [[calendar dateFromComponents:comps] timeIntervalSinceDate:(NSDate *)value]; + if (timeInterval < 86400) { + // Today + return [NSString stringWithFormat:@"Today %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterNoStyle + timeStyle:NSDateFormatterShortStyle]]; + } else if (timeInterval < 172800) { + // Yesterday + return [NSString stringWithFormat:@"Yesterday %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterNoStyle + timeStyle:NSDateFormatterShortStyle]]; + } else { + return [NSDateFormatter localizedStringFromDate:(NSDate *)value + dateStyle:NSDateFormatterShortStyle + timeStyle:NSDateFormatterShortStyle]; + } } + (void)initialize { diff --git a/pithos-macos/PithosSyncDaemon.h b/pithos-macos/PithosSyncDaemon.h index 8b454a3..6c7910f 100644 --- a/pithos-macos/PithosSyncDaemon.h +++ b/pithos-macos/PithosSyncDaemon.h @@ -56,6 +56,8 @@ NSUInteger syncOperationCount; BOOL newSyncRequested; + NSDate *lastCompletedSync; + BOOL syncIncomplete; ASINetworkQueue *queue; NSTimer *timer; @@ -72,6 +74,8 @@ @property (nonatomic, readonly) NSString *pithosStateFilePath; @property (nonatomic, readonly) NSString *tempDownloadsDirPath; +@property (nonatomic, retain) NSDate *lastCompletedSync; + - (id)initWithDirectoryPath:(NSString *)aDirectoryPath containerName:(NSString *)aContainerName timeInterval:(NSTimeInterval)aTimeInterval; diff --git a/pithos-macos/PithosSyncDaemon.m b/pithos-macos/PithosSyncDaemon.m index a06372f..8631443 100644 --- a/pithos-macos/PithosSyncDaemon.m +++ b/pithos-macos/PithosSyncDaemon.m @@ -62,10 +62,14 @@ object:(ASIPithosObject *)object localFilePath:(NSString *)filePath; - (void)requestFailed:(ASIPithosRequest *)request; + +- (void)increaseSyncOperationCount; +- (void)decreaseSyncOperationCount; + @end @implementation PithosSyncDaemon -@synthesize blockHash, blockSize, lastModified, remoteObjects, storedLocalObjectStates; +@synthesize blockHash, blockSize, lastModified, lastCompletedSync, remoteObjects, storedLocalObjectStates; @synthesize pithosStateFilePath, tempDownloadsDirPath; #pragma mark - @@ -120,6 +124,7 @@ [storedLocalObjectStates release]; [remoteObjects release]; [objects release]; + [lastCompletedSync release]; [lastModified release]; [blockHash release]; [containerName release]; @@ -189,6 +194,23 @@ [data writeToFile:self.pithosStateFilePath atomically:YES]; } +- (void)increaseSyncOperationCount { + @synchronized(self) { + syncOperationCount++; + } +} + +- (void)decreaseSyncOperationCount { + @synchronized(self) { + syncOperationCount--; + if (!syncOperationCount && !syncIncomplete) { + self.lastCompletedSync = [NSDate date]; + [activityFacility startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Completed %@", lastCompletedSync]]; + } + } +} + - (void)sync { @synchronized(self) { if (syncOperationCount) { @@ -199,6 +221,7 @@ // The first operation is the server listing syncOperationCount = 1; newSyncRequested = NO; + syncIncomplete = NO; } } @@ -244,9 +267,12 @@ message:@"Sync: Getting server listing"]; containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: activity, @"activity", + @"Sync: Getting server listing (stopped)", @"stoppedActivityMessage", + @"Sync: Getting server listing (failed)", @"failedActivityMessage", + @"Sync: Getting server listing (finished)", @"finishedActivityMessage", + [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", nil]; -// [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh]]; } @@ -400,9 +426,7 @@ message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; } else if (storedState.tmpDownloadFile == nil) { // Create new local object - @synchronized(self) { - syncOperationCount++; - } + [self increaseSyncOperationCount]; __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectBlockDataRequestWithContainerName:containerName object:object blockIndex:0 @@ -423,7 +447,7 @@ [NSString stringWithFormat:@"Sync: Downloading '%@' (stopped)", object.name], @"stoppedActivityMessage", [NSString stringWithFormat:@"Sync: Downloading '%@' (failed)", object.name], @"failedActivityMessage", [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage", - [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", + [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", nil]; [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){ @@ -434,13 +458,10 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; -// [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; } else { // Resume local object download - @synchronized(self) { - syncOperationCount++; - } + [self increaseSyncOperationCount]; ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectHashmapRequestWithContainerName:containerName objectName:object.name]; objectRequest.delegate = self; @@ -458,22 +479,19 @@ [NSString stringWithFormat:@"Sync: Downloading '%@' (stopped)", object.name], @"stoppedActivityMessage", [NSString stringWithFormat:@"Sync: Downloading '%@' (failed)", object.name], @"failedActivityMessage", [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage", - [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", + [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", nil]; -// [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; } } -(void)updateServerStateWithCurrentState:(PithosLocalObjectState *)currentState object:(ASIPithosObject *)object localFilePath:(NSString *)filePath { + [self increaseSyncOperationCount]; if (currentState.isDirectory) { // Create remote directory object - @synchronized(self) { - syncOperationCount++; - } ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName objectName:object.name eTag:nil @@ -499,31 +517,41 @@ [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", nil]; -// [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; } else if ([currentState.md5 isEqualToString:@" "] && [currentState.hashMapHash isEqualToString:@" "]) { // Delete remote object - @synchronized(self) { - syncOperationCount++; + NSString *safeObjectName = [PithosUtilities safeObjectNameForContainerName:@"trash" + objectName:object.name]; + if (safeObjectName) { + ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithContainerName:containerName + objectName:object.name + destinationContainerName:@"trash" + destinationObjectName:safeObjectName + checkIfExists:NO]; + if (objectRequest) { + objectRequest.delegate = self; + objectRequest.didFinishSelector = @selector(moveObjectToTrashFinished:); + objectRequest.didFailSelector = @selector(requestFailed:); + PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete + message:[NSString stringWithFormat:@"Sync: Moving to trash '%@'", object.name]]; + objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + object, @"pithosObject", + activity, @"activity", + [NSString stringWithFormat:@"Sync: Moving to trash '%@' (stopped)", object.name], @"stoppedActivityMessage", + [NSString stringWithFormat:@"Sync: Moving to trash '%@' (failed)", object.name], @"failedActivityMessage", + [NSString stringWithFormat:@"Sync: Moving to trash '%@' (finished)", object.name], @"finishedActivityMessage", + [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", + [NSNumber numberWithUnsignedInteger:10], @"retries", + nil]; + [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + } else { + syncIncomplete = YES; + [self decreaseSyncOperationCount]; + } + } else { + syncIncomplete = YES; + [self decreaseSyncOperationCount]; } - ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:containerName - objectName:object.name]; - objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(deleteObjectFinished:); - objectRequest.didFailSelector = @selector(requestFailed:); - PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete - message:[NSString stringWithFormat:@"Sync: Deleting '%@'", object.name]]; - objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: - object, @"pithosObject", - activity, @"activity", - [NSString stringWithFormat:@"Sync: Deleting '%@' (stopped)", object.name], @"stoppedActivityMessage", - [NSString stringWithFormat:@"Sync: Deleting '%@' (failed)", object.name], @"failedActivityMessage", - [NSString stringWithFormat:@"Sync: Deleting '%@' (finished)", object.name], @"finishedActivityMessage", - [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", - [NSNumber numberWithUnsignedInteger:10], @"retries", - nil]; -// [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; } else { // Upload file to remote object NSError *error = nil; @@ -543,9 +571,6 @@ hashes:&hashes sharingAccount:nil]; if (objectRequest) { - @synchronized(self) { - syncOperationCount++; - } objectRequest.delegate = self; objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); objectRequest.didFailSelector = @selector(requestFailed:); @@ -563,11 +588,13 @@ [NSString stringWithFormat:@"Sync: Uploading '%@' (stopped)", object.name], @"stoppedActivityMessage", [NSString stringWithFormat:@"Sync: Uploading '%@' (failed)", object.name], @"failedActivityMessage", [NSString stringWithFormat:@"Sync: Uploading '%@' (100%%)", object.name], @"finishedActivityMessage", - [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", + [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", nil]]; -// [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; + } else { + syncIncomplete = YES; + [self decreaseSyncOperationCount]; } } @@ -613,13 +640,12 @@ newContainerRequest.didFailSelector = @selector(listRequestFailed:); newContainerRequest.userInfo = newContainerRequest.userInfo; [(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; -// [[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; return; } } [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:@"Sync: Getting server listing (finished)"]; + withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *containerDirectoryPath = [directoryPath stringByAppendingPathComponent:containerName]; NSError *error = nil; @@ -769,7 +795,7 @@ } } @synchronized(self) { - syncOperationCount--; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -778,11 +804,10 @@ if (retries > 0) { ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; -// [[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:@"Sync: Getting server listing (failed)"]; + withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { // Since the server listing failed in all retries, the operation finished and the sync cycle is completeted unsuccesfully syncOperationCount = 0; @@ -796,7 +821,7 @@ - (void)listRequestFailed:(ASIPithosContainerRequest *)containerRequest { if ([containerRequest isCancelled]) { [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:@"Sync: Getting server listing (stopped)"]; + withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; [objects release]; objects = nil; @synchronized(self) { @@ -809,11 +834,10 @@ if (retries > 0) { ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; -// [[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:NSOperationQueuePriorityVeryHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:@"Sync: Getting server listing (failed)"]; + withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; [objects release]; objects = nil; @synchronized(self) { @@ -838,7 +862,8 @@ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -861,7 +886,8 @@ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -895,7 +921,8 @@ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -914,7 +941,8 @@ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -931,7 +959,8 @@ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -957,7 +986,7 @@ [self saveLocalState]; @synchronized(self) { - syncOperationCount--; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -967,7 +996,8 @@ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (!syncOperationCount) [self sync]; } @@ -991,8 +1021,7 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; -// [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } } else if (objectRequest.responseStatusCode == 412) { @@ -1000,7 +1029,8 @@ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -1016,7 +1046,8 @@ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (!syncOperationCount) [self sync]; } @@ -1058,8 +1089,7 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; -// [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; - [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityHigh]]; + [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } else { [self requestFailed:objectRequest]; @@ -1075,7 +1105,7 @@ [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -1084,15 +1114,15 @@ } } -- (void)deleteObjectFinished:(ASIPithosObjectRequest *)objectRequest { - NSLog(@"Sync::delete object finished: %@", objectRequest.url); - if (objectRequest.responseStatusCode == 204) { +- (void)moveObjectToTrashFinished:(ASIPithosObjectRequest *)objectRequest { + NSLog(@"Sync::move object to trash finished: %@", objectRequest.url); + if (objectRequest.responseStatusCode == 201) { [storedLocalObjectStates removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]]; [self saveLocalState]; [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -1121,7 +1151,7 @@ totalBytes:totalBytes currentBytes:totalBytes]; @synchronized(self) { - syncOperationCount--; + [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) [self sync]; } @@ -1130,7 +1160,8 @@ [activityFacility endActivity:activity withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (!syncOperationCount) [self sync]; } @@ -1140,10 +1171,9 @@ if (iteration == 0) { NSLog(@"Sync::upload iteration limit reached: %@", objectRequest.url); [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; - @synchronized(self) { - syncOperationCount--; - } + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; return; } NSLog(@"Sync::object is missing hashes: %@", objectRequest.url); @@ -1175,7 +1205,6 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; -// [[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } else { @@ -1217,14 +1246,14 @@ [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"]; -// [[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { if (newSyncRequested) { [activityFacility endActivity:activity withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (!syncOperationCount) [self sync]; } @@ -1247,7 +1276,6 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; -// [[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } @@ -1260,16 +1288,16 @@ if ([request isCancelled]) { [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; - @synchronized(self) { - syncOperationCount--; - } + syncIncomplete = YES; + [self decreaseSyncOperationCount]; return; } if (newSyncRequested) { [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { - syncOperationCount--; + syncIncomplete = YES; + [self decreaseSyncOperationCount]; if (!syncOperationCount) [self sync]; } @@ -1279,14 +1307,12 @@ if (retries > 0) { ASIPithosRequest *newRequest = (ASIPithosRequest *)[PithosUtilities copyRequest:request]; [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; -// [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; [queue addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]]; - @synchronized(self) { - syncOperationCount--; - } + syncIncomplete = YES; + [self decreaseSyncOperationCount]; } } diff --git a/pithos-macos/en.lproj/MainMenu.xib b/pithos-macos/en.lproj/MainMenu.xib index fdd2fc2..700229d 100644 --- a/pithos-macos/en.lproj/MainMenu.xib +++ b/pithos-macos/en.lproj/MainMenu.xib @@ -2180,6 +2180,42 @@ 561 + + + title: delegate.pithosSyncDaemon.lastCompletedSync + + + + + + title: delegate.pithosSyncDaemon.lastCompletedSync + title + delegate.pithosSyncDaemon.lastCompletedSync + + NSValueTransformerName + LastCompletedSyncTransformer + + 2 + + + 565 + + + + enabled: delegate.alwaysNo + + + + + + enabled: delegate.alwaysNo + enabled + delegate.alwaysNo + 2 + + + 569 + @@ -3643,7 +3679,7 @@ - 561 + 569 0 diff --git a/pithos-macos/pithos_macosAppDelegate.h b/pithos-macos/pithos_macosAppDelegate.h index c684274..93f954a 100644 --- a/pithos-macos/pithos_macosAppDelegate.h +++ b/pithos-macos/pithos_macosAppDelegate.h @@ -44,7 +44,8 @@ IBOutlet PithosBrowserController *pithosBrowserController; IBOutlet PithosPreferencesController *pithosPreferencesController; - PithosSyncDaemon *pithosSyncDaemon; + IBOutlet PithosSyncDaemon *pithosSyncDaemon; + BOOL alwaysNo; IBOutlet NSMenu *statusMenu; NSStatusItem *statusItem; @@ -78,4 +79,7 @@ @property (nonatomic, readonly) NSString *syncContainerName; @property (nonatomic, assign) NSTimeInterval syncTimeInterval; +@property (nonatomic, retain) PithosSyncDaemon *pithosSyncDaemon; +@property (nonatomic, assign) BOOL alwaysNo; + @end diff --git a/pithos-macos/pithos_macosAppDelegate.m b/pithos-macos/pithos_macosAppDelegate.m index 235a9f7..b05ac13 100644 --- a/pithos-macos/pithos_macosAppDelegate.m +++ b/pithos-macos/pithos_macosAppDelegate.m @@ -44,7 +44,7 @@ @implementation pithos_macosAppDelegate @synthesize storageURLPrefix, publicURLPrefix, loginURLPrefix, aboutURL; -@synthesize syncDirectoryPath, syncContainerName, syncTimeInterval; +@synthesize syncDirectoryPath, syncContainerName, syncTimeInterval, pithosSyncDaemon, alwaysNo; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { NSURL *testURL; @@ -99,7 +99,7 @@ [syncDirectoryPath retain]; syncContainerName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosSyncContainerName"]; - if (!syncContainerName || ![syncContainerName length]) { + if (!syncContainerName || ![syncContainerName length] || [syncContainerName isEqualToString:@"trash"]) { syncContainerName = [NSString stringWithString:@"pithos"]; } [syncContainerName retain]; @@ -135,6 +135,8 @@ [statusItem setMenu:statusMenu]; [statusItem setImage:sourceImage]; [statusItem setHighlightMode:YES]; + + self.alwaysNo = NO; } - (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent { @@ -235,8 +237,7 @@ } - (void)startSyncWithDirectoryPath:(NSString *)directoryPath containerName:(NSString *)containerName { - [pithosSyncDaemon release]; - pithosSyncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:syncDirectoryPath + self.pithosSyncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:syncDirectoryPath containerName:syncContainerName timeInterval:syncTimeInterval]; }