flutter_flutter/shell/platform/common/cpp/json_method_codec.cc
stuartmorgan 08ae3bb63e
Remove JSON codec from C++ client wrapper (#17312)
The JSON codec is awkward to use in the wrapper (since the client has to build and link one of the JSON libraries to do so). Since it would be very cumbersome to wrap in a C API, and there's essentially no reason to use it instead of the standard codec, this removes it from the wrapper entirely.

Since some system channels (internal to the engine) still use it, it's moved into common/cpp instead of being eliminated entirely. Internally we always use RapidJSON though, so the jsoncpp implementation is removed. Also adds some unit test coverage, since there wasn't any.

Fixes #30669
2020-04-02 14:57:46 -07:00

112 lines
4.3 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/common/cpp/json_method_codec.h"
#include "flutter/shell/platform/common/cpp/json_message_codec.h"
namespace flutter {
namespace {
// Keys used in MethodCall encoding.
constexpr char kMessageMethodKey[] = "method";
constexpr char kMessageArgumentsKey[] = "args";
} // namespace
// static
const JsonMethodCodec& JsonMethodCodec::GetInstance() {
static JsonMethodCodec sInstance;
return sInstance;
}
std::unique_ptr<MethodCall<rapidjson::Document>>
JsonMethodCodec::DecodeMethodCallInternal(const uint8_t* message,
const size_t message_size) const {
std::unique_ptr<rapidjson::Document> json_message =
JsonMessageCodec::GetInstance().DecodeMessage(message, message_size);
if (!json_message) {
return nullptr;
}
auto method_name_iter = json_message->FindMember(kMessageMethodKey);
if (method_name_iter == json_message->MemberEnd()) {
return nullptr;
}
if (!method_name_iter->value.IsString()) {
return nullptr;
}
std::string method_name(method_name_iter->value.GetString());
auto arguments_iter = json_message->FindMember(kMessageArgumentsKey);
std::unique_ptr<rapidjson::Document> arguments;
if (arguments_iter != json_message->MemberEnd()) {
// Pull the arguments subtree up to the root of json_message. This is
// destructive to json_message, but the full value is no longer needed, and
// this avoids a subtree copy.
// Note: The static_cast is for compatibility with RapidJSON 1.1; master
// already allows swapping a Document with a Value directly. Once there is
// a new RapidJSON release (at which point clients can be expected to have
// that change in the version they depend on) remove the cast.
static_cast<rapidjson::Value*>(json_message.get())
->Swap(arguments_iter->value);
// Swap it into |arguments|. This moves the allocator ownership, so that
// the data won't be deleted when json_message goes out of scope.
arguments = std::make_unique<rapidjson::Document>();
arguments->Swap(*json_message);
}
return std::make_unique<MethodCall<rapidjson::Document>>(
method_name, std::move(arguments));
}
std::unique_ptr<std::vector<uint8_t>> JsonMethodCodec::EncodeMethodCallInternal(
const MethodCall<rapidjson::Document>& method_call) const {
// TODO: Consider revisiting the codec APIs to avoid the need to copy
// everything when doing encoding (e.g., by having a version that takes
// owership of the object to encode, so that it can be moved instead).
rapidjson::Document message(rapidjson::kObjectType);
auto& allocator = message.GetAllocator();
rapidjson::Value name(method_call.method_name(), allocator);
rapidjson::Value arguments;
if (method_call.arguments()) {
arguments.CopyFrom(*method_call.arguments(), allocator);
}
message.AddMember(kMessageMethodKey, name, allocator);
message.AddMember(kMessageArgumentsKey, arguments, allocator);
return JsonMessageCodec::GetInstance().EncodeMessage(message);
}
std::unique_ptr<std::vector<uint8_t>>
JsonMethodCodec::EncodeSuccessEnvelopeInternal(
const rapidjson::Document* result) const {
rapidjson::Document envelope;
envelope.SetArray();
rapidjson::Value result_value;
if (result) {
result_value.CopyFrom(*result, envelope.GetAllocator());
}
envelope.PushBack(result_value, envelope.GetAllocator());
return JsonMessageCodec::GetInstance().EncodeMessage(envelope);
}
std::unique_ptr<std::vector<uint8_t>>
JsonMethodCodec::EncodeErrorEnvelopeInternal(
const std::string& error_code,
const std::string& error_message,
const rapidjson::Document* error_details) const {
rapidjson::Document envelope(rapidjson::kArrayType);
auto& allocator = envelope.GetAllocator();
envelope.PushBack(rapidjson::Value(error_code, allocator), allocator);
envelope.PushBack(rapidjson::Value(error_message, allocator), allocator);
rapidjson::Value details_value;
if (error_details) {
details_value.CopyFrom(*error_details, allocator);
}
envelope.PushBack(details_value, allocator);
return JsonMessageCodec::GetInstance().EncodeMessage(envelope);
}
} // namespace flutter