Add requestResponse handler for incoming calls

Summary:
Flipper exposes a call() api to plugins which lets them call their sdk component, and it returns a promise with the response.
Currently this is done by sending a fireAndForget request, noting the id of the request, and then receiving fireAndForget requests and matching up the ids to give the result back to the right plugin promise.

Instead, it will be simpler to use rsocket requestResponse, instead of fireAndForget, which is for this exact use case. This diff adds a requestResponse handler to the SDK, so that it can deal with such requests and respond accordingly, while preserving the current functionality if it receives a fireAndForget.

So this part is backwards compatible and should be safe to land in isolation.

A later diff will change the desktop app to use requestResponse, which may not be backwards compatible, so that will have to be deployed more carefully.

Reviewed By: passy

Differential Revision: D13974049

fbshipit-source-id: b371d94a86b1f186375161ed8f2242a462ce418f
This commit is contained in:
John Knox
2019-02-11 14:01:31 -08:00
committed by Facebook Github Bot
parent 8f6138a41c
commit 4a3de26a88
15 changed files with 486 additions and 284 deletions

View File

@@ -10,6 +10,7 @@
#include <stdexcept>
#include <vector>
#include "ConnectionContextStore.h"
#include "FireAndForgetBasedFlipperResponder.h"
#include "FlipperConnectionImpl.h"
#include "FlipperConnectionManagerImpl.h"
#include "FlipperResponderImpl.h"
@@ -154,18 +155,17 @@ void FlipperClient::onDisconnected() {
});
}
void FlipperClient::onMessageReceived(const dynamic& message) {
performAndReportError([this, &message]() {
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::lock_guard<std::mutex> lock(mutex_);
const auto& method = message["method"];
const auto& params = message.getDefault("params");
std::unique_ptr<FlipperResponderImpl> responder;
if (message.find("id") != message.items().end()) {
responder.reset(
new FlipperResponderImpl(socket_.get(), message["id"].getInt()));
}
if (method == "getPlugins") {
dynamic identifiers = dynamic::array();
for (const auto& elem : plugins_) {
@@ -179,9 +179,12 @@ void FlipperClient::onMessageReceived(const dynamic& message) {
if (method == "init") {
const auto identifier = params["plugin"].getString();
if (plugins_.find(identifier) == plugins_.end()) {
throw std::out_of_range(
"plugin " + identifier + " not found for method " +
method.getString());
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);
if (!plugin.get()->runInBackground()) {
@@ -196,9 +199,12 @@ void FlipperClient::onMessageReceived(const dynamic& message) {
if (method == "deinit") {
const auto identifier = params["plugin"].getString();
if (plugins_.find(identifier) == plugins_.end()) {
throw std::out_of_range(
"plugin " + identifier + " not found for method " +
method.getString());
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);
if (!plugin.get()->runInBackground()) {
@@ -210,23 +216,42 @@ void FlipperClient::onMessageReceived(const dynamic& message) {
if (method == "execute") {
const auto identifier = params["api"].getString();
if (connections_.find(identifier) == connections_.end()) {
throw std::out_of_range(
"connection " + identifier + " not found for method " +
method.getString());
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(
params["method"].getString(),
params.getDefault("params"),
std::move(responder));
responder);
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"));
}
}
}
std::string FlipperClient::callstack() {
#if __APPLE__
// For some iOS apps, __Unwind_Backtrace symbol wasn't found in sandcastle