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