@amazon-devices/expo-file-system 2.0.1758683737

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +317 -0
  3. package/CMakeLists.txt +52 -0
  4. package/LICENSE +7 -0
  5. package/README.kepler.md +260 -0
  6. package/README.md +46 -0
  7. package/THIRD_PARTY_NOTICES.txt +24 -0
  8. package/android/build.gradle +118 -0
  9. package/android/src/main/AndroidManifest.xml +17 -0
  10. package/android/src/main/java/expo/modules/filesystem/AppDirectoriesModule.kt +26 -0
  11. package/android/src/main/java/expo/modules/filesystem/CountingRequestBody.kt +52 -0
  12. package/android/src/main/java/expo/modules/filesystem/FilePermissionModule.kt +48 -0
  13. package/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt +48 -0
  14. package/android/src/main/java/expo/modules/filesystem/FileSystemFileProvider.kt +5 -0
  15. package/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt +1110 -0
  16. package/android/src/main/java/expo/modules/filesystem/FileSystemPackage.kt +10 -0
  17. package/android/src/main/java/expo/modules/filesystem/FileSystemRecords.kt +92 -0
  18. package/android/src/main/res/xml/file_system_provider_paths.xml +5 -0
  19. package/app.plugin.js +1 -0
  20. package/build/ExponentFileSystem.d.ts +4 -0
  21. package/build/ExponentFileSystem.d.ts.map +1 -0
  22. package/build/ExponentFileSystem.js +5 -0
  23. package/build/ExponentFileSystem.js.map +1 -0
  24. package/build/ExponentFileSystem.kepler.d.ts +4 -0
  25. package/build/ExponentFileSystem.kepler.d.ts.map +1 -0
  26. package/build/ExponentFileSystem.kepler.js +112 -0
  27. package/build/ExponentFileSystem.kepler.js.map +1 -0
  28. package/build/ExponentFileSystem.web.d.ts +3 -0
  29. package/build/ExponentFileSystem.web.d.ts.map +1 -0
  30. package/build/ExponentFileSystem.web.js +3 -0
  31. package/build/ExponentFileSystem.web.js.map +1 -0
  32. package/build/ExponentFileSystemShim.d.ts +4 -0
  33. package/build/ExponentFileSystemShim.d.ts.map +1 -0
  34. package/build/ExponentFileSystemShim.js +21 -0
  35. package/build/ExponentFileSystemShim.js.map +1 -0
  36. package/build/FileSystem.d.ts +361 -0
  37. package/build/FileSystem.d.ts.map +1 -0
  38. package/build/FileSystem.js +616 -0
  39. package/build/FileSystem.js.map +1 -0
  40. package/build/FileSystem.types.d.ts +304 -0
  41. package/build/FileSystem.types.d.ts.map +1 -0
  42. package/build/FileSystem.types.js +47 -0
  43. package/build/FileSystem.types.js.map +1 -0
  44. package/build/index.d.ts +3 -0
  45. package/build/index.d.ts.map +1 -0
  46. package/build/index.js +3 -0
  47. package/build/index.js.map +1 -0
  48. package/build/types.d.ts +35 -0
  49. package/build/types.d.ts.map +1 -0
  50. package/build/types.js +2 -0
  51. package/build/types.js.map +1 -0
  52. package/expo-module.config.json +11 -0
  53. package/ios/EXFilePermissionModule.h +16 -0
  54. package/ios/EXFilePermissionModule.m +68 -0
  55. package/ios/EXFileSystem.h +25 -0
  56. package/ios/EXFileSystem.m +1084 -0
  57. package/ios/EXFileSystemAssetLibraryHandler.h +6 -0
  58. package/ios/EXFileSystemAssetLibraryHandler.m +142 -0
  59. package/ios/EXFileSystemHandler.h +17 -0
  60. package/ios/EXFileSystemLocalFileHandler.h +7 -0
  61. package/ios/EXFileSystemLocalFileHandler.m +79 -0
  62. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.h +16 -0
  63. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.m +55 -0
  64. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.h +13 -0
  65. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.m +64 -0
  66. package/ios/EXSessionTasks/EXSessionHandler.h +19 -0
  67. package/ios/EXSessionTasks/EXSessionHandler.m +49 -0
  68. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h +18 -0
  69. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m +66 -0
  70. package/ios/EXSessionTasks/EXSessionTaskDelegate.h +32 -0
  71. package/ios/EXSessionTasks/EXSessionTaskDelegate.m +58 -0
  72. package/ios/EXSessionTasks/EXSessionTaskDispatcher.h +19 -0
  73. package/ios/EXSessionTasks/EXSessionTaskDispatcher.m +96 -0
  74. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.h +8 -0
  75. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.m +52 -0
  76. package/ios/EXSessionTasks/EXTaskHandlersManager.h +21 -0
  77. package/ios/EXSessionTasks/EXTaskHandlersManager.m +56 -0
  78. package/ios/Encoding.swift +88 -0
  79. package/ios/ExpoFileSystem.h +1 -0
  80. package/ios/ExpoFileSystem.podspec +32 -0
  81. package/ios/FileSystemBackgroundSessionHandler.swift +25 -0
  82. package/ios/FileSystemExceptions.swift +69 -0
  83. package/ios/FileSystemHelpers.swift +66 -0
  84. package/ios/FileSystemModule.swift +263 -0
  85. package/ios/FileSystemRecords.swift +74 -0
  86. package/ios/NSData+EXFileSystem.h +9 -0
  87. package/ios/NSData+EXFileSystem.m +19 -0
  88. package/ios/NetworkingHelpers.swift +84 -0
  89. package/ios/Tests/EXFileSystemSpec.swift +55 -0
  90. package/jest.config.js +3 -0
  91. package/kepler/ExponentFileSystem.cpp +498 -0
  92. package/kepler/ExponentFileSystem.h +60 -0
  93. package/kepler/KeplerInit.cpp +28 -0
  94. package/kepler/NetworkingRequestHandler.cpp +47 -0
  95. package/kepler/test/FileSystem.cpp +425 -0
  96. package/package.json +1 -0
  97. package/plugin/build/withFileSystem.d.ts +3 -0
  98. package/plugin/build/withFileSystem.js +12 -0
  99. package/plugin/src/withFileSystem.ts +13 -0
  100. package/plugin/tsconfig.json +9 -0
  101. package/plugin/tsconfig.tsbuildinfo +1 -0
  102. package/react-native.config.js +21 -0
  103. package/src/ExponentFileSystem.kepler.ts +167 -0
  104. package/src/ExponentFileSystem.ts +7 -0
  105. package/src/ExponentFileSystem.web.ts +2 -0
  106. package/src/ExponentFileSystemShim.ts +23 -0
  107. package/src/FileSystem.ts +756 -0
  108. package/src/FileSystem.types.ts +339 -0
  109. package/src/index.ts +2 -0
  110. package/src/types.ts +34 -0
  111. package/tsconfig.json +9 -0
@@ -0,0 +1,498 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+
9
+ #include "ExponentFileSystem.h"
10
+
11
+ #include <JsonContainer/JsonContainer.h>
12
+ #include <KeplerScript/logger/KPLog.h>
13
+ #include <KeplerScript/utils/KeplerPath.h>
14
+ #include <openssl/evp.h>
15
+ #include <openssl/md5.h>
16
+ #include <sys/stat.h>
17
+
18
+ #include <filesystem>
19
+ #include <fstream>
20
+ #include <iostream>
21
+ #include <memory>
22
+ #include <sstream>
23
+ #include <string>
24
+
25
+ namespace {
26
+ std::string md5Hash(const std::string& content) {
27
+ std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)> context(EVP_MD_CTX_new(), ::EVP_MD_CTX_free);
28
+ const EVP_MD* md = EVP_md5();
29
+ unsigned char md_value[EVP_MAX_MD_SIZE];
30
+ unsigned int md_len;
31
+
32
+ EVP_DigestInit_ex2(context.get(), md, NULL);
33
+ EVP_DigestUpdate(context.get(), content.data(), content.length());
34
+ EVP_DigestFinal_ex(context.get(), md_value, &md_len);
35
+
36
+ std::string output(std::string(md_len * 2, '\0'));
37
+ for (size_t i = 0; i < md_len; ++i)
38
+ std::sprintf(&output[i * 2], "%02x", md_value[i]);
39
+
40
+ return output;
41
+ }
42
+
43
+ std::string base64Encode(const std::string& input) {
44
+ const auto base64Length = 4 * ((input.size() + 2) / 3);
45
+ std::vector<unsigned char> base64(base64Length + 1);
46
+ const auto encodedLength =
47
+ EVP_EncodeBlock(base64.data(), reinterpret_cast<const unsigned char*>(input.data()), input.size());
48
+ if (base64Length != encodedLength) {
49
+ throw std::runtime_error(
50
+ std::string("Expected and encoded length differ: expected: ") + std::to_string(base64Length) +
51
+ ", encoded: " + std::to_string(encodedLength));
52
+ }
53
+ return std::string(base64.begin(), base64.end());
54
+ }
55
+
56
+ template<typename T>
57
+ T getOrDefault(volta::react::NativeJSObject map, std::string key, const T& defaultValue) {
58
+ if (map.count(key)) {
59
+ return std::get<T>(map[key]);
60
+ }
61
+ return defaultValue;
62
+ }
63
+ } // namespace
64
+
65
+ ExponentFileSystem::ExponentFileSystem() : volta::react::KeplerTurboModule("ExponentFileSystem") {
66
+ volta::react::KPLog.debug("ExponentFileSystem constructor {}", name());
67
+ };
68
+
69
+ /**
70
+ * @brief Returns "/data" - when called within an app with eg. id "com.amazon.keplerscript.expodemosapp" present in
71
+ * manifest.toml - it's considered as /home/app_user/packages/com.amazon.keplerscript.expodemosapp/data.
72
+ */
73
+ std::string ExponentFileSystem::documentDirectory() {
74
+ return std::filesystem::absolute("data");
75
+ };
76
+
77
+ std::string ExponentFileSystem::cacheDirectory() {
78
+ return std::filesystem::absolute("cache");
79
+ };
80
+
81
+ std::string ExponentFileSystem::bundleDirectory() {
82
+ return volta::react::KeplerPath::getPath(volta::react::KeplerPathKind::JavaScriptBundle);
83
+ };
84
+
85
+ volta::react::Promise ExponentFileSystem::getInfoAsync(
86
+ const std::string fileUri,
87
+ volta::react::NativeJSObject options) {
88
+ bool shouldIncludeFileSize = getOrDefault(options, "size", false);
89
+ bool shouldIncludeMD5Hash = getOrDefault(options, "md5", false);
90
+
91
+ return volta::react::Promise([this, fileUri, shouldIncludeFileSize, shouldIncludeMD5Hash](
92
+ std::shared_ptr<volta::react::Promise> promise) {
93
+ bool exists = std::filesystem::exists(fileUri);
94
+
95
+ if (!exists) {
96
+ promise->resolve(volta::react::NativeJSObject{{"exists", false}, {"isDirectory", false}});
97
+ return;
98
+ }
99
+
100
+ bool isDirectory = std::filesystem::is_directory(fileUri);
101
+
102
+ struct stat fileStat;
103
+ int status = stat(fileUri.c_str(), &fileStat);
104
+ if (status != 0) {
105
+ volta::react::KPLog.error("[ExponentFileSystem] error while obtaining information about the file!");
106
+ promise->reject("Error while obtaining information about the file!");
107
+ return;
108
+ }
109
+
110
+ std::uintmax_t modificationTime = fileStat.st_mtime;
111
+ std::uintmax_t fileSize = getSize(fileUri);
112
+
113
+ auto fileInfo = volta::react::NativeJSObject{
114
+ {"exists", true},
115
+ {"isDirectory", isDirectory},
116
+ {"modification", std::to_string(modificationTime)}};
117
+
118
+ if (shouldIncludeFileSize) {
119
+ fileInfo.insert({"size", std::to_string(fileSize)});
120
+ }
121
+
122
+ if (shouldIncludeMD5Hash) {
123
+ std::ifstream stream(fileUri);
124
+ volta::react::KPLog.debug("[MD5] trying to open the file: {} for read", fileUri);
125
+ if (stream.fail()) {
126
+ volta::react::KPLog.error("[MD5] unable to open file at {} for read", fileUri);
127
+ promise->reject("Error while trying to open the file");
128
+ return;
129
+ } else {
130
+ std::stringstream buffer;
131
+ buffer << stream.rdbuf();
132
+ std::string content = buffer.str();
133
+ volta::react::KPLog.debug("[MD5] content: {}", content);
134
+ volta::react::KPLog.debug("[MD5] calculating the file content hash...");
135
+ std::string hash = md5Hash(content);
136
+ volta::react::KPLog.debug("[MD5] file hash: {}", hash);
137
+ fileInfo.insert({"md5", hash});
138
+ }
139
+ }
140
+ promise->resolve(fileInfo);
141
+ });
142
+ };
143
+
144
+ volta::react::Promise ExponentFileSystem::readAsStringAsync(
145
+ const std::string fileUri,
146
+ volta::react::NativeJSObject options) {
147
+ std::string desiredEncoding = getOrDefault(options, "encoding", std::string("utf8"));
148
+ int bytesToSkip = int(getOrDefault(options, "position", static_cast<double>(0)));
149
+ int length = getOrDefault(options, "length", static_cast<double>(-1));
150
+
151
+ return volta::react::Promise(
152
+ [this, fileUri, desiredEncoding, bytesToSkip, length](std::shared_ptr<volta::react::Promise> promise) {
153
+ try {
154
+ volta::react::KPLog.debug("[ExponentFileSystem] path: {}", fileUri);
155
+ std::int32_t fileSize = std::filesystem::file_size(fileUri);
156
+
157
+ std::ifstream stream(fileUri);
158
+ volta::react::KPLog.debug("[ExponentFileSystem] trying to open the file: {} for read", fileUri);
159
+ if (stream.fail()) {
160
+ volta::react::KPLog.error("[ExponentFileSystem] unable to open file at {} for read", fileUri);
161
+ promise->reject("Error while trying to open the file");
162
+ return;
163
+ }
164
+
165
+ if (bytesToSkip >= fileSize) {
166
+ volta::react::KPLog.error("[ExponentFileSystem] cannot skip beyond end of file!");
167
+ promise->reject("Cannot skip beyond end of file");
168
+ return;
169
+ }
170
+
171
+ std::int32_t bytesToRead = length < 0 ? std::min(fileSize, fileSize - bytesToSkip)
172
+ : std::min(length, fileSize - bytesToSkip);
173
+
174
+ stream.seekg(bytesToSkip, std::ios::beg);
175
+ std::string content;
176
+ content.resize(bytesToRead);
177
+ stream.read(&content[0], bytesToRead);
178
+ volta::react::KPLog.debug("[ExponentFileSystem] content: {}", content);
179
+
180
+ if (desiredEncoding == "base64") {
181
+ volta::react::KPLog.debug("[base64] base64 encoding...");
182
+ promise->resolve(base64Encode(content));
183
+ } else {
184
+ promise->resolve(content);
185
+ }
186
+ } catch (std::exception& e) {
187
+ volta::react::KPLog.error("[ExponentFileSystem] reading file exception reason: {}", e.what());
188
+ promise->reject(e.what());
189
+ }
190
+ });
191
+ };
192
+
193
+ volta::react::Promise ExponentFileSystem::getContentUriAsync(const std::string fileUri) {
194
+ return volta::react::Promise([this, &fileUri](std::shared_ptr<volta::react::Promise> promise) {
195
+ std::string contentUri = std::filesystem::absolute(fileUri);
196
+
197
+ promise->resolve(contentUri);
198
+ });
199
+ };
200
+
201
+ volta::react::Promise ExponentFileSystem::writeAsStringAsync(
202
+ const std::string fileUri,
203
+ const std::string contents,
204
+ volta::react::NativeJSObject options) {
205
+ std::string desiredEncoding = getOrDefault(options, "encoding", std::string("utf8"));
206
+
207
+ return volta::react::Promise(
208
+ [this, fileUri, contents, desiredEncoding](std::shared_ptr<volta::react::Promise> promise) {
209
+ try {
210
+ std::ofstream stream(fileUri);
211
+ volta::react::KPLog.debug("[ExponentFileSystem] trying to open the file: {} for write", fileUri);
212
+ if (stream.fail()) {
213
+ volta::react::KPLog.error("[ExponentFileSystem] unable to open file at {} for write", fileUri);
214
+ promise->reject("Error while trying to open the file");
215
+ return;
216
+ } else {
217
+ if (desiredEncoding == "base64") {
218
+ stream << base64Encode(contents);
219
+ } else {
220
+ stream << contents;
221
+ }
222
+
223
+ if (stream.fail()) {
224
+ volta::react::KPLog.error("[ExponentFileSystem] error while writing to file");
225
+ promise->reject("Error while trying to write to the file");
226
+ return;
227
+ }
228
+ stream.close();
229
+ }
230
+ promise->resolve();
231
+ } catch (std::exception& e) {
232
+ volta::react::KPLog.error("[ExponentFileSystem] writing file exception reason: {}", e.what());
233
+ promise->reject(e.what());
234
+ }
235
+ });
236
+ };
237
+
238
+ volta::react::Promise ExponentFileSystem::writeArrayBufferAsync(
239
+ const std::string fileUri,
240
+ const volta::react::ArrayBuffer arrayBuffer) {
241
+ return volta::react::Promise([this, fileUri, arrayBuffer](std::shared_ptr<volta::react::Promise> promise) {
242
+ try {
243
+ std::ofstream file(fileUri, std::ios::binary);
244
+ std::shared_ptr<std::vector<uint8_t>> dataPtr = arrayBuffer.dataVector();
245
+
246
+ if (file.fail()) {
247
+ volta::react::KPLog.error("[ExponentFileSystem] unable to open file at {} for response write", fileUri);
248
+ promise->reject("File while tring to open the file");
249
+ return;
250
+ } else {
251
+ if (dataPtr && !dataPtr->empty()) {
252
+ file.write(reinterpret_cast<const char*>(dataPtr->data()), dataPtr->size());
253
+ if (file.fail()) {
254
+ volta::react::KPLog.error("[ExponentFileSystem] error while writing response to file");
255
+ promise->reject("Error while trying to write response to file");
256
+ return;
257
+ }
258
+ }
259
+ }
260
+ promise->resolve();
261
+ } catch (std::exception& e) {
262
+ volta::react::KPLog.error("[ExponentFileSystem] writing file exception reason: {}", e.what());
263
+ promise->reject(e.what());
264
+ }
265
+ });
266
+ }
267
+
268
+ volta::react::Promise ExponentFileSystem::deleteAsync(const std::string fileUri, volta::react::NativeJSObject options) {
269
+ bool idempotent = getOrDefault(options, "idempotent", false);
270
+
271
+ return volta::react::Promise([this, fileUri, idempotent](std::shared_ptr<volta::react::Promise> promise) {
272
+ if (!std::filesystem::exists(fileUri)) {
273
+ if (idempotent) {
274
+ promise->resolve();
275
+ return;
276
+ } else {
277
+ volta::react::KPLog.error("[ExponentFileSystem] file does not exist at the specified URI!");
278
+ promise->reject("File does not exist at the specified URI");
279
+ return;
280
+ }
281
+ }
282
+
283
+ if (std::filesystem::is_regular_file(fileUri)) {
284
+ try {
285
+ std::filesystem::remove(fileUri);
286
+ promise->resolve();
287
+ } catch (std::filesystem::filesystem_error& e) {
288
+ volta::react::KPLog.error("[ExponentFileSystem] file deletion exception, reason: {}", e.what());
289
+ promise->reject(e.what());
290
+ }
291
+ } else {
292
+ volta::react::KPLog.error("[ExponentFileSystem] resource is not a regular file!");
293
+ promise->reject("Resource is not a regular file");
294
+ }
295
+ });
296
+ };
297
+
298
+ volta::react::Promise ExponentFileSystem::moveAsync(volta::react::NativeJSObject options) {
299
+ std::string from = getOrDefault(options, "from", std::string(""));
300
+ std::string to = getOrDefault(options, "to", std::string(""));
301
+
302
+ return volta::react::Promise([this, from, to](std::shared_ptr<volta::react::Promise> promise) {
303
+ if (from.empty() || to.empty()) {
304
+ volta::react::KPLog.error(
305
+ "[ExponentFileSystem]::moveAsync 'from' or 'to' not provided but they are both required");
306
+ promise->reject("'from' or 'to' not provided but they are both required");
307
+ return;
308
+ }
309
+
310
+ try {
311
+ std::filesystem::rename(from, to);
312
+ promise->resolve();
313
+ } catch (std::filesystem::filesystem_error& e) {
314
+ volta::react::KPLog.error("[ExponentFileSystem] file transfer exception, reason: {}", e.what());
315
+ promise->reject(e.what());
316
+ }
317
+ });
318
+ };
319
+
320
+ volta::react::Promise ExponentFileSystem::copyAsync(volta::react::NativeJSObject options) {
321
+ std::string from = getOrDefault(options, "from", std::string(""));
322
+ std::string to = getOrDefault(options, "to", std::string(""));
323
+
324
+ return volta::react::Promise([this, from, to](std::shared_ptr<volta::react::Promise> promise) {
325
+ if (from.empty() || to.empty()) {
326
+ volta::react::KPLog.error(
327
+ "[ExponentFileSystem]::copyAsync 'from' or 'to' not provided but they are both required");
328
+ promise->reject("'from' or 'to' not provided but they are both required");
329
+ return;
330
+ }
331
+
332
+ try {
333
+ std::filesystem::copy(from, to, std::filesystem::copy_options::recursive);
334
+ promise->resolve();
335
+ } catch (std::filesystem::filesystem_error& e) {
336
+ volta::react::KPLog.error("[ExponentFileSystem] file transfer exception, reason: {}", e.what());
337
+ promise->reject(e.what());
338
+ }
339
+ });
340
+ };
341
+
342
+ volta::react::Promise ExponentFileSystem::makeDirectoryAsync(
343
+ const std::string fileUri,
344
+ volta::react::NativeJSObject options) {
345
+ bool idempotent = getOrDefault(options, "intermediates", false);
346
+
347
+ return volta::react::Promise([this, fileUri, idempotent](std::shared_ptr<volta::react::Promise> promise) {
348
+ try {
349
+ bool exists = std::filesystem::exists(fileUri);
350
+
351
+ if (exists) {
352
+ if (idempotent) {
353
+ promise->resolve();
354
+ return;
355
+ }
356
+ volta::react::KPLog.error("[ExponentFileSystem] directory already exists!");
357
+ promise->reject("Directory already exists");
358
+ return;
359
+ }
360
+
361
+ std::error_code errorCode;
362
+
363
+ if (std::filesystem::create_directories(fileUri, errorCode)) {
364
+ volta::react::KPLog.debug("[ExponentFileSystem] directory created successfully!");
365
+ } else {
366
+ volta::react::KPLog.error(
367
+ "[ExponentFileSystem] directory creation failed, message: {}",
368
+ errorCode.message());
369
+ promise->reject(errorCode.message());
370
+ return;
371
+ }
372
+ promise->resolve();
373
+ } catch (std::exception& e) {
374
+ volta::react::KPLog.error("[ExponentFileSystem] directory creation exception, reason: {}", e.what());
375
+ promise->reject(e.what());
376
+ }
377
+ });
378
+ };
379
+
380
+ volta::react::Promise ExponentFileSystem::readDirectoryAsync(const std::string fileUri) {
381
+ return volta::react::Promise([this, fileUri](std::shared_ptr<volta::react::Promise> promise) {
382
+ try {
383
+ if (!std::filesystem::exists(fileUri)) {
384
+ volta::react::KPLog.error("[ExponentFileSystem] directory does not exist at the specified URI!");
385
+ promise->reject("Directory does not exist at the specified URI");
386
+ return;
387
+ } else if (!std::filesystem::is_directory(fileUri)) {
388
+ volta::react::KPLog.error("[ExponentFileSystem] resource at the specified URI is not a directory!");
389
+ promise->reject("Resource at the specified URI is not a directory");
390
+ return;
391
+ }
392
+
393
+ auto childrenNames = volta::react::NativeJSArray{};
394
+
395
+ // Symbolic links of the directory entries are not followed
396
+ // during this enumeration.
397
+ for (auto& child : std::filesystem::directory_iterator(fileUri)) {
398
+ childrenNames.push_back(child.path().filename().string());
399
+ }
400
+
401
+ promise->resolve(childrenNames);
402
+ } catch (std::exception& e) {
403
+ volta::react::KPLog.error("[ExponentFileSystem] Reading directory exception: {}", e.what());
404
+ promise->reject(e.what());
405
+ }
406
+ });
407
+ };
408
+
409
+ volta::react::Promise ExponentFileSystem::getFreeDiskStorageAsync() {
410
+ return volta::react::Promise([](std::shared_ptr<volta::react::Promise> promise) {
411
+ try {
412
+ std::string path = std::filesystem::absolute("data");
413
+
414
+ std::error_code errorCode;
415
+ std::filesystem::space_info spaceInfo = std::filesystem::space(path, errorCode);
416
+ if (errorCode) {
417
+ volta::react::KPLog.error(
418
+ "[ExponentFileSystem] Error when getting free disk space: {}",
419
+ errorCode.message());
420
+ promise->reject(errorCode.message());
421
+ return;
422
+ }
423
+ volta::react::KPLog.debug("[ExponentFileSystem] Free space: {}", std::to_string(spaceInfo.available));
424
+ promise->resolve(std::to_string(spaceInfo.available));
425
+ } catch (std::exception& e) {
426
+ volta::react::KPLog.error("[ExponentFileSystem] Getting free disk storage exception: {}", e.what());
427
+ promise->reject(e.what());
428
+ }
429
+ });
430
+ };
431
+
432
+ volta::react::Promise ExponentFileSystem::getTotalDiskCapacityAsync() {
433
+ return volta::react::Promise([](std::shared_ptr<volta::react::Promise> promise) { promise->resolve(); });
434
+ };
435
+
436
+ volta::react::Promise ExponentFileSystem::downloadAsync(
437
+ const std::string,
438
+ const std::string,
439
+ volta::react::NativeJSObject,
440
+ double,
441
+ std::vector<utils::json::JsonContainer>) {
442
+ return volta::react::Promise([](std::shared_ptr<volta::react::Promise> promise) {
443
+ promise->reject("downloadAsync method has been deprecated, Update expo-file-system npm package");
444
+ });
445
+ };
446
+
447
+ volta::react::Promise ExponentFileSystem::uploadAsync(
448
+ const std::string,
449
+ const std::string,
450
+ volta::react::NativeJSObject,
451
+ double,
452
+ std::vector<utils::json::JsonContainer>) {
453
+ return volta::react::Promise([](std::shared_ptr<volta::react::Promise> promise) {
454
+ promise->reject("uploadAsync method has been deprecated, Update expo-file-system npm package");
455
+ });
456
+ };
457
+
458
+ std::uintmax_t ExponentFileSystem::getSize(const std::string& path) {
459
+ if (std::filesystem::is_regular_file(path)) {
460
+ return std::filesystem::file_size(path);
461
+ }
462
+
463
+ std::uintmax_t totalSize = DIRECTORY_SIZE;
464
+ for (const auto& file : std::filesystem::recursive_directory_iterator(
465
+ path,
466
+ std::filesystem::directory_options::follow_directory_symlink)) {
467
+ if (std::filesystem::is_regular_file(file)) {
468
+ totalSize += std::filesystem::file_size(file);
469
+ } else {
470
+ totalSize += DIRECTORY_SIZE;
471
+ }
472
+ }
473
+
474
+ return totalSize;
475
+ };
476
+
477
+ void ExponentFileSystem::aggregateMethods(
478
+ volta::react::MethodAggregator<volta::react::KeplerTurboModule>& methodAggregator) const noexcept {
479
+ volta::react::KPLog.debug("methodAggregator");
480
+
481
+ methodAggregator.addMethod("documentDirectory", 0, &ExponentFileSystem::documentDirectory);
482
+ methodAggregator.addMethod("cacheDirectory", 0, &ExponentFileSystem::cacheDirectory);
483
+ methodAggregator.addMethod("bundleDirectory", 0, &ExponentFileSystem::bundleDirectory);
484
+ methodAggregator.addMethod("getInfoAsync", 2, &ExponentFileSystem::getInfoAsync);
485
+ methodAggregator.addMethod("readAsStringAsync", 2, &ExponentFileSystem::readAsStringAsync);
486
+ methodAggregator.addMethod("getContentUriAsync", 1, &ExponentFileSystem::getContentUriAsync);
487
+ methodAggregator.addMethod("writeAsStringAsync", 3, &ExponentFileSystem::writeAsStringAsync);
488
+ methodAggregator.addMethod("writeArrayBufferAsync", 2, &ExponentFileSystem::writeArrayBufferAsync);
489
+ methodAggregator.addMethod("deleteAsync", 2, &ExponentFileSystem::deleteAsync);
490
+ methodAggregator.addMethod("moveAsync", 1, &ExponentFileSystem::moveAsync);
491
+ methodAggregator.addMethod("copyAsync", 1, &ExponentFileSystem::copyAsync);
492
+ methodAggregator.addMethod("makeDirectoryAsync", 2, &ExponentFileSystem::makeDirectoryAsync);
493
+ methodAggregator.addMethod("readDirectoryAsync", 1, &ExponentFileSystem::readDirectoryAsync);
494
+ methodAggregator.addMethod("getFreeDiskStorageAsync", 0, &ExponentFileSystem::getFreeDiskStorageAsync);
495
+ methodAggregator.addMethod("getTotalDiskCapacityAsync", 0, &ExponentFileSystem::getTotalDiskCapacityAsync);
496
+ methodAggregator.addMethod("downloadAsync", 5, &ExponentFileSystem::downloadAsync);
497
+ methodAggregator.addMethod("uploadAsync", 4, &ExponentFileSystem::uploadAsync);
498
+ }
@@ -0,0 +1,60 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+ #pragma once
9
+
10
+ #include <KeplerScript/modules/KeplerTurboModule.h>
11
+
12
+ class KEPLERSCRIPT_EXPORT ExponentFileSystem : public volta::react::KeplerTurboModule {
13
+ public:
14
+ ExponentFileSystem();
15
+
16
+ #ifndef UNIT_TEST
17
+ protected:
18
+ #endif
19
+ std::string documentDirectory();
20
+ std::string cacheDirectory();
21
+ std::string bundleDirectory();
22
+
23
+ volta::react::Promise getInfoAsync(const std::string fileUri, volta::react::NativeJSObject options);
24
+ volta::react::Promise readAsStringAsync(const std::string fileUri, volta::react::NativeJSObject options);
25
+ volta::react::Promise getContentUriAsync(const std::string fileUri);
26
+ volta::react::Promise writeAsStringAsync(
27
+ const std::string fileUri,
28
+ const std::string contents,
29
+ volta::react::NativeJSObject options);
30
+ volta::react::Promise writeArrayBufferAsync(
31
+ const std::string fileUri,
32
+ const volta::react::ArrayBuffer arrayBuffer);
33
+ volta::react::Promise deleteAsync(const std::string fileUri, volta::react::NativeJSObject options);
34
+ volta::react::Promise moveAsync(volta::react::NativeJSObject options);
35
+ volta::react::Promise copyAsync(volta::react::NativeJSObject options);
36
+ volta::react::Promise makeDirectoryAsync(const std::string fileUri, volta::react::NativeJSObject options);
37
+ volta::react::Promise readDirectoryAsync(const std::string fileUri);
38
+ volta::react::Promise getFreeDiskStorageAsync();
39
+ volta::react::Promise getTotalDiskCapacityAsync();
40
+ volta::react::Promise downloadAsync(
41
+ const std::string url,
42
+ const std::string fileUri,
43
+ volta::react::NativeJSObject options,
44
+ double requestId,
45
+ std::vector<utils::json::JsonContainer> headers);
46
+ volta::react::Promise uploadAsync(
47
+ const std::string url,
48
+ const std::string fileUri,
49
+ volta::react::NativeJSObject options,
50
+ double requestId,
51
+ std::vector<utils::json::JsonContainer> headers);
52
+
53
+ void aggregateMethods(
54
+ volta::react::MethodAggregator<volta::react::KeplerTurboModule>& methodAggregator) const noexcept override;
55
+
56
+ private:
57
+ static constexpr int DIRECTORY_SIZE = 4096;
58
+
59
+ std::uintmax_t getSize(const std::string& path);
60
+ };
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+
9
+ #include <KeplerScript/logger/KPLog.h>
10
+ #include <KeplerScript/utils/autolink/KeplerAutoLinkInfo.h>
11
+ #include <keplerui-072/keplerscript-export.h>
12
+
13
+ #include "ExponentFileSystem.h"
14
+ #include "RegisterModule.h"
15
+
16
+ extern "C" {
17
+ KEPLERSCRIPT_EXPORT void keplerAutoLinkInitV1(const kepler::autolink::v1::KeplerAutoLinkInfo* autoLinkInfo) noexcept {
18
+ volta::react::KPLog.debug("keplerAutoLinkInitV1 for ExponentFileSystem");
19
+
20
+ REGISTER_MODULE(autoLinkInfo, ExponentFileSystem, "ExponentFileSystem");
21
+
22
+ volta::react::KPLog.debug("after registering module");
23
+ }
24
+ }
25
+
26
+ int main() {
27
+ return 0;
28
+ }
@@ -0,0 +1,47 @@
1
+ #include "NetworkingRequestHandler.h"
2
+
3
+ #include <fstream>
4
+
5
+ bool NetworkingRequestHandler::supports(utils::json::JsonContainer& data) {
6
+ return data["fileUri"].isValue();
7
+ }
8
+
9
+ void NetworkingRequestHandler::decorateRequest(
10
+ utils::json::JsonContainer& data,
11
+ const std::string& contentType,
12
+ volta::react::NetworkRequest& request) {
13
+ auto type = data["type"].getValue<std::string>("");
14
+
15
+ if (type.empty()) {
16
+ type = "application/octet-stream";
17
+ }
18
+
19
+ request.addHeader(volta::react::NetworkingModule::CONTENT_TYPE_HEADER_KEY, type);
20
+
21
+ try {
22
+ auto dataPtr = std::make_shared<std::vector<uint8_t>>();
23
+
24
+ auto fileUri = data["fileUri"].getValue<std::string>();
25
+
26
+ std::ifstream file(fileUri, std::ios::binary);
27
+
28
+ if (file.fail()) {
29
+ volta::react::KPLog.error("[ExponentFileSystem] unable to open file at {} for response read", fileUri);
30
+ } else {
31
+ std::copy(
32
+ std::istreambuf_iterator<char>(file),
33
+ std::istreambuf_iterator<char>(),
34
+ std::back_inserter(*dataPtr));
35
+
36
+ if (file.fail()) {
37
+ volta::react::KPLog.error("[ExponentFileSystem] error while reading response from file");
38
+ } else {
39
+ volta::react::KPLog.debug("[ExponentFileSystem] successfully read response from file");
40
+ volta::react::ArrayBuffer buf(dataPtr);
41
+ request.bodyDataBuffer = volta::react::ArrayBuffer(buf.dataVector());
42
+ }
43
+ }
44
+ } catch (std::exception& e) {
45
+ volta::react::KPLog.error("[ExponentFileSystem] reading response from file exception reason: {}", e.what());
46
+ }
47
+ }