FIRStorageDownloadTask.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright 2017 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FirebaseStorage/Sources/Public/FirebaseStorage/FIRStorageDownloadTask.h"
  15. #import "FirebaseStorage/Sources/FIRStorageConstants_Private.h"
  16. #import "FirebaseStorage/Sources/FIRStorageDownloadTask_Private.h"
  17. #import "FirebaseStorage/Sources/FIRStorageObservableTask_Private.h"
  18. #import "FirebaseStorage/Sources/FIRStorageTask_Private.h"
  19. #import "FirebaseStorage/Sources/FIRStorage_Private.h"
  20. @implementation FIRStorageDownloadTask
  21. @synthesize progress = _progress;
  22. @synthesize fetcher = _fetcher;
  23. @synthesize fetcherCompletion = _fetcherCompletion;
  24. - (instancetype)initWithReference:(FIRStorageReference *)reference
  25. fetcherService:(GTMSessionFetcherService *)service
  26. dispatchQueue:(dispatch_queue_t)queue
  27. file:(nullable NSURL *)fileURL {
  28. self = [super initWithReference:reference fetcherService:service dispatchQueue:queue];
  29. if (self) {
  30. _fileURL = [fileURL copy];
  31. _progress = [NSProgress progressWithTotalUnitCount:0];
  32. }
  33. return self;
  34. }
  35. - (void)dealloc {
  36. [_fetcher stopFetching];
  37. }
  38. - (void)enqueue {
  39. [self enqueueWithData:nil];
  40. }
  41. - (void)enqueueWithData:(nullable NSData *)resumeData {
  42. __weak FIRStorageDownloadTask *weakSelf = self;
  43. [self dispatchAsync:^() {
  44. FIRStorageDownloadTask *strongSelf = weakSelf;
  45. if (!strongSelf) {
  46. return;
  47. }
  48. strongSelf.state = FIRStorageTaskStateQueueing;
  49. NSMutableURLRequest *request = [strongSelf.baseRequest mutableCopy];
  50. request.HTTPMethod = @"GET";
  51. request.timeoutInterval = strongSelf.reference.storage.maxDownloadRetryTime;
  52. NSURLComponents *components = [NSURLComponents componentsWithURL:request.URL
  53. resolvingAgainstBaseURL:NO];
  54. [components setQuery:@"alt=media"];
  55. request.URL = components.URL;
  56. GTMSessionFetcher *fetcher;
  57. if (resumeData) {
  58. fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData];
  59. fetcher.comment = @"Resuming DownloadTask";
  60. } else {
  61. fetcher = [strongSelf.fetcherService fetcherWithRequest:request];
  62. fetcher.comment = @"Starting DownloadTask";
  63. }
  64. [fetcher setResumeDataBlock:^(NSData *data) {
  65. FIRStorageDownloadTask *strong = weakSelf;
  66. if (strong && data) {
  67. strong->_downloadData = data;
  68. }
  69. }];
  70. fetcher.maxRetryInterval = strongSelf.reference.storage.maxDownloadRetryInterval;
  71. if (strongSelf->_fileURL) {
  72. // Handle file downloads
  73. [fetcher setDestinationFileURL:strongSelf->_fileURL];
  74. [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten,
  75. int64_t totalBytesExpectedToWrite) {
  76. weakSelf.state = FIRStorageTaskStateProgress;
  77. weakSelf.progress.completedUnitCount = totalBytesWritten;
  78. weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite;
  79. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  80. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  81. weakSelf.state = FIRStorageTaskStateRunning;
  82. }];
  83. } else {
  84. // Handle data downloads
  85. [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) {
  86. weakSelf.state = FIRStorageTaskStateProgress;
  87. weakSelf.progress.completedUnitCount = totalBytesWritten;
  88. int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength];
  89. weakSelf.progress.totalUnitCount = totalLength;
  90. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  91. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  92. weakSelf.state = FIRStorageTaskStateRunning;
  93. }];
  94. }
  95. strongSelf->_fetcher = fetcher;
  96. strongSelf->_fetcherCompletion = ^(NSData *data, NSError *error) {
  97. // Fire last progress updates
  98. [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot];
  99. // Handle potential issues with download
  100. if (error) {
  101. self.state = FIRStorageTaskStateFailed;
  102. self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
  103. [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
  104. [self removeAllObservers];
  105. self->_fetcherCompletion = nil;
  106. return;
  107. }
  108. // Download completed successfully, fire completion callbacks
  109. self.state = FIRStorageTaskStateSuccess;
  110. if (data) {
  111. self->_downloadData = data;
  112. }
  113. [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot];
  114. [self removeAllObservers];
  115. self->_fetcherCompletion = nil;
  116. };
  117. strongSelf.state = FIRStorageTaskStateRunning;
  118. [strongSelf.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
  119. FIRStorageDownloadTask *strongSelf = weakSelf;
  120. if (strongSelf.fetcherCompletion) {
  121. strongSelf.fetcherCompletion(data, error);
  122. }
  123. }];
  124. }];
  125. }
  126. #pragma mark - Download Management
  127. - (void)cancel {
  128. NSError *error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled];
  129. [self cancelWithError:error];
  130. }
  131. - (void)cancelWithError:(NSError *)error {
  132. __weak FIRStorageDownloadTask *weakSelf = self;
  133. [self dispatchAsync:^() {
  134. weakSelf.state = FIRStorageTaskStateCancelled;
  135. [weakSelf.fetcher stopFetching];
  136. weakSelf.error = error;
  137. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:weakSelf.snapshot];
  138. }];
  139. }
  140. - (void)pause {
  141. __weak FIRStorageDownloadTask *weakSelf = self;
  142. [self dispatchAsync:^() {
  143. __strong FIRStorageDownloadTask *strongSelf = weakSelf;
  144. if (!strongSelf || strongSelf.state == FIRStorageTaskStatePaused ||
  145. strongSelf.state == FIRStorageTaskStatePausing) {
  146. return;
  147. }
  148. strongSelf.state = FIRStorageTaskStatePausing;
  149. // Use the resume callback to confirm pause status since it always runs after the last
  150. // NSURLSession update.
  151. [strongSelf.fetcher setResumeDataBlock:^(NSData *data) {
  152. // Silence compiler warning about retain cycles
  153. __strong __typeof(self) strong = weakSelf;
  154. strong->_downloadData = data;
  155. strong.state = FIRStorageTaskStatePaused;
  156. FIRStorageTaskSnapshot *snapshot = strong.snapshot;
  157. [strong fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot];
  158. }];
  159. [strongSelf.fetcher stopFetching];
  160. }];
  161. }
  162. - (void)resume {
  163. __weak FIRStorageDownloadTask *weakSelf = self;
  164. [self dispatchAsync:^() {
  165. weakSelf.state = FIRStorageTaskStateResuming;
  166. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  167. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot];
  168. weakSelf.state = FIRStorageTaskStateRunning;
  169. [weakSelf enqueueWithData:weakSelf.downloadData];
  170. }];
  171. }
  172. @end