ModuleRegistry.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "ModuleRegistry.h"
  8. #include <glog/logging.h>
  9. #include "NativeModule.h"
  10. #include "SystraceSection.h"
  11. namespace facebook {
  12. namespace react {
  13. namespace {
  14. std::string normalizeName(std::string name) {
  15. // TODO mhorowitz #10487027: This is super ugly. We should just
  16. // change iOS to emit normalized names, drop the "RK..." from
  17. // names hardcoded in Android, and then delete this and the
  18. // similar hacks in js.
  19. if (name.compare(0, 3, "RCT") == 0) {
  20. return name.substr(3);
  21. } else if (name.compare(0, 2, "RK") == 0) {
  22. return name.substr(2);
  23. }
  24. return name;
  25. }
  26. } // namespace
  27. ModuleRegistry::ModuleRegistry(
  28. std::vector<std::unique_ptr<NativeModule>> modules,
  29. ModuleNotFoundCallback callback)
  30. : modules_{std::move(modules)}, moduleNotFoundCallback_{callback} {}
  31. void ModuleRegistry::updateModuleNamesFromIndex(size_t index) {
  32. for (; index < modules_.size(); index++) {
  33. std::string name = normalizeName(modules_[index]->getName());
  34. modulesByName_[name] = index;
  35. }
  36. }
  37. void ModuleRegistry::registerModules(
  38. std::vector<std::unique_ptr<NativeModule>> modules) {
  39. SystraceSection s_("ModuleRegistry::registerModules");
  40. if (modules_.empty() && unknownModules_.empty()) {
  41. modules_ = std::move(modules);
  42. } else {
  43. size_t modulesSize = modules_.size();
  44. size_t addModulesSize = modules.size();
  45. bool addToNames = !modulesByName_.empty();
  46. modules_.reserve(modulesSize + addModulesSize);
  47. std::move(modules.begin(), modules.end(), std::back_inserter(modules_));
  48. if (!unknownModules_.empty()) {
  49. for (size_t index = modulesSize; index < modulesSize + addModulesSize;
  50. index++) {
  51. std::string name = normalizeName(modules_[index]->getName());
  52. auto it = unknownModules_.find(name);
  53. if (it != unknownModules_.end()) {
  54. throw std::runtime_error(folly::to<std::string>(
  55. "module ",
  56. name,
  57. " was required without being registered and is now being registered."));
  58. } else if (addToNames) {
  59. modulesByName_[name] = index;
  60. }
  61. }
  62. } else if (addToNames) {
  63. updateModuleNamesFromIndex(modulesSize);
  64. }
  65. }
  66. }
  67. std::vector<std::string> ModuleRegistry::moduleNames() {
  68. SystraceSection s_("ModuleRegistry::moduleNames");
  69. std::vector<std::string> names;
  70. for (size_t i = 0; i < modules_.size(); i++) {
  71. std::string name = normalizeName(modules_[i]->getName());
  72. modulesByName_[name] = i;
  73. names.push_back(std::move(name));
  74. }
  75. return names;
  76. }
  77. folly::Optional<ModuleConfig> ModuleRegistry::getConfig(
  78. const std::string &name) {
  79. SystraceSection s("ModuleRegistry::getConfig", "module", name);
  80. // Initialize modulesByName_
  81. if (modulesByName_.empty() && !modules_.empty()) {
  82. moduleNames();
  83. }
  84. auto it = modulesByName_.find(name);
  85. if (it == modulesByName_.end()) {
  86. if (unknownModules_.find(name) != unknownModules_.end()) {
  87. return folly::none;
  88. }
  89. if (!moduleNotFoundCallback_ || !moduleNotFoundCallback_(name) ||
  90. (it = modulesByName_.find(name)) == modulesByName_.end()) {
  91. unknownModules_.insert(name);
  92. return folly::none;
  93. }
  94. }
  95. size_t index = it->second;
  96. CHECK(index < modules_.size());
  97. NativeModule *module = modules_[index].get();
  98. // string name, object constants, array methodNames (methodId is index),
  99. // [array promiseMethodIds], [array syncMethodIds]
  100. folly::dynamic config = folly::dynamic::array(name);
  101. {
  102. SystraceSection s_("ModuleRegistry::getConstants", "module", name);
  103. config.push_back(module->getConstants());
  104. }
  105. {
  106. SystraceSection s_("ModuleRegistry::getMethods", "module", name);
  107. std::vector<MethodDescriptor> methods = module->getMethods();
  108. folly::dynamic methodNames = folly::dynamic::array;
  109. folly::dynamic promiseMethodIds = folly::dynamic::array;
  110. folly::dynamic syncMethodIds = folly::dynamic::array;
  111. for (auto &descriptor : methods) {
  112. // TODO: #10487027 compare tags instead of doing string comparison?
  113. methodNames.push_back(std::move(descriptor.name));
  114. if (descriptor.type == "promise") {
  115. promiseMethodIds.push_back(methodNames.size() - 1);
  116. } else if (descriptor.type == "sync") {
  117. syncMethodIds.push_back(methodNames.size() - 1);
  118. }
  119. }
  120. if (!methodNames.empty()) {
  121. config.push_back(std::move(methodNames));
  122. if (!promiseMethodIds.empty() || !syncMethodIds.empty()) {
  123. config.push_back(std::move(promiseMethodIds));
  124. if (!syncMethodIds.empty()) {
  125. config.push_back(std::move(syncMethodIds));
  126. }
  127. }
  128. }
  129. }
  130. if (config.size() == 2 && config[1].empty()) {
  131. // no constants or methods
  132. return folly::none;
  133. } else {
  134. return ModuleConfig{index, config};
  135. }
  136. }
  137. void ModuleRegistry::callNativeMethod(
  138. unsigned int moduleId,
  139. unsigned int methodId,
  140. folly::dynamic &&params,
  141. int callId) {
  142. if (moduleId >= modules_.size()) {
  143. throw std::runtime_error(folly::to<std::string>(
  144. "moduleId ", moduleId, " out of range [0..", modules_.size(), ")"));
  145. }
  146. modules_[moduleId]->invoke(methodId, std::move(params), callId);
  147. }
  148. MethodCallResult ModuleRegistry::callSerializableNativeHook(
  149. unsigned int moduleId,
  150. unsigned int methodId,
  151. folly::dynamic &&params) {
  152. if (moduleId >= modules_.size()) {
  153. throw std::runtime_error(folly::to<std::string>(
  154. "moduleId ", moduleId, "out of range [0..", modules_.size(), ")"));
  155. }
  156. return modules_[moduleId]->callSerializableNativeHook(
  157. methodId, std::move(params));
  158. }
  159. } // namespace react
  160. } // namespace facebook