1// Copyright 2015-present 650 Industries. All rights reserved.
2
3#import "EXApiUtil.h"
4#import "EXAppFetcher+Private.h"
5#import "EXAppLoader.h"
6#import "EXEnvironment.h"
7#import "EXErrorRecoveryManager.h"
8#import "EXJavaScriptResource.h"
9#import "EXKernel.h"
10#import "EXVersions.h"
11
12#import <React/RCTUtils.h>
13
14NS_ASSUME_NONNULL_BEGIN
15
16@implementation EXAppFetcher
17
18- (instancetype)initWithAppLoader:(EXAppLoader *)appLoader
19{
20  if (self = [super init]) {
21    _appLoader = appLoader;
22  }
23  return self;
24}
25
26- (void)start
27{
28  // overridden by subclasses
29  @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Should not call EXAppFetcher#start -- use a subclass instead" userInfo:nil];
30}
31
32- (void)fetchJSBundleWithManifest:(EXUpdatesRawManifest *)manifest
33                    cacheBehavior:(EXCachedResourceBehavior)cacheBehavior
34                  timeoutInterval:(NSTimeInterval)timeoutInterval
35                         progress:(void (^ _Nullable )(EXLoadingProgress *))progressBlock
36                          success:(void (^)(NSData *))successBlock
37                            error:(void (^)(NSError *))errorBlock
38{
39  EXJavaScriptResource *jsResource = [[EXJavaScriptResource alloc] initWithBundleName:[self.dataSource bundleResourceNameForAppFetcher:self withManifest:manifest]
40                                                                            remoteUrl:[EXApiUtil bundleUrlFromManifest:manifest]
41                                                                      devToolsEnabled:manifest.isUsingDeveloperTool];
42  jsResource.abiVersion = [[EXVersions sharedInstance] availableSdkVersionForManifest:manifest];
43  jsResource.requestTimeoutInterval = timeoutInterval;
44
45  EXCachedResourceBehavior behavior = cacheBehavior;
46  // if we've disabled updates, ignore all other settings and only use the cache
47  if ([EXEnvironment sharedEnvironment].isDetached && ![EXEnvironment sharedEnvironment].areRemoteUpdatesEnabled) {
48    behavior = EXCachedResourceOnlyCache;
49  }
50
51  if ([self.dataSource appFetcherShouldInvalidateBundleCache:self]) {
52    [jsResource removeCache];
53  }
54
55  [jsResource loadResourceWithBehavior:cacheBehavior progressBlock:progressBlock successBlock:successBlock errorBlock:errorBlock];
56}
57
58+ (EXCachedResourceBehavior)cacheBehaviorForJSWithManifest:(EXUpdatesRawManifest * _Nonnull)manifest
59{
60  if ([[EXKernel sharedInstance].serviceRegistry.errorRecoveryManager scopeKeyIsRecoveringFromError:manifest.scopeKey]) {
61    // if this experience id encountered a loading error before, discard any cache we might have
62    return EXCachedResourceWriteToCache;
63  }
64  if (manifest.isUsingDeveloperTool) {
65    return EXCachedResourceNoCache;
66  }
67  return EXCachedResourceWriteToCache;
68}
69
70@end
71
72NS_ASSUME_NONNULL_END
73
74