1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "ExpoModulesHostObject.h"
4 #include "LazyObject.h"
5 
6 #include <folly/dynamic.h>
7 #include <jsi/JSIDynamic.h>
8 #include <react/bridging/LongLivedObject.h>
9 
10 namespace jsi = facebook::jsi;
11 
12 namespace expo {
13 
14 ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer)
15   : installer(installer) {}
16 
17 /**
18  * Clears jsi references held by JSRegistry and JavaScriptRuntime.
19  */
20 ExpoModulesHostObject::~ExpoModulesHostObject() {
21   facebook::react::LongLivedObjectCollection::get().clear();
22   installer->jsRegistry.reset();
23   installer->runtimeHolder.reset();
24 }
25 
26 jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
27   auto cName = name.utf8(runtime);
28 
29   if (!installer->hasModule(cName)) {
30     modulesCache.erase(cName);
31     return jsi::Value::undefined();
32   }
33   if (UniqueJSIObject &cachedObject = modulesCache[cName]) {
34     return jsi::Value(runtime, *cachedObject);
35   }
36 
37   // Create a lazy object for the specific module. It defers initialization of the final module object.
38   LazyObject::Shared moduleLazyObject = std::make_shared<LazyObject>(
39     [this, cName](jsi::Runtime &rt) {
40       auto module = installer->getModule(cName);
41       module->cthis()->jsiInteropModuleRegistry = installer;
42       return module->cthis()->getJSIObject(rt);
43     });
44 
45   // Save the module's lazy host object for later use.
46   modulesCache[cName] = std::make_unique<jsi::Object>(
47     jsi::Object::createFromHostObject(runtime, moduleLazyObject));
48 
49   return jsi::Value(runtime, *modulesCache[cName]);
50 }
51 
52 void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name,
53                                 const jsi::Value &value) {
54   throw jsi::JSError(
55     runtime,
56     "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
57   );
58 }
59 
60 std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &rt) {
61   auto names = installer->getModulesName();
62   size_t size = names->size();
63   std::vector<jsi::PropNameID> result;
64   result.reserve(size);
65   for (int i = 0; i < size; i++) {
66     result.push_back(
67       jsi::PropNameID::forUtf8(rt, names->getElement(i)->toStdString())
68     );
69   }
70   return result;
71 }
72 } // namespace expo
73