164f5c95fSŁukasz Kosmaty // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
264f5c95fSŁukasz Kosmaty 
364f5c95fSŁukasz Kosmaty #include "ExpoModulesHostObject.h"
4b627df43SŁukasz Kosmaty #include "LazyObject.h"
564f5c95fSŁukasz Kosmaty 
664f5c95fSŁukasz Kosmaty #include <folly/dynamic.h>
764f5c95fSŁukasz Kosmaty #include <jsi/JSIDynamic.h>
8695fef9bSKudo Chien #include <react/bridging/LongLivedObject.h>
964f5c95fSŁukasz Kosmaty 
1064f5c95fSŁukasz Kosmaty namespace jsi = facebook::jsi;
1164f5c95fSŁukasz Kosmaty 
1264f5c95fSŁukasz Kosmaty namespace expo {
1364f5c95fSŁukasz Kosmaty 
ExpoModulesHostObject(JSIInteropModuleRegistry * installer)1464f5c95fSŁukasz Kosmaty ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer)
1564f5c95fSŁukasz Kosmaty   : installer(installer) {}
1664f5c95fSŁukasz Kosmaty 
1733ae33eaSŁukasz Kosmaty /**
1833ae33eaSŁukasz Kosmaty  * Clears jsi references held by JSRegistry and JavaScriptRuntime.
1933ae33eaSŁukasz Kosmaty  */
~ExpoModulesHostObject()2033ae33eaSŁukasz Kosmaty ExpoModulesHostObject::~ExpoModulesHostObject() {
21695fef9bSKudo Chien   facebook::react::LongLivedObjectCollection::get().clear();
2233ae33eaSŁukasz Kosmaty   installer->jsRegistry.reset();
2333ae33eaSŁukasz Kosmaty   installer->runtimeHolder.reset();
24*29e8b6f8SŁukasz Kosmaty   installer->jsInvoker.reset();
25*29e8b6f8SŁukasz Kosmaty   installer->nativeInvoker.reset();
26*29e8b6f8SŁukasz Kosmaty   installer->jniDeallocator.reset();
2733ae33eaSŁukasz Kosmaty }
2833ae33eaSŁukasz Kosmaty 
get(jsi::Runtime & runtime,const jsi::PropNameID & name)2964f5c95fSŁukasz Kosmaty jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
3064f5c95fSŁukasz Kosmaty   auto cName = name.utf8(runtime);
31b627df43SŁukasz Kosmaty 
32b627df43SŁukasz Kosmaty   if (!installer->hasModule(cName)) {
33b627df43SŁukasz Kosmaty     modulesCache.erase(cName);
3464f5c95fSŁukasz Kosmaty     return jsi::Value::undefined();
3564f5c95fSŁukasz Kosmaty   }
36b627df43SŁukasz Kosmaty   if (UniqueJSIObject &cachedObject = modulesCache[cName]) {
37b627df43SŁukasz Kosmaty     return jsi::Value(runtime, *cachedObject);
38b627df43SŁukasz Kosmaty   }
3964f5c95fSŁukasz Kosmaty 
40b627df43SŁukasz Kosmaty   // Create a lazy object for the specific module. It defers initialization of the final module object.
41b627df43SŁukasz Kosmaty   LazyObject::Shared moduleLazyObject = std::make_shared<LazyObject>(
42b627df43SŁukasz Kosmaty     [this, cName](jsi::Runtime &rt) {
43b627df43SŁukasz Kosmaty       auto module = installer->getModule(cName);
4464f5c95fSŁukasz Kosmaty       module->cthis()->jsiInteropModuleRegistry = installer;
45b627df43SŁukasz Kosmaty       return module->cthis()->getJSIObject(rt);
46b627df43SŁukasz Kosmaty     });
47b627df43SŁukasz Kosmaty 
48b627df43SŁukasz Kosmaty   // Save the module's lazy host object for later use.
49b627df43SŁukasz Kosmaty   modulesCache[cName] = std::make_unique<jsi::Object>(
50b627df43SŁukasz Kosmaty     jsi::Object::createFromHostObject(runtime, moduleLazyObject));
51b627df43SŁukasz Kosmaty 
52b627df43SŁukasz Kosmaty   return jsi::Value(runtime, *modulesCache[cName]);
5364f5c95fSŁukasz Kosmaty }
5464f5c95fSŁukasz Kosmaty 
set(jsi::Runtime & runtime,const jsi::PropNameID & name,const jsi::Value & value)5564f5c95fSŁukasz Kosmaty void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name,
5664f5c95fSŁukasz Kosmaty                                 const jsi::Value &value) {
5764f5c95fSŁukasz Kosmaty   throw jsi::JSError(
5864f5c95fSŁukasz Kosmaty     runtime,
5964f5c95fSŁukasz Kosmaty     "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
6064f5c95fSŁukasz Kosmaty   );
6164f5c95fSŁukasz Kosmaty }
6264f5c95fSŁukasz Kosmaty 
getPropertyNames(jsi::Runtime & rt)6364f5c95fSŁukasz Kosmaty std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &rt) {
6478b3dbc7SŁukasz Kosmaty   auto names = installer->getModulesName();
6578b3dbc7SŁukasz Kosmaty   size_t size = names->size();
66d3f89796SBartłomiej Klocek   std::vector<jsi::PropNameID> result;
67d3f89796SBartłomiej Klocek   result.reserve(size);
6878b3dbc7SŁukasz Kosmaty   for (int i = 0; i < size; i++) {
6978b3dbc7SŁukasz Kosmaty     result.push_back(
7078b3dbc7SŁukasz Kosmaty       jsi::PropNameID::forUtf8(rt, names->getElement(i)->toStdString())
7178b3dbc7SŁukasz Kosmaty     );
7278b3dbc7SŁukasz Kosmaty   }
7378b3dbc7SŁukasz Kosmaty   return result;
7464f5c95fSŁukasz Kosmaty }
7564f5c95fSŁukasz Kosmaty } // namespace expo
76