26 #include <boost/algorithm/string/join.hpp>
31 static size_t curl_write_function(
void *contents,
size_t size,
size_t nmemb,
void *userp)
33 ((std::string*)userp)->append((
char*)contents, size * nmemb);
39 static bool handle_bulk_response( uint16_t http_code,
const std::string& curl_read_buffer )
45 bool errors = j[
"errors"].
as_bool();
48 elog(
"ES returned 200 but with errors: ${e}", (
"e", curl_read_buffer) );
56 elog(
"413 error: Request too large. Can be low disk space. ${e}", (
"e", curl_read_buffer) );
60 elog(
"401 error: Unauthorized. ${e}", (
"e", curl_read_buffer) );
64 elog(
"${code} error: ${e}", (
"code",
std::to_string(http_code)) (
"e", curl_read_buffer) );
71 std::vector<std::string> bulk;
73 final_bulk_header[
"index"] = bulk_header;
75 bulk.emplace_back(std::move(data));
85 CURL* curl_wrapper::init_curl()
87 CURL* curl = curl_easy_init();
90 curl_easy_setopt( curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 );
96 curl_slist* curl_wrapper::init_request_headers()
98 curl_slist* request_headers = curl_slist_append( NULL,
"Content-Type: application/json" );
99 FC_ASSERT( request_headers,
"Unable to init cURL request headers" );
100 return request_headers;
105 curl_easy_setopt( curl.get(), CURLOPT_HTTPHEADER, request_headers.get() );
106 curl_easy_setopt( curl.get(), CURLOPT_USERAGENT,
"bitshares-core/6.1" );
109 void curl_wrapper::curl_deleter::operator()( CURL* p_curl )
const
112 curl_easy_cleanup( p_curl );
115 void curl_wrapper::curl_slist_deleter::operator()( curl_slist* slist )
const
118 curl_slist_free_all( slist );
122 const std::string& url,
123 const std::string& auth,
124 const std::string& query )
const
132 curl_easy_setopt( curl.get(), CURLOPT_URL, url.c_str() );
134 curl_easy_setopt( curl.get(), CURLOPT_USERPWD, auth.c_str() );
137 static const std::vector<std::string> http_request_method_custom_str = {
146 const auto& custom_request = http_request_method_custom_str[
static_cast<size_t>(method)];
147 const auto* p_custom_request = custom_request.empty() ? NULL : custom_request.c_str();
148 curl_easy_setopt( curl.get(), CURLOPT_CUSTOMREQUEST, p_custom_request );
153 curl_easy_setopt( curl.get(), CURLOPT_HTTPGET,
false );
154 curl_easy_setopt( curl.get(), CURLOPT_POST,
true );
155 curl_easy_setopt( curl.get(), CURLOPT_POSTFIELDS, query.c_str() );
159 curl_easy_setopt( curl.get(), CURLOPT_POSTFIELDS, NULL );
160 curl_easy_setopt( curl.get(), CURLOPT_POST,
false );
161 curl_easy_setopt( curl.get(), CURLOPT_HTTPGET,
true );
164 curl_easy_setopt( curl.get(), CURLOPT_WRITEFUNCTION, curl_write_function );
165 curl_easy_setopt( curl.get(), CURLOPT_WRITEDATA, (
void *)(&resp.
content) );
166 curl_easy_perform( curl.get() );
169 curl_easy_getinfo( curl.get(), CURLINFO_RESPONSE_CODE, &code );
170 resp.
code =
static_cast<uint16_t
>( code );
186 const std::string& query )
const
192 const std::string& query )
const
199 const auto response = curl.get( base_url +
"_nodes", auth );
202 return !response.content.empty();
207 const auto response = curl.get( base_url, auth );
208 if( !response.is_200() )
209 FC_THROW(
"Error on es_client::get_version(): code = ${code}, message = ${message} ",
210 (
"code", response.code) (
"message", response.content) );
213 return content[
"version"][
"number"].
as_string();
218 static const int64_t version_7 = 7;
220 const auto es_version = get_version();
221 ilog(
"ES version detected: ${v}", (
"v", es_version) );
222 auto dot_pos = es_version.find(
'.');
223 result = ( std::stoi(es_version.substr(0,dot_pos)) >= version_7 );
227 wlog(
"Unable to get ES version, assuming it is 7 or above" );
234 auto bulk_str = boost::algorithm::join( bulk_lines,
"\n" ) +
"\n";
235 const auto response = curl.post( base_url +
"_bulk", auth, bulk_str );
237 return handle_bulk_response( response.code, response.content );
242 const auto response = curl.del( base_url + path, auth );
245 return !response.content.empty();
250 const auto response = curl.get( base_url + path, auth );
253 return response.content;
258 const auto response = curl.post( base_url + path, auth, query );
261 return response.content;
280 static const std::unordered_set<std::string> to_string_array_fields = {
"account_auths",
"address_auths",
294 static const std::unordered_map<std::string, data_type> to_string_fields = {
295 {
"parameters", data_type::array_type },
296 {
"op", data_type::static_variant_type },
297 {
"proposed_ops", data_type::array_type },
298 {
"operations", data_type::array_type },
299 {
"initializer", data_type::static_variant_type },
300 {
"policy", data_type::static_variant_type },
301 {
"predicates", data_type::array_type },
302 {
"active_special_authority", data_type::static_variant_type },
303 {
"owner_special_authority", data_type::static_variant_type },
304 {
"htlc_preimage_hash", data_type::static_variant_type },
305 {
"argument", data_type::static_variant_type },
306 {
"feeds", data_type::map_type },
307 {
"acceptable_collateral", data_type::map_type },
308 {
"acceptable_borrowers", data_type::map_type },
309 {
"on_fill", data_type::array_type }
311 std::vector<std::pair<std::string, fc::variants>> original_arrays;
312 std::vector<std::string> keys_to_rename;
315 const std::string& name = i.key();
316 auto& element = i.value();
317 if( element.is_object() )
319 const auto& vo = element.get_object();
320 if( vo.contains(name.c_str()) )
321 keys_to_rename.emplace_back(name);
322 element = adapt( vo, max_depth - 1 );
326 if( !element.is_array() )
329 auto& array = element.get_array();
330 if( to_string_fields.find(name) != to_string_fields.end() )
334 original_arrays.emplace_back( name, array );
337 else if( to_string_array_fields.find(name) != to_string_array_fields.end() )
343 original_arrays.emplace_back( name, std::move( backup ) );
345 in_situ_adapt( array, max_depth - 1 );
348 in_situ_adapt( array, max_depth - 1 );
351 for(
const auto& i : keys_to_rename )
353 std::string new_name = i +
"_";
358 if( o.find(
"nonce") != o.end() )
360 o[
"nonce"] = o[
"nonce"].as_string();
363 if( o.find(
"owner") != o.end() && o[
"owner"].is_string() )
365 o[
"owner_"] = o[
"owner"].as_string();
369 for(
const auto& pair : original_arrays )
371 const auto& name = pair.first;
372 auto& value = pair.second;
373 auto type = data_type::map_type;
374 if( to_string_fields.find(name) != to_string_fields.end() )
375 type = to_string_fields.at(name);
376 o[name +
"_object"] = adapt( value, type, max_depth - 1 );
386 if( data_type::static_variant_type == type )
387 return adapt_static_variant( v, max_depth );
391 vs.reserve( v.size() );
392 for(
const auto& item : v )
394 if( item.is_array() )
396 if( data_type::map_type == type )
397 vs.push_back( adapt_map_item( item.get_array(), max_depth ) );
399 vs.push_back( adapt_static_variant( item.get_array(), max_depth ) );
401 else if( item.is_object() )
402 vs.push_back( adapt( item.get_object(), max_depth ) );
404 wlog(
"Type of item is unexpected: ${item}", (
"item", item) );
415 FC_ASSERT( max_depth > 0,
"Internal error" );
417 mv[prefix +
"_object"] = adapt( v.
get_object(), max_depth - 1 );
419 mv[prefix +
"_int"] = v;
421 mv[prefix +
"_bool"] = v;
440 FC_ASSERT( v.size() == 2,
"Internal error" );
443 extract_data_from_variant( v[0], mv,
"key", max_depth );
444 extract_data_from_variant( v[1], mv,
"data", max_depth );
460 FC_ASSERT( v.size() == 2,
"Internal error" );
464 extract_data_from_variant( v[1], mv,
"data", max_depth );
473 for(
auto& array_element : v )
475 if( array_element.is_object() )
476 array_element = adapt( array_element.get_object(), max_depth );
477 else if( array_element.is_array() )
478 in_situ_adapt( array_element.get_array(), max_depth );
480 array_element = array_element.as_string();