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