FIRStorageDownloadTask.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 "FIRStorageDownloadTask.h"
  15. #import "FIRStorageConstants_Private.h"
  16. #import "FIRStorageDownloadTask_Private.h"
  17. #import "FIRStorageObservableTask_Private.h"
  18. #import "FIRStorageTask_Private.h"
  19. @implementation FIRStorageDownloadTask
  20. @synthesize progress = _progress;
  21. @synthesize fetcher = _fetcher;
  22. @synthesize fetcherCompletion = _fetcherCompletion;
  23. - (instancetype)initWithReference:(FIRStorageReference *)reference
  24. fetcherService:(GTMSessionFetcherService *)service
  25. file:(nullable NSURL *)fileURL {
  26. self = [super initWithReference:reference fetcherService:service];
  27. if (self) {
  28. _fileURL = [fileURL copy];
  29. _progress = [NSProgress progressWithTotalUnitCount:0];
  30. }
  31. return self;
  32. }
  33. - (void) dealloc {
  34. [_fetcher stopFetching];
  35. }
  36. - (void)enqueue {
  37. [self enqueueWithData:nil];
  38. }
  39. - (void)enqueueWithData:(nullable NSData *)resumeData {
  40. NSAssert([NSThread isMainThread], @"Download attempting to execute on non main queue! Please "
  41. @"only execute this method on the main queue.");
  42. self.state = FIRStorageTaskStateQueueing;
  43. NSMutableURLRequest *request = [self.baseRequest mutableCopy];
  44. request.HTTPMethod = @"GET";
  45. request.timeoutInterval = self.reference.storage.maxDownloadRetryTime;
  46. NSURLComponents *components =
  47. [NSURLComponents componentsWithURL:request.URL resolvingAgainstBaseURL:NO];
  48. [components setQuery:@"alt=media"];
  49. request.URL = components.URL;
  50. GTMSessionFetcher *fetcher;
  51. if (resumeData) {
  52. fetcher = [GTMSessionFetcher fetcherWithDownloadResumeData:resumeData];
  53. fetcher.comment = @"Resuming DownloadTask";
  54. } else {
  55. fetcher = [self.fetcherService fetcherWithRequest:request];
  56. fetcher.comment = @"Starting DownloadTask";
  57. }
  58. __weak FIRStorageDownloadTask *weakSelf = self;
  59. [fetcher setResumeDataBlock:^(NSData *data) {
  60. if (data) {
  61. FIRStorageDownloadTask *strongSelf = weakSelf;
  62. strongSelf->_downloadData = data;
  63. }
  64. }];
  65. fetcher.maxRetryInterval = self.reference.storage.maxDownloadRetryTime;
  66. if (_fileURL) {
  67. // Handle file downloads
  68. [fetcher setDestinationFileURL:_fileURL];
  69. [fetcher setDownloadProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten,
  70. int64_t totalBytesExpectedToWrite) {
  71. weakSelf.state = FIRStorageTaskStateProgress;
  72. weakSelf.progress.completedUnitCount = totalBytesWritten;
  73. weakSelf.progress.totalUnitCount = totalBytesExpectedToWrite;
  74. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  75. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  76. weakSelf.state = FIRStorageTaskStateRunning;
  77. }];
  78. } else {
  79. // Handle data downloads
  80. [fetcher setReceivedProgressBlock:^(int64_t bytesWritten, int64_t totalBytesWritten) {
  81. weakSelf.state = FIRStorageTaskStateProgress;
  82. weakSelf.progress.completedUnitCount = totalBytesWritten;
  83. int64_t totalLength = [[weakSelf.fetcher response] expectedContentLength];
  84. weakSelf.progress.totalUnitCount = totalLength;
  85. FIRStorageTaskSnapshot *snapshot = weakSelf.snapshot;
  86. [weakSelf fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:snapshot];
  87. weakSelf.state = FIRStorageTaskStateRunning;
  88. }];
  89. }
  90. _fetcher = fetcher;
  91. #pragma clang diagnostic push
  92. #pragma clang diagnostic ignored "-Warc-retain-cycles"
  93. _fetcherCompletion = ^(NSData *data, NSError *error) {
  94. // Fire last progress updates
  95. [self fireHandlersForStatus:FIRStorageTaskStatusProgress snapshot:self.snapshot];
  96. // Handle potential issues with download
  97. if (error) {
  98. self.state = FIRStorageTaskStateFailed;
  99. self.error = [FIRStorageErrors errorWithServerError:error reference:self.reference];
  100. [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
  101. [self removeAllObservers];
  102. _fetcherCompletion = nil;
  103. return;
  104. }
  105. // Download completed successfully, fire completion callbacks
  106. self.state = FIRStorageTaskStateSuccess;
  107. if (data) {
  108. _downloadData = data;
  109. }
  110. [self fireHandlersForStatus:FIRStorageTaskStatusSuccess snapshot:self.snapshot];
  111. [self removeAllObservers];
  112. _fetcherCompletion = nil;
  113. };
  114. #pragma clang diagnostic pop
  115. self.state = FIRStorageTaskStateRunning;
  116. [self.fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
  117. weakSelf.fetcherCompletion(data, error);
  118. }];
  119. }
  120. #pragma mark - Download Management
  121. - (void)cancel {
  122. NSError *error = [FIRStorageErrors errorWithCode:FIRStorageErrorCodeCancelled];
  123. [self cancelWithError:error];
  124. }
  125. - (void)cancelWithError:(NSError *)error {
  126. NSAssert([NSThread isMainThread], @"Cancel attempting to execute on non main queue! Please only "
  127. @"execute this method on the main queue.");
  128. self.state = FIRStorageTaskStateCancelled;
  129. [self.fetcher stopFetching];
  130. self.error = error;
  131. [self fireHandlersForStatus:FIRStorageTaskStatusFailure snapshot:self.snapshot];
  132. }
  133. - (void)pause {
  134. NSAssert([NSThread isMainThread], @"Pause attempting to execute on non main queue! Please only "
  135. @"execute this method on the main queue.");
  136. self.state = FIRStorageTaskStatePausing;
  137. [self.fetcher stopFetching];
  138. // Give the resume callback a chance to run (if scheduled)
  139. [self.fetcher waitForCompletionWithTimeout:0.001];
  140. self.state = FIRStorageTaskStatePaused;
  141. FIRStorageTaskSnapshot *snapshot = self.snapshot;
  142. [self fireHandlersForStatus:FIRStorageTaskStatusPause snapshot:snapshot];
  143. }
  144. - (void)resume {
  145. NSAssert([NSThread isMainThread], @"Resume attempting to execute on non main queue! Please only "
  146. @"execute this method on the main queue.");
  147. self.state = FIRStorageTaskStateResuming;
  148. FIRStorageTaskSnapshot *snapshot = self.snapshot;
  149. [self fireHandlersForStatus:FIRStorageTaskStatusResume snapshot:snapshot];
  150. self.state = FIRStorageTaskStateRunning;
  151. [self enqueueWithData:_downloadData];
  152. }
  153. @end