// // PithosActivityFacility.m // pithos-macos // // Copyright 2011-2012 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 "PithosActivityFacility.h" #import "PithosAccount.h" #import "pithos_macosAppDelegate.h" static PithosActivityFacility *defaultPithosActivityFacility = nil; @implementation PithosActivityFacility @synthesize delegate; #pragma mark - #pragma mark - Singleton + (id)defaultPithosActivityFacility { @synchronized(self) { if (!defaultPithosActivityFacility) [[self alloc] init]; // Assignment not done here } return defaultPithosActivityFacility; } + (id)allocWithZone:(NSZone *)zone { @synchronized(self) { if (!defaultPithosActivityFacility) { defaultPithosActivityFacility = [super allocWithZone:zone]; return defaultPithosActivityFacility; } } return nil; } - (id)copyWithZone:(NSZone *)zone { return self; } - (id)retain { return self; } - (NSUInteger)retainCount { return UINT_MAX; // Can not be released } - (void)release { // Do nothing } - (id)autorelease { return self; } #pragma mark - #pragma mark Object Lifecycle - (id)init { if ((self = [super init])) { [self reset]; } return self; } - (void)dealloc { [timer invalidate]; [timer release]; [runningActivities release]; [endingActivities release]; [super dealloc]; } - (void)reset { @synchronized(self) { [timer invalidate]; [timer release]; [runningActivities release]; runningActivities = [[NSMutableArray alloc] init]; [endingActivities release]; endingActivities = [[NSMutableArray alloc] init]; totalUploadBytes = 0; currentUploadBytes = 0; totalDownloadBytes = 0; currentDownloadBytes = 0; pickedRunning = NO; timer = [[NSTimer scheduledTimerWithTimeInterval:[(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] activityFacilityTimeInterval] target:self selector:@selector(update:) userInfo:nil repeats:YES] retain]; } } - (NSString *)description { return [NSString stringWithFormat:@"running activities: %lu, ending activities: %lu, totalUploadBytes: %lu, currentUploadBytes: %lu, totalDownloadBytes: %lu, currentDownloadBytes: %lu", [runningActivities count], [endingActivities count], totalUploadBytes, currentUploadBytes, totalDownloadBytes, currentDownloadBytes]; } #pragma mark - #pragma mark Timer - (void)update:(NSTimer *)aTimer { NSMutableDictionary *info = [NSMutableDictionary dictionary]; @synchronized(self) { PithosActivity *activity = nil; NSUInteger endingActivitiesCount = [endingActivities count]; NSUInteger runningActivitiesCount = [runningActivities count]; if ((pickedRunning || !runningActivitiesCount) && endingActivitiesCount) { NSUInteger index; for (index = 0 ; index < endingActivitiesCount; index++) { activity = [endingActivities objectAtIndex:index]; switch (activity.type) { case PithosActivityUpload: totalUploadBytes -= activity.totalBytes; currentUploadBytes -= activity.currentBytes; break; case PithosActivityDownload: totalDownloadBytes -= activity.totalBytes; currentDownloadBytes -= activity.currentBytes; break; default: break; } if (activity.message) break; } [activity retain]; [endingActivities removeObjectsInRange:NSMakeRange(0, (index + 1))]; pickedRunning = NO; } else if (runningActivitiesCount) { NSUInteger count; for (count = 0 ; count < runningActivitiesCount; count++) { activity = [[runningActivities objectAtIndex:0] retain]; [runningActivities removeObjectAtIndex:0]; [runningActivities addObject:activity]; if (activity.message) { break; } else { [activity release]; activity = nil; } } pickedRunning = YES; } if (activity && activity.message) { if (activity.pithosAccount) [info setObject:[NSString stringWithFormat:@"[%@] %@", activity.pithosAccount.name, activity.message] forKey:@"message"]; else [info setObject:activity.message forKey:@"message"]; } [info setObject:[NSNumber numberWithUnsignedInteger:[runningActivities count]] forKey:@"runningActivitiesCount"]; [info setObject:[NSNumber numberWithUnsignedInteger:[endingActivities count]] forKey:@"endingActivitiesCount"]; [info setObject:[NSNumber numberWithUnsignedInteger:totalUploadBytes] forKey:@"totalUploadBytes"]; [info setObject:[NSNumber numberWithUnsignedInteger:currentUploadBytes] forKey:@"currentUploadBytes"]; [info setObject:[NSNumber numberWithUnsignedInteger:totalDownloadBytes] forKey:@"totalDownloadBytes"]; [info setObject:[NSNumber numberWithUnsignedInteger:currentDownloadBytes] forKey:@"currentDownloadBytes"]; [activity release]; } if (delegate) { [delegate activityUpdate:info]; } } #pragma mark - #pragma mark Activity Actions - (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes pithosAccount:(PithosAccount *)pithosAccount { PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease]; activity.message = message; activity.totalBytes = totalBytes; activity.currentBytes = currentBytes; NSLog(@"PithosActivityFacility startedActivity %@", activity); switch (type) { case PithosActivityUpload: @synchronized(self) { totalUploadBytes += totalBytes; currentUploadBytes += currentBytes; } break; case PithosActivityDownload: @synchronized(self) { totalDownloadBytes += totalBytes; currentDownloadBytes += currentBytes; } break; default: break; } @synchronized(self) { [runningActivities addObject:activity]; } NSLog(@"PithosActivityFacility %@", self); return activity; } - (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes { return [self startActivityWithType:type message:message totalBytes:totalBytes currentBytes:currentBytes pithosAccount:nil]; } - (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message pithosAccount:(PithosAccount *)pithosAccount { return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0 pithosAccount:pithosAccount]; } - (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message { return [self startActivityWithType:type message:message pithosAccount:nil]; } - (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message pithosAccount:(PithosAccount *)pithosAccount { PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease]; activity.message = message; activity.totalBytes = 0; activity.currentBytes = 0; @synchronized(self) { [endingActivities addObject:activity]; } NSLog(@"PithosActivityFacility startedAndEndedActivity %@", activity); return activity; } - (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message { return [self startAndEndActivityWithType:type message:message pithosAccount:nil]; } - (void)updateActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes { if (!activity) return; NSLog(@"PithosActivityFacility updatedActivity %@", activity); @synchronized(self) { activity.message = message; switch (activity.type) { case PithosActivityUpload: totalUploadBytes += totalBytes - activity.totalBytes; activity.totalBytes = totalBytes; currentUploadBytes += currentBytes - activity.currentBytes; activity.currentBytes = currentBytes; break; case PithosActivityDownload: totalDownloadBytes += totalBytes - activity.totalBytes; activity.totalBytes = totalBytes; currentDownloadBytes += currentBytes - activity.currentBytes; activity.currentBytes = currentBytes; break; default: break; } } NSLog(@"PithosActivityFacility %@", self); } - (void)updateActivity:(PithosActivity *)activity withMessage:(NSString *)message { [self updateActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes]; } - (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message totalBytes:(NSUInteger)totalBytes currentBytes:(NSUInteger)currentBytes { if (!activity) return; @synchronized(self) { [runningActivities removeObject:activity]; activity.message = message; switch (activity.type) { case PithosActivityUpload: totalUploadBytes += totalBytes - activity.totalBytes; activity.totalBytes = totalBytes; currentUploadBytes += currentBytes - activity.currentBytes; activity.currentBytes = currentBytes; break; case PithosActivityDownload: totalDownloadBytes += totalBytes - activity.totalBytes; activity.totalBytes = totalBytes; currentDownloadBytes += currentBytes - activity.currentBytes; activity.currentBytes = currentBytes; break; default: break; } [endingActivities addObject:activity]; } NSLog(@"PithosActivityFacility endedActivity %@", activity); NSLog(@"PithosActivityFacility %@", self); } - (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message { [self endActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes]; } @end