Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #ifndef IROHA_JSON_COMMON_HPP
7 : #define IROHA_JSON_COMMON_HPP
8 :
9 : #include <numeric>
10 : #include <string>
11 : #include <unordered_map>
12 :
13 : // Enable std::string support in rapidjson
14 : #define RAPIDJSON_HAS_STDSTRING 1
15 : #include <rapidjson/document.h>
16 : #include <rapidjson/prettywriter.h>
17 : #include <rapidjson/stringbuffer.h>
18 :
19 : #include "common/bind.hpp"
20 : #include "common/byteutils.hpp"
21 : #include "common/obj_utils.hpp"
22 : #include "model/block.hpp"
23 : #include "model/common.hpp"
24 : #include "model/queries/get_transactions.hpp"
25 : #include "model/signature.hpp"
26 :
27 : namespace iroha {
28 : namespace model {
29 : namespace converters {
30 : /**
31 : * Convert functor which specifies output type
32 : * @tparam V - output type
33 : */
34 : template <typename V>
35 : struct Convert {
36 : /**
37 : * Convert input type to defined type
38 : * @tparam T - input type
39 : * @param x - input value
40 : * @return optional of output type from input value
41 : */
42 : template <typename T>
43 : auto operator()(T &&x) const {
44 123 : return boost::optional<V>(std::forward<T>(x));
45 : }
46 : };
47 :
48 : template <size_t size>
49 : struct Convert<blob_t<size>> {
50 : template <typename T>
51 : auto operator()(T &&x) const {
52 33 : return hexstringToArray<size>(std::forward<T>(x));
53 0 : }
54 : };
55 :
56 : /**
57 : * Deserialize field from given document with given type
58 : * @tparam T - getter return type
59 : * @tparam D - document type
60 : * @param document - document value for deserialization
61 : * @param field - field name for deserialization
62 : * @return deserialized field on success, nullopt otherwise
63 : */
64 : template <typename T, typename D>
65 : boost::optional<T> deserializeField(const D &document,
66 : const std::string &field) {
67 172 : if (document.HasMember(field.c_str())
68 172 : and document[field.c_str()].template Is<T>()) {
69 172 : return document[field.c_str()].template Get<T>();
70 : }
71 4 : return boost::none;
72 172 : }
73 :
74 : /**
75 : * Functor for deserialization from given document
76 : * @tparam D - document type
77 : */
78 : template <typename D>
79 : struct FieldDeserializer {
80 : /**
81 : * @param document - document for field deserialization
82 : */
83 : explicit FieldDeserializer(const D &document) : document(document) {}
84 :
85 : /**
86 : * Create function, which deserializes document field,
87 : * transforms the value to required type, and
88 : * assigns it to block member
89 : * @tparam T - getter return type
90 : * @tparam V - block member type
91 : * @tparam B - block type
92 : * @tparam Convert - transform function type
93 : * @param member - pointer to member in block
94 : * @param field - field name for deserialization
95 : * @param transform - transform function from T to V
96 : * @return function, which takes block, returns block with deserialized
97 : * member on success, nullopt otherwise
98 : */
99 : template <typename T,
100 : typename V,
101 : typename B,
102 : typename Convert = Convert<V>>
103 : auto deserialize(V B::*member,
104 : const std::string &field,
105 : Convert transform = Convert()) {
106 : return [this, member, field, transform](auto block) {
107 55 : return deserializeField<T>(document, field) | transform
108 55 : | assignObjectField(block, member);
109 0 : };
110 : }
111 :
112 : /**
113 : * Deserialize field of Uint type to given member field of block
114 : * @tparam V - block member type
115 : * @tparam B - block type
116 : * @param member - pointer to member in block
117 : * @param field - field name for deserialization
118 : * @return @see deserialize
119 : */
120 : template <typename V, typename B>
121 : auto Uint(V B::*member, const std::string &field) {
122 9 : return deserialize<uint32_t>(member, field);
123 : }
124 :
125 : /**
126 : * Deserialize field of Uint64 type to given member field of block
127 : * @tparam V - block member type
128 : * @tparam B - block type
129 : * @param member - pointer to member in block
130 : * @param field - field name for deserialization
131 : * @return @see deserialize
132 : */
133 : template <typename V, typename B>
134 : auto Uint64(V B::*member, const std::string &field) {
135 43 : return deserialize<uint64_t>(member, field);
136 : }
137 :
138 : /**
139 : * Deserialize field of Bool type to given member field of block
140 : * @tparam V - block member type
141 : * @tparam B - block type
142 : * @param member - pointer to member in block
143 : * @param field - field name for deserialization
144 : * @return @see deserialize
145 : */
146 : template <typename V, typename B>
147 : auto Bool(V B::*member, const std::string &field) {
148 : return deserialize<bool>(member, field);
149 : }
150 :
151 : /**
152 : * Deserialize field of String type to given member field of block
153 : * @tparam V - block member type
154 : * @tparam B - block type
155 : * @param member - pointer to member in block
156 : * @param field - field name for deserialization
157 : * @return @see deserialize
158 : */
159 : template <typename V, typename B>
160 : auto String(V B::*member, const std::string &field) {
161 40 : return deserialize<std::string>(member, field);
162 : }
163 :
164 : /**
165 : * Deserialize field of String type
166 : * @param field - field name for deserialization
167 : * @return deserialized field on success, nullopt otherwise
168 : */
169 : auto String(const std::string &field) {
170 49 : return deserializeField<std::string>(document, field);
171 : }
172 :
173 : /**
174 : * Deserialize field of Array type to given member field of block,
175 : * using provided transform function
176 : * @tparam V - block member type
177 : * @tparam B - block type
178 : * @tparam Convert - transform function type
179 : * @param member - pointer to member in block
180 : * @param field - field name for deserialization
181 : * @param transform - transform function from Array to V
182 : * @return @see deserialize
183 : */
184 : template <typename V, typename B, typename Convert = Convert<V>>
185 : auto Array(V B::*member,
186 : const std::string &field,
187 : Convert transform = Convert()) {
188 7 : return deserialize<rapidjson::Value::ConstArray>(
189 7 : member, field, transform);
190 : }
191 :
192 : /**
193 : * Deserialize field of Object type to given member field of block
194 : * @tparam V - block member type
195 : * @tparam B - block type
196 : * @param member - pointer to member in block
197 : * @param field - field name for deserialization
198 : * @return @see deserialize
199 : */
200 : template <typename V, typename B, typename Convert = Convert<V>>
201 : auto Object(V B::*member,
202 : const std::string &field,
203 : Convert transform = Convert()) {
204 21 : return deserialize<rapidjson::Value::ConstObject>(
205 21 : member, field, transform);
206 : }
207 :
208 : // document for deserialization
209 : const D &document;
210 : };
211 :
212 : /**
213 : * Factory method for FieldDeserializer functor
214 : * @tparam D - document type
215 : * @param document - document for deserialization
216 : * @return FieldDeserializer instance for given arguments
217 : */
218 : template <typename D>
219 : auto makeFieldDeserializer(const D &document) {
220 100 : return FieldDeserializer<D>(document);
221 : }
222 :
223 : template <>
224 : struct Convert<Signature> {
225 : template <typename T>
226 : auto operator()(T &&x) const {
227 19 : auto des = makeFieldDeserializer(std::forward<T>(x));
228 19 : return boost::make_optional(Signature())
229 19 : | des.String(&Signature::pubkey, "pubkey")
230 19 : | des.String(&Signature::signature, "signature");
231 0 : }
232 : };
233 :
234 : template <>
235 : struct Convert<Block::SignaturesType> {
236 : template <typename T>
237 : auto operator()(T &&x) const {
238 : auto acc_signatures = [](auto init, auto &x) {
239 : return init | [&x](auto signatures) {
240 : return Convert<Signature>()(x) | [&signatures](auto signature) {
241 2 : signatures.push_back(signature);
242 2 : return boost::make_optional(std::move(signatures));
243 : };
244 0 : };
245 : };
246 3 : return std::accumulate(x.begin(),
247 3 : x.end(),
248 3 : boost::make_optional(Block::SignaturesType()),
249 : acc_signatures);
250 0 : }
251 : };
252 :
253 : template <>
254 : struct Convert<GetTransactions::TxHashCollectionType> {
255 : template <typename T>
256 : auto operator()(T &&x) const {
257 : auto acc_hashes = [](auto init, auto &x) {
258 : return init | [&x](auto tx_hashes)
259 : -> boost::optional<
260 : GetTransactions::TxHashCollectionType> {
261 : // If invalid type included, returns nullopt
262 4 : if (not x.IsString()) {
263 0 : return boost::none;
264 : }
265 : auto tx_hash_opt =
266 4 : Convert<GetTransactions::TxHashType>()(x.GetString());
267 4 : if (not tx_hash_opt) {
268 : // If the the hash is wrong, just skip.
269 1 : return boost::make_optional(std::move(tx_hashes));
270 : }
271 : return tx_hash_opt | [&tx_hashes](auto tx_hash) {
272 3 : tx_hashes.push_back(tx_hash);
273 3 : return boost::make_optional(std::move(tx_hashes));
274 : };
275 4 : };
276 : };
277 3 : return std::accumulate(
278 3 : x.begin(),
279 3 : x.end(),
280 3 : boost::make_optional(GetTransactions::TxHashCollectionType()),
281 : acc_hashes);
282 0 : }
283 : };
284 :
285 : /**
286 : * Serialize signature to JSON with given allocator
287 : * @param signature - signature for serialization
288 : * @param allocator - allocator for JSON value
289 : * @return JSON value with signature
290 : */
291 : rapidjson::Value serializeSignature(
292 : const Signature &signature,
293 : rapidjson::Document::AllocatorType &allocator);
294 :
295 : /**
296 : * Try to parse JSON from string
297 : * @param string - string for parsing
298 : * @return JSON document on success, nullopt otherwise
299 : */
300 : boost::optional<rapidjson::Document> stringToJson(
301 : const std::string &string);
302 :
303 : /**
304 : * Pretty print JSON document to string
305 : * @param document - document for printing
306 : * @return pretty printed JSON document
307 : */
308 : std::string jsonToString(const rapidjson::Document &document);
309 : } // namespace converters
310 : } // namespace model
311 : } // namespace iroha
312 :
313 : #endif // IROHA_JSON_COMMON_HPP
|