diff options
author | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
---|---|---|
committer | Paul Beusterien <paulbeusterien@google.com> | 2017-05-15 12:27:07 -0700 |
commit | 98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch) | |
tree | 131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Firebase/Storage/FIRStorageObservableTask.m | |
parent | 32461366c9e204a527ca05e6e9b9404a2454ac51 (diff) |
Initial
Diffstat (limited to 'Firebase/Storage/FIRStorageObservableTask.m')
-rw-r--r-- | Firebase/Storage/FIRStorageObservableTask.m | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/Firebase/Storage/FIRStorageObservableTask.m b/Firebase/Storage/FIRStorageObservableTask.m new file mode 100644 index 0000000..bac5924 --- /dev/null +++ b/Firebase/Storage/FIRStorageObservableTask.m @@ -0,0 +1,216 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRStorageObservableTask.h" +#import "FIRStorageObservableTask_Private.h" +#import "FIRStorageTask_Private.h" + +@implementation FIRStorageObservableTask { + @private + // Handlers for pause, resume, progress, success, and failure callbacks + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_resumeHandlers; + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_pauseHandlers; + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_progressHandlers; + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_successHandlers; + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *_failureHandlers; + // Reverse map of fetcher handles to status types + NSMutableDictionary<NSString *, NSNumber *> *_handleToStatusMap; +} + +@synthesize state = _state; + +- (instancetype)initWithReference:(FIRStorageReference *)reference + fetcherService:(GTMSessionFetcherService *)service { + self = [super initWithReference:reference fetcherService:service]; + if (self) { + _pauseHandlers = [[NSMutableDictionary alloc] init]; + _resumeHandlers = [[NSMutableDictionary alloc] init]; + _progressHandlers = [[NSMutableDictionary alloc] init]; + _successHandlers = [[NSMutableDictionary alloc] init]; + _failureHandlers = [[NSMutableDictionary alloc] init]; + _handleToStatusMap = [[NSMutableDictionary alloc] init]; + } + return self; +} + +#pragma mark - Observers + +- (FIRStorageHandle)observeStatus:(FIRStorageTaskStatus)status + handler:(FIRStorageVoidSnapshot)handler { + FIRStorageVoidSnapshot callback = handler; + handler = nil; + + // Note: self.snapshot is synchronized + FIRStorageTaskSnapshot *snapshot = self.snapshot; + // TODO: use an increasing counter instead of a random UUID + NSString *UUIDString = [[NSUUID UUID] UUIDString]; + switch (status) { + case FIRStorageTaskStatusPause: + @synchronized(self) { + [_pauseHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStatePausing || _state == FIRStorageTaskStatePaused) { + [self fireHandlers:_pauseHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusResume: + @synchronized(self) { + [_resumeHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateResuming || _state == FIRStorageTaskStateRunning) { + [self fireHandlers:_resumeHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusProgress: + @synchronized(self) { + [_progressHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateRunning || _state == FIRStorageTaskStateProgress) { + [self fireHandlers:_progressHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusSuccess: + @synchronized(self) { + [_successHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateSuccess) { + [self fireHandlers:_successHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusFailure: + @synchronized(self) { + [_failureHandlers setValue:callback forKey:UUIDString]; + } // @synchronized(self) + if (_state == FIRStorageTaskStateFailing || _state == FIRStorageTaskStateFailed) { + [self fireHandlers:_failureHandlers snapshot:snapshot]; + } + break; + + case FIRStorageTaskStatusUnknown: + // Fall through to exception case if an unknown status is passed + + default: + [NSException raise:NSInternalInconsistencyException + format:kFIRStorageInvalidObserverStatus, nil]; + break; + } + + @synchronized(self) { + _handleToStatusMap[UUIDString] = @(status); + } // @synchronized(self) + + return UUIDString; +} + +- (void)removeObserverWithHandle:(FIRStorageHandle)handle { + FIRStorageTaskStatus status = [_handleToStatusMap[handle] intValue]; + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary = + [self handlerDictionaryForStatus:status]; + + @synchronized(self) { + [observerDictionary removeObjectForKey:handle]; + [_handleToStatusMap removeObjectForKey:handle]; + } // @synchronized(self) +} + +- (void)removeAllObserversForStatus:(FIRStorageTaskStatus)status { + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary = + [self handlerDictionaryForStatus:status]; + [self removeHandlersFromStatusMapForDictionary:observerDictionary]; + + @synchronized(self) { + [observerDictionary removeAllObjects]; + } // @synchronized(self) +} + +- (void)removeAllObservers { + @synchronized(self) { + [_pauseHandlers removeAllObjects]; + [_resumeHandlers removeAllObjects]; + [_progressHandlers removeAllObjects]; + [_successHandlers removeAllObjects]; + [_failureHandlers removeAllObjects]; + [_handleToStatusMap removeAllObjects]; + } // @synchronized(self) +} + +- (NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)handlerDictionaryForStatus: + (FIRStorageTaskStatus)status { + switch (status) { + case FIRStorageTaskStatusPause: + return _pauseHandlers; + + case FIRStorageTaskStatusResume: + return _resumeHandlers; + + case FIRStorageTaskStatusProgress: + return _progressHandlers; + + case FIRStorageTaskStatusSuccess: + return _successHandlers; + + case FIRStorageTaskStatusFailure: + return _failureHandlers; + + case FIRStorageTaskStatusUnknown: + return [NSMutableDictionary dictionary]; + + default: + [NSException raise:NSInternalInconsistencyException + format:kFIRStorageInvalidObserverStatus, nil]; + return nil; + } +} + +- (void)removeHandlersFromStatusMapForDictionary: + (NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)dict { + @synchronized(self) { + [_handleToStatusMap removeObjectsForKeys:dict.allKeys]; + } // @synchronized(self) +} + +- (void)fireHandlersForStatus:(FIRStorageTaskStatus)status + snapshot:(FIRStorageTaskSnapshot *)snapshot { + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *observerDictionary = + [self handlerDictionaryForStatus:status]; + [self fireHandlers:observerDictionary snapshot:snapshot]; +} + +- (void)fireHandlers:(NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *)handlers + snapshot:(FIRStorageTaskSnapshot *)snapshot { + dispatch_queue_t callbackQueue = self.fetcherService.callbackQueue; + if (!callbackQueue) { + callbackQueue = dispatch_get_main_queue(); + } + + // TODO: iterate over this list in a consistent order + NSMutableDictionary<NSString *, FIRStorageVoidSnapshot> *handlersCopy; + @synchronized(self) { + handlersCopy = [handlers copy]; + } // @synchronized(self) + [handlersCopy enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, + FIRStorageVoidSnapshot _Nonnull handler, + BOOL *_Nonnull stop) { + + dispatch_async(callbackQueue, ^{ + handler(snapshot); + }); + }]; +} + +@end |