aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Storage/FIRStorageObservableTask.m
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
committerGravatar Paul Beusterien <paulbeusterien@google.com>2017-05-15 12:27:07 -0700
commit98ba64449a632518bd2b86fe8d927f4a960d3ddc (patch)
tree131d9c4272fa6179fcda6c5a33fcb3b1bd57ad2e /Firebase/Storage/FIRStorageObservableTask.m
parent32461366c9e204a527ca05e6e9b9404a2454ac51 (diff)
Initial
Diffstat (limited to 'Firebase/Storage/FIRStorageObservableTask.m')
-rw-r--r--Firebase/Storage/FIRStorageObservableTask.m216
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