forked from toyota-connected/ivi-homescreen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson_method_codec.cc
160 lines (141 loc) · 5.34 KB
/
json_method_codec.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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.
// FLUTTER_NOLINT
#include "json_method_codec.h"
#include "json_message_codec.h"
namespace flutter {
namespace {
// Keys used in MethodCall encoding.
constexpr char kMessageMethodKey[] = "method";
constexpr char kMessageArgumentsKey[] = "args";
// Returns a new document containing only |element|, which must be an element
// in |document|. This is a move rather than a copy, so it is efficient but
// destructive to the data in |document|.
std::unique_ptr<rapidjson::Document> ExtractElement(
rapidjson::Document* document,
rapidjson::Value* subtree) {
auto extracted = std::make_unique<rapidjson::Document>();
// Pull the subtree up to the root of the document.
document->Swap(*subtree);
// Swap the entire document into |extracted|. Unlike the swap above this moves
// the allocator ownership, so the data won't be deleted when |document| is
// destroyed.
extracted->Swap(*document);
return extracted;
}
} // namespace
// static
const JsonMethodCodec& JsonMethodCodec::GetInstance() {
static JsonMethodCodec sInstance;
return sInstance;
}
std::unique_ptr<MethodCall<rapidjson::Document>>
JsonMethodCodec::DecodeMethodCallInternal(const uint8_t* message,
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()) {
arguments = ExtractElement(json_message.get(), &(arguments_iter->value));
}
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().c_str(), 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.c_str(), allocator), allocator);
envelope.PushBack(rapidjson::Value(error_message.c_str(), 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);
}
bool JsonMethodCodec::DecodeAndProcessResponseEnvelopeInternal(
const uint8_t* response,
size_t response_size,
MethodResult<rapidjson::Document>* result) const {
std::unique_ptr<rapidjson::Document> json_response =
JsonMessageCodec::GetInstance().DecodeMessage(response, response_size);
if (!json_response) {
return false;
}
if (!json_response->IsArray()) {
return false;
}
switch (json_response->Size()) {
case 1: {
std::unique_ptr<rapidjson::Document> value =
ExtractElement(json_response.get(), &((*json_response)[0]));
if (value->IsNull()) {
result->Success();
} else {
result->Success(*value);
}
return true;
}
case 3: {
std::string code = (*json_response)[0].GetString();
std::string message = (*json_response)[1].GetString();
std::unique_ptr<rapidjson::Document> details =
ExtractElement(json_response.get(), &((*json_response)[2]));
if (details->IsNull()) {
result->Error(code, message);
} else {
result->Error(code, message, *details);
}
return true;
}
default:
return false;
}
}
} // namespace flutter