Skip to content

Commit

Permalink
[expo-file-system] Fix lifetime of EXFileSystem
Browse files Browse the repository at this point in the history
  • Loading branch information
lukmccall committed Apr 14, 2020
1 parent b0018be commit 35e2394
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 186 deletions.
2 changes: 2 additions & 0 deletions ios/Pods/.project_cache/installation_cache.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

260 changes: 134 additions & 126 deletions ios/Pods/EXFileSystem.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/expo-file-system/ios/EXFileSystem/EXFileSystem.h
Expand Up @@ -6,6 +6,7 @@
#import <UMCore/UMEventEmitter.h>
#import <UMFileSystemInterface/UMFileSystemInterface.h>
#import <EXFileSystem/EXSessionResumableDownloadTaskDelegate.h>
#import <EXFileSystem/EXSessionTaskDispatcher.h>

@interface EXFileSystem : UMExportedModule <UMEventEmitter, UMModuleRegistryConsumer, UMFileSystemInterface, NSURLSessionDelegate>

Expand Down
73 changes: 13 additions & 60 deletions packages/expo-file-system/ios/EXFileSystem/EXFileSystem.m
Expand Up @@ -35,8 +35,7 @@ @interface EXFileSystem ()

@property (nonatomic, strong) NSURLSession *backgroundSession;
@property (nonatomic, strong) NSURLSession *foregroundSession;
@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, EXSessionTaskDelegate *> *tasks;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSURLSessionDownloadTask *> *resumableDownloads;
@property (nonatomic, strong) EXSessionTaskDispatcher *sessionTaskDispatcher;
@property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
@property (nonatomic, weak) id<UMEventEmitterService> eventEmitter;
@property (nonatomic, strong) NSString *documentDirectory;
Expand Down Expand Up @@ -66,8 +65,7 @@ - (instancetype)initWithDocumentDirectory:(NSString *)documentDirectory cachesDi
_cachesDirectory = cachesDirectory;
_bundleDirectory = bundleDirectory;

_tasks = [NSMutableDictionary dictionary];
_resumableDownloads = [NSMutableDictionary dictionary];
_sessionTaskDispatcher = [EXSessionTaskDispatcher new];
_backgroundSession = [self _createSession:EXFileSystemBackgroundSession];
_foregroundSession = [self _createSession:EXFileSystemForegroundSession];

Expand Down Expand Up @@ -121,6 +119,7 @@ - (void)stopObserving {

- (void)dealloc
{
[_sessionTaskDispatcher deactivate];
[_backgroundSession invalidateAndCancel];
[_foregroundSession invalidateAndCancel];
}
Expand Down Expand Up @@ -555,10 +554,10 @@ - (NSDictionary *)encodingMap
EXFileSystemSessionType type = [self _importSessionType:options[@"sessionType"]];
NSURLSessionDownloadTask *task = [[self _sessionForType:type] downloadTaskWithRequest:request];
EXSessionTaskDelegate *taskDelegate = [[EXSessionDownloadTaskDelegate alloc] initWithResolve:resolve
reject:reject
localUrl:localUri
shouldCalculateMd5:[options[@"md5"] boolValue]];
_tasks[task] = taskDelegate;
reject:reject
localUrl:localUri
shouldCalculateMd5:[options[@"md5"] boolValue]];
[_sessionTaskDispatcher registerTaskDelegate:taskDelegate forTask:task];
[task resume];
}

Expand Down Expand Up @@ -607,7 +606,7 @@ - (NSDictionary *)encodingMap
EXFileSystemSessionType type = [self _importSessionType:options[@"sessionType"]];
NSURLSessionUploadTask *task = [[self _sessionForType:type] uploadTaskWithRequest:request fromFile:fileUri];
EXSessionTaskDelegate *taskDelegate = [[EXSessionUploadTaskDelegate alloc] initWithResolve:resolve reject:reject];
_tasks[task] = taskDelegate;
[_sessionTaskDispatcher registerTaskDelegate:taskDelegate forTask:task];
[task resume];
}

Expand Down Expand Up @@ -665,7 +664,7 @@ - (NSDictionary *)encodingMap
resolver:(UMPromiseResolveBlock)resolve
rejecter:(UMPromiseRejectBlock)reject)
{
NSURLSessionDownloadTask *task = _resumableDownloads[uuid];
NSURLSessionDownloadTask *task = [_sessionTaskDispatcher resumableDownload:uuid];
if (!task) {
reject(@"ERR_UNABLE_TO_PAUSE",
[NSString stringWithFormat:@"There is no download object with UUID: %@", uuid],
Expand All @@ -677,8 +676,7 @@ - (NSDictionary *)encodingMap
[task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
UM_ENSURE_STRONGIFY(self);
resolve(@{ @"resumeData": UMNullIfNil([resumeData base64EncodedStringWithOptions:0]) });
[self.tasks removeObjectForKey:task];
[self.resumableDownloads removeObjectForKey:uuid];
[self.sessionTaskDispatcher removeResumableDownload:uuid];
}];
}

Expand Down Expand Up @@ -752,7 +750,7 @@ - (NSURLSession *)_createSession:(EXFileSystemSessionType)type
sessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
sessionConfiguration.URLCache = nil;
return [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegate:_sessionTaskDispatcher
delegateQueue:nil];
}

Expand Down Expand Up @@ -810,8 +808,8 @@ - (void)_downloadResumableCreateSessionWithUrl:(NSURL *)url
shouldCalculateMd5:[options[@"md5"] boolValue]
onWriteCallback:onWrite
uuid:uuid];
_tasks[downloadTask] = taskDelegate;
_resumableDownloads[uuid] = downloadTask;
[_sessionTaskDispatcher registerTaskDelegate:taskDelegate forTask:downloadTask];
[_sessionTaskDispatcher registerResumableDownloadTask:downloadTask uuid:uuid];
[downloadTask resume];
}

Expand Down Expand Up @@ -909,49 +907,4 @@ - (NSNumber *)freeDiskStorage {
return nil;
}

#pragma mark - NSURLSessionDelegate

- (void)_unregisterIfResumableTaskDelegate:(EXSessionTaskDelegate *)taskDelegate
{
if ([taskDelegate isKindOfClass:[EXSessionResumableDownloadTaskDelegate class]]) {
EXSessionResumableDownloadTaskDelegate *exResumableTask = (EXSessionResumableDownloadTaskDelegate *)taskDelegate;
[_resumableDownloads removeObjectForKey:exResumableTask.uuid];
}
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
if (exTask) {
[exTask URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
[_tasks removeObjectForKey:downloadTask];
[self _unregisterIfResumableTaskDelegate:exTask];
}
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
EXSessionTaskDelegate *exTask = _tasks[task];
if (exTask) {
[exTask URLSession:session task:task didCompleteWithError:error];
[_tasks removeObjectForKey:task];
[self _unregisterIfResumableTaskDelegate:exTask];
}
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
[exTask URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
EXSessionTaskDelegate *exTask = _tasks[dataTask];
[exTask URLSession:session dataTask:dataTask didReceiveData:data];
}

@end
@@ -0,0 +1,22 @@
// Copyright 2015-present 650 Industries. All rights reserved.

#import <Foundation/Foundation.h>
#import <EXFileSystem/EXSessionTaskDelegate.h>

NS_ASSUME_NONNULL_BEGIN

@interface EXSessionTaskDispatcher : NSObject <NSURLSessionDelegate>

- (void)registerTaskDelegate:(EXSessionTaskDelegate *)delegate forTask:(NSURLSessionTask *)task;

- (void)registerResumableDownloadTask:(NSURLSessionDownloadTask *)task uuid:(NSString *)uuid;

- (NSURLSessionDownloadTask * _Nullable)resumableDownload:(NSString *)uuid;

- (void)removeResumableDownload:(NSString *)uuid;

- (void)deactivate;

@end

NS_ASSUME_NONNULL_END
@@ -0,0 +1,114 @@
// Copyright 2015-present 650 Industries. All rights reserved.

#import <EXFileSystem/EXSessionTaskDispatcher.h>
#import <EXFileSystem/EXSessionResumableDownloadTaskDelegate.h>

@interface EXSessionTaskDispatcher ()

@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, EXSessionTaskDelegate *> *tasks;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSURLSessionDownloadTask *> *resumableDownloads;
@property (nonatomic) BOOL isActive;

@end

@implementation EXSessionTaskDispatcher

- (instancetype)init
{
if (self = [super init]) {
_tasks = [NSMutableDictionary dictionary];
_resumableDownloads = [NSMutableDictionary dictionary];
_isActive = true;
}
return self;
}

#pragma mark - public methods

- (void)registerTaskDelegate:(EXSessionTaskDelegate *)delegate forTask:(NSURLSessionTask *)task
{
_tasks[task] = delegate;
}

- (void)registerResumableDownloadTask:(NSURLSessionDownloadTask *)task uuid:(NSString *)uuid
{
_resumableDownloads[uuid] = task;
}

- (NSURLSessionDownloadTask * _Nullable)resumableDownload:(NSString *)uuid
{
return _resumableDownloads[uuid];
}

- (void)removeResumableDownload:(NSString *)uuid
{
NSURLSessionTask *task = _resumableDownloads[uuid];
if (!task) {
return;
}

[_resumableDownloads removeObjectForKey:uuid];
[_tasks removeObjectForKey:task];
}

- (void)deactivate
{
_isActive = false;
}

#pragma mark - helpers

- (void)_unregisterIfResumableTaskDelegate:(EXSessionTaskDelegate *)taskDelegate
{
if ([taskDelegate isKindOfClass:[EXSessionResumableDownloadTaskDelegate class]]) {
EXSessionResumableDownloadTaskDelegate *exResumableTask = (EXSessionResumableDownloadTaskDelegate *)taskDelegate;
[_resumableDownloads removeObjectForKey:exResumableTask.uuid];
}
}

#pragma mark - dispatcher

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
if (_isActive) {
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
if (exTask) {
[exTask URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
[_tasks removeObjectForKey:downloadTask];
[self _unregisterIfResumableTaskDelegate:exTask];
}
}
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (_isActive) {
EXSessionTaskDelegate *exTask = _tasks[task];
if (exTask) {
[exTask URLSession:session task:task didCompleteWithError:error];
[_tasks removeObjectForKey:task];
[self _unregisterIfResumableTaskDelegate:exTask];
}
}
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
if (_isActive) {
EXSessionTaskDelegate *exTask = _tasks[downloadTask];
[exTask URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
}
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
if (_isActive) {
EXSessionTaskDelegate *exTask = _tasks[dataTask];
[exTask URLSession:session dataTask:dataTask didReceiveData:data];
}
}

@end

0 comments on commit 35e2394

Please sign in to comment.