// // 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 - Singleton + (id)defaultPithosActivityFacility { static dispatch_once_t pred = 0; __strong static id _sharedObject = nil; dispatch_once(&pred, ^{ _sharedObject = [[self alloc] init]; }); return _sharedObject; } //+ (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 - Object Lifecycle - (id)init { if ((self = [super init])) { [self reset]; } return self; } - (void)dealloc { [timer invalidate]; } - (void)reset { @synchronized(self) { [timer invalidate]; runningActivities = [[NSMutableArray alloc] init]; 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]; } } - (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; } [endingActivities removeObjectsInRange:NSMakeRange(0, (index + 1))]; pickedRunning = NO; } else if (runningActivitiesCount) { NSUInteger count; for (count = 0 ; count < runningActivitiesCount; count++) { activity = [runningActivities objectAtIndex:0]; [runningActivities removeObjectAtIndex:0]; [runningActivities addObject:activity]; if (activity.message) { break; } else { 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"]; } 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]; activity.message = message; activity.totalBytes = totalBytes; activity.currentBytes = currentBytes; DLog(@"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]; } DLog(@"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]; activity.message = message; activity.totalBytes = 0; activity.currentBytes = 0; @synchronized(self) { [endingActivities addObject:activity]; } DLog(@"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; DLog(@"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; } } DLog(@"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]; } DLog(@"PithosActivityFacility endedActivity %@", activity); DLog(@"PithosActivityFacility %@", self); } - (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message { [self endActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes]; } @end