1// Copyright 2015-present 650 Industries. All rights reserved.
2
3#if __has_include(<EXFileSystem/EXFileSystem.h>)
4#import "EXScopedFileSystemModule.h"
5
6// TODO @sjchmiela: Should this be versioned? It is only used in detached scenario.
7NSString * const EXShellManifestResourceName = @"shell-app-manifest";
8
9@implementation EXScopedFileSystemModule
10
11- (instancetype)initWithExperienceId:(NSString *)experienceId andConstantsBinding:(EXConstantsBinding *)constantsBinding
12{
13  NSString *escapedExperienceId = [EXScopedFileSystemModule escapedResourceName:experienceId];
14
15  NSString *mainDocumentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
16  NSString *exponentDocumentDirectory = [mainDocumentDirectory stringByAppendingPathComponent:@"ExponentExperienceData"];
17  NSString *experienceDocumentDirectory = [[exponentDocumentDirectory stringByAppendingPathComponent:escapedExperienceId] stringByStandardizingPath];
18
19  NSString *mainCachesDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
20  NSString *exponentCachesDirectory = [mainCachesDirectory stringByAppendingPathComponent:@"ExponentExperienceData"];
21  NSString *experienceCachesDirectory = [[exponentCachesDirectory stringByAppendingPathComponent:escapedExperienceId] stringByStandardizingPath];
22
23  if (![@"expo" isEqualToString:constantsBinding.appOwnership]) {
24    return [super init];
25  }
26
27  return [super initWithDocumentDirectory:experienceDocumentDirectory
28                          cachesDirectory:experienceCachesDirectory
29                          bundleDirectory:nil];
30}
31
32- (NSDictionary *)constantsToExport
33{
34  NSMutableDictionary *constants = [[NSMutableDictionary alloc] initWithDictionary:[super constantsToExport]];
35  constants[@"bundledAssets"] = [self bundledAssets] ?: [NSNull null];
36  return constants;
37}
38
39+ (NSString *)escapedResourceName:(NSString *)name
40{
41  NSString *charactersToEscape = @"!*'();:@&=+$,/?%#[]";
42  NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
43  return [name stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
44}
45
46- (NSArray<NSString *> *)bundledAssets
47{
48  static NSArray<NSString *> *bundledAssets = nil;
49  static dispatch_once_t once;
50  dispatch_once(&once, ^{
51    NSString *manifestBundlePath = [[NSBundle mainBundle] pathForResource:EXShellManifestResourceName ofType:@"json"];
52    NSData *data = [NSData dataWithContentsOfFile:manifestBundlePath];
53    if (data.length == 0) {
54      return;
55    }
56    __block NSError *error;
57    id manifest = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
58    if (error) {
59      UMLogError(@"Error parsing bundled manifest: %@", error);
60      return;
61    }
62    bundledAssets = manifest[@"bundledAssets"];
63  });
64  return bundledAssets;
65}
66
67@end
68#endif
69