void FlipperClient::onMessageReceived()

in xplat/Flipper/FlipperClient.cpp [162:281]


void FlipperClient::onMessageReceived(
    const dynamic& message,
    std::unique_ptr<FlipperResponder> uniqueResponder) {
  // Convert to shared pointer so we can hold on to it while passing it to the
  // plugin, and still use it to respond with an error if we catch an exception.
  std::shared_ptr<FlipperResponder> responder = std::move(uniqueResponder);
  try {
    std::unique_lock<std::mutex> lock(mutex_);
    const auto& method = message["method"];
    const auto& params = message.getDefault("params");

    if (method == "getPlugins") {
      dynamic identifiers = dynamic::array();
      for (const auto& elem : plugins_) {
        identifiers.push_back(elem.first);
      }
      dynamic response = dynamic::object("plugins", identifiers);
      responder->success(response);
      return;
    }

    if (method == "getBackgroundPlugins") {
      dynamic identifiers = dynamic::array();
      for (const auto& elem : plugins_) {
        if (elem.second->runInBackground()) {
          identifiers.push_back(elem.first);
        }
      }
      dynamic response = dynamic::object("plugins", identifiers);
      responder->success(response);
      return;
    }

    if (method == "init") {
      const auto identifier = params["plugin"].getString();
      if (plugins_.find(identifier) == plugins_.end()) {
        std::string errorMessage = "Plugin " + identifier +
            " not found for method " + method.getString();
        log(errorMessage);
        responder->error(folly::dynamic::object("message", errorMessage)(
            "name", "PluginNotFound"));
        return;
      }
      const auto plugin = plugins_.at(identifier);
      connect(plugin);
      return;
    }

    if (method == "deinit") {
      const auto identifier = params["plugin"].getString();
      if (plugins_.find(identifier) == plugins_.end()) {
        std::string errorMessage = "Plugin " + identifier +
            " not found for method " + method.getString();
        log(errorMessage);
        responder->error(folly::dynamic::object("message", errorMessage)(
            "name", "PluginNotFound"));
        return;
      }
      const auto plugin = plugins_.at(identifier);
      disconnect(plugin);
      return;
    }

    if (method == "execute") {
      const auto identifier = params["api"].getString();
      if (connections_.find(identifier) == connections_.end()) {
        std::string errorMessage = "Connection " + identifier +
            " not found for method " + method.getString();
        log(errorMessage);
        responder->error(folly::dynamic::object("message", errorMessage)(
            "name", "ConnectionNotFound"));
        return;
      }
      const auto conn = connections_.at(params["api"].getString());

      // conn->call(...) may call back to FlipperClient causing a deadlock (see
      // T92341964). Making sure the mutex is not locked.
      lock.unlock();

      conn->call(
          params["method"].getString(), params.getDefault("params"), responder);
      return;
    }

    if (method == "isMethodSupported") {
      const auto identifier = params["api"].getString();
      if (connections_.find(identifier) == connections_.end()) {
        std::string errorMessage = "Connection " + identifier +
            " not found for method " + method.getString();
        log(errorMessage);
        responder->error(folly::dynamic::object("message", errorMessage)(
            "name", "ConnectionNotFound"));
        return;
      }
      const auto& conn = connections_.at(params["api"].getString());
      bool isSupported = conn->hasReceiver(params["method"].getString());
      responder->success(dynamic::object("isSupported", isSupported));
      return;
    }

    dynamic response =
        dynamic::object("message", "Received unknown method: " + method);
    responder->error(response);
  } catch (std::exception& e) {
    log(std::string("Error: ") + e.what());
    if (responder) {
      responder->error(dynamic::object("message", e.what())(
          "stacktrace", callstack())("name", e.what()));
    }
  } catch (...) {
    log("Unknown error suppressed in FlipperClient");
    if (responder) {
      responder->error(dynamic::object(
          "message",
          "Unknown error during " + message["method"] + ". " +
              folly::toJson(message))("stacktrace", callstack())(
          "name", "Unknown"));
    }
  }
}