2018-12-27 18:50:45 +03:00
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
# pragma once
# include "serialization/keyvalue_serialization.h"
# include "storages/portable_storage_template_helper.h"
# include "http_base.h"
2023-05-24 23:43:44 +02:00
# include "net/net_utils_base.h"
2024-03-21 22:57:55 +01:00
# include "storages/portable_storage_extended_for_doc.h"
2018-12-27 18:50:45 +03:00
2022-07-31 22:59:29 +02:00
2024-04-09 22:52:41 +02:00
namespace epee
{
namespace json_rpc
{
template < typename t_param >
struct request
{
std : : string jsonrpc ;
std : : string method ;
epee : : serialization : : storage_entry id ;
t_param params ;
BEGIN_KV_SERIALIZE_MAP ( )
2024-04-22 23:28:36 +04:00
KV_SERIALIZE ( jsonrpc ) DOC_DSCR ( " " ) DOC_EXMP ( " 2.0 " ) DOC_END
2024-04-09 22:52:41 +02:00
KV_SERIALIZE ( id )
KV_SERIALIZE ( method )
KV_SERIALIZE ( params )
END_KV_SERIALIZE_MAP ( )
} ;
struct error
{
int64_t code ;
std : : string message ;
BEGIN_KV_SERIALIZE_MAP ( )
KV_SERIALIZE ( code )
KV_SERIALIZE ( message )
END_KV_SERIALIZE_MAP ( )
} ;
struct dummy_error
{
BEGIN_KV_SERIALIZE_MAP ( )
END_KV_SERIALIZE_MAP ( )
} ;
struct dummy_result
{
BEGIN_KV_SERIALIZE_MAP ( )
END_KV_SERIALIZE_MAP ( )
} ;
template < typename t_param , typename t_error >
struct response
{
std : : string jsonrpc ;
t_param result ;
epee : : serialization : : storage_entry id ;
t_error error ;
BEGIN_KV_SERIALIZE_MAP ( )
KV_SERIALIZE ( jsonrpc )
KV_SERIALIZE ( id )
KV_SERIALIZE ( result )
KV_SERIALIZE ( error )
END_KV_SERIALIZE_MAP ( )
} ;
template < typename t_param >
struct response < t_param , dummy_error >
{
std : : string jsonrpc ;
t_param result ;
epee : : serialization : : storage_entry id ;
BEGIN_KV_SERIALIZE_MAP ( )
2024-04-22 23:28:36 +04:00
KV_SERIALIZE ( jsonrpc ) DOC_DSCR ( " " ) DOC_EXMP ( " 2.0 " ) DOC_END
2024-04-09 22:52:41 +02:00
KV_SERIALIZE ( id )
KV_SERIALIZE ( result )
END_KV_SERIALIZE_MAP ( )
} ;
template < typename t_error >
struct response < dummy_result , t_error >
{
std : : string jsonrpc ;
std : : string method ;
t_error error ;
epee : : serialization : : storage_entry id ;
BEGIN_KV_SERIALIZE_MAP ( )
KV_SERIALIZE ( jsonrpc )
KV_SERIALIZE ( method )
KV_SERIALIZE ( id )
KV_SERIALIZE ( error )
END_KV_SERIALIZE_MAP ( )
} ;
typedef response < dummy_result , error > error_response ;
}
}
2022-07-31 22:59:29 +02:00
template < typename typename_t >
typename_t get_documentation_json_struct ( )
{
return AUTO_VAL_INIT_T ( typename_t ) ;
}
2024-04-09 22:52:41 +02:00
struct documentation_entry
{
std : : string uri ;
bool is_binary = false ; //if not - then it's JSON
std : : string json_method_name ;
std : : string request_json_example ;
std : : string request_json_descriptions ;
std : : string response_json_example ;
std : : string response_json_descriptions ;
std : : string method_general_decription ;
} ;
2024-03-28 12:49:43 +01:00
2024-04-09 22:52:41 +02:00
struct documentation
2018-12-27 18:50:45 +03:00
{
2024-04-09 22:52:41 +02:00
bool do_generate_documentation = false ;
std : : list < documentation_entry > entries ;
} ;
// Primary template
template < typename T >
struct has_static_member_description {
private :
// SFINAE test function
template < typename U >
static auto test ( int ) - > decltype ( U : : description , std : : true_type { } ) ;
2018-12-27 18:50:45 +03:00
2024-04-09 22:52:41 +02:00
// Fallback function
template < typename >
static auto test ( . . . ) - > std : : false_type ;
public :
// Member constant indicating whether T has a static member
static constexpr bool value = decltype ( test < T > ( 0 ) ) : : value ;
} ;
template < typename T >
const char * get_command_description ( )
2018-12-27 18:50:45 +03:00
{
2024-04-09 22:52:41 +02:00
if constexpr ( has_static_member_description < T > : : value )
{
return T : : description ;
}
else
{
return " NO DESCRIPTION " ;
}
}
template < typename T >
void f ( T ) { } // Definition #2
2024-04-22 23:28:36 +04:00
// Base template
template < typename T >
struct is_std_simple_container : std : : false_type { } ;
// Specializations for each container
template < typename T , typename Alloc >
struct is_std_simple_container < std : : vector < T , Alloc > > : std : : true_type { } ;
template < typename T , typename Alloc >
struct is_std_simple_container < std : : deque < T , Alloc > > : std : : true_type { } ;
template < typename T , typename Alloc >
struct is_std_simple_container < std : : list < T , Alloc > > : std : : true_type { } ;
template < typename T , std : : size_t N >
struct is_std_simple_container < std : : array < T , N > > : std : : true_type { } ;
2024-04-09 22:52:41 +02:00
template < typename command_type_t , bool is_json_rpc_method >
bool auto_doc ( const std : : string & uri , const std : : string & method , bool is_json , documentation & docs )
{
if ( ! docs . do_generate_documentation ) return true ;
docs . entries . resize ( docs . entries . size ( ) + 1 ) ;
docs . entries . back ( ) . is_binary = ! is_json ;
2024-04-10 14:17:07 +02:00
docs . entries . back ( ) . uri = uri ;
2024-04-09 22:52:41 +02:00
docs . entries . back ( ) . json_method_name = method ;
docs . entries . back ( ) . method_general_decription = get_command_description < command_type_t > ( ) ;
if constexpr ( is_json_rpc_method )
{
//json rpc-like call
typedef typename epee : : json_rpc : : request < typename command_type_t : : request > request_t ;
2024-04-22 23:28:36 +04:00
typedef typename epee : : json_rpc : : response < typename command_type_t : : response , typename epee : : json_rpc : : dummy_error > response_t ;
2024-04-09 22:52:41 +02:00
request_t req = AUTO_VAL_INIT ( req ) ; //get_documentation_json_struct<request_t>();
2024-04-22 23:28:36 +04:00
if constexpr ( is_std_simple_container < typename command_type_t : : request > : : value )
{
req . params . resize ( 1 ) ;
}
response_t res = AUTO_VAL_INIT ( res ) ;
if constexpr ( is_std_simple_container < typename command_type_t : : response > : : value )
{
req . result . resize ( 1 ) ;
}
2024-04-09 22:52:41 +02:00
2024-04-22 23:28:36 +04:00
req . method = method ;
2024-04-09 22:52:41 +02:00
epee : : serialization : : portable_storage_extended_doc ps ;
req . store ( ps , nullptr ) ;
ps . dump_as_json ( docs . entries . back ( ) . request_json_example ) ;
ps . dump_as_decriptions ( docs . entries . back ( ) . request_json_descriptions ) ;
epee : : serialization : : portable_storage_extended_doc ps_res ;
res . store ( ps_res , nullptr ) ;
ps_res . dump_as_json ( docs . entries . back ( ) . response_json_example ) ;
ps_res . dump_as_decriptions ( docs . entries . back ( ) . response_json_descriptions ) ;
}
else
{
//json/bin uri/based
2024-04-10 12:16:45 +02:00
typedef typename command_type_t : : request request_t ;
typedef typename command_type_t : : response response_t ;
2024-04-09 22:52:41 +02:00
request_t req = AUTO_VAL_INIT ( req ) ; //get_documentation_json_struct<request_t>();
response_t res = AUTO_VAL_INIT ( res ) ; //get_documentation_json_struct<response_t>();
epee : : serialization : : portable_storage_extended_doc ps ;
req . store ( ps , nullptr ) ;
ps . dump_as_json ( docs . entries . back ( ) . request_json_example ) ;
ps . dump_as_decriptions ( docs . entries . back ( ) . request_json_descriptions ) ;
epee : : serialization : : portable_storage_extended_doc ps_res ;
res . store ( ps_res , nullptr ) ;
ps_res . dump_as_json ( docs . entries . back ( ) . response_json_example ) ;
ps_res . dump_as_decriptions ( docs . entries . back ( ) . response_json_descriptions ) ;
}
// std::stringstream ss;
// ss << prefix_name << ENDL
// << "REQUEST: " << ENDL << req_str << ENDL << req_str_descr << "--------------------------------" << ENDL
// << "RESPONSE: " << ENDL << res_str << ENDL << res_str_descr << "################################" << ENDL;
// generate_reference += ss.str();
return true ;
//return auto_doc_t<typename command_type_t::request, typename command_type_t::response>(prefix_name, generate_reference);
2018-12-27 18:50:45 +03:00
}
2023-05-24 23:43:44 +02:00
namespace epee {
namespace net_utils {
namespace http {
struct i_chain_handler
{
2024-10-23 20:05:03 +04:00
virtual bool handle_http_request ( const epee : : net_utils : : http : : http_request_info & query_info , epee : : net_utils : : http : : http_response_info & response_info ,
epee : : net_utils : : connection_context_base & conn_context , bool & call_found , documentation & docs = epee : : net_utils : : http : : i_chain_handler : : m_empty_documentation )
{
return this - > handle_http_request_map ( query_info , response_info , conn_context , call_found , docs ) ;
}
2023-05-24 23:43:44 +02:00
virtual bool handle_http_request_map ( const epee : : net_utils : : http : : http_request_info & query_info , epee : : net_utils : : http : : http_response_info & response_info ,
2024-04-10 13:33:37 +02:00
epee : : net_utils : : connection_context_base & m_conn_context , bool & call_found , documentation & docs = epee : : net_utils : : http : : i_chain_handler : : m_empty_documentation ) = 0 ;
2024-10-23 20:05:03 +04:00
2024-04-10 13:33:37 +02:00
static inline documentation m_empty_documentation ;
2023-05-24 23:43:44 +02:00
} ;
}
}
}
2018-12-27 18:50:45 +03:00
# define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
epee : : net_utils : : http : : http_response_info & response , \
context_type & m_conn_context ) \
{ \
response . m_response_code = 200 ; \
response . m_response_comment = " Ok " ; \
bool call_found = false ; \
2024-04-09 22:52:41 +02:00
if ( ! handle_http_request_map ( query_info , response , m_conn_context , call_found ) & & response . m_response_code = = 200 ) \
2018-12-27 18:50:45 +03:00
{ response . m_response_code = 500 ; response . m_response_comment = " Internal Server Error " ; return true ; } \
if ( ! call_found ) \
{ response . m_response_code = 404 ; response . m_response_comment = " Not Found " ; return true ; } \
return true ; \
}
# define BEGIN_URI_MAP2() template<class t_context> bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee : : net_utils : : http : : http_response_info & response_info , \
2024-04-10 13:33:37 +02:00
t_context & m_conn_context , bool & call_found , documentation & docs = epee : : net_utils : : http : : i_chain_handler : : m_empty_documentation ) { \
2018-12-27 18:50:45 +03:00
call_found = false ; \
if ( false ) return true ; //just a stub to have "else if"
2023-05-24 23:43:44 +02:00
# define BEGIN_URI_MAP2_VIRTUAL() virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee : : net_utils : : http : : http_response_info & response_info , \
2024-04-10 13:33:37 +02:00
epee : : net_utils : : connection_context_base & m_conn_context , bool & call_found , documentation & docs = epee : : net_utils : : http : : i_chain_handler : : m_empty_documentation ) { \
2023-05-24 23:43:44 +02:00
call_found = false ; \
if ( false ) return true ; //just a stub to have "else if"
2018-12-27 18:50:45 +03:00
# define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context);
# define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
# define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \
2024-04-09 22:52:41 +02:00
else if ( auto_doc < command_type , false > ( s_pattern , " " , true , docs ) & & query_info . m_URI = = s_pattern ) \
2018-12-27 18:50:45 +03:00
{ \
call_found = true ; \
uint64_t ticks = misc_utils : : get_tick_count ( ) ; \
boost : : value_initialized < command_type : : request > req ; \
bool res = epee : : serialization : : load_t_from_json ( static_cast < command_type : : request & > ( req ) , query_info . m_body ) ; \
CHECK_AND_ASSERT_MES ( res , false , " Failed to parse json: \r \n " < < query_info . m_body ) ; \
uint64_t ticks1 = epee : : misc_utils : : get_tick_count ( ) ; \
boost : : value_initialized < command_type : : response > resp ; \
res = callback_f ( static_cast < command_type : : request & > ( req ) , static_cast < command_type : : response & > ( resp ) , m_conn_context ) ; \
CHECK_AND_ASSERT_MES ( res , false , " Failed to call " < < # callback_f < < " () while handling " < < s_pattern ) ; \
uint64_t ticks2 = epee : : misc_utils : : get_tick_count ( ) ; \
epee : : serialization : : store_t_to_json ( static_cast < command_type : : response & > ( resp ) , response_info . m_body ) ; \
uint64_t ticks3 = epee : : misc_utils : : get_tick_count ( ) ; \
response_info . m_mime_tipe = " application/json " ; \
response_info . m_header_info . m_content_type = " application/json " ; \
LOG_PRINT ( " [HTTP/JSON][ " < < epee : : string_tools : : get_ip_string_from_int32 ( m_conn_context . m_remote_ip ) < < " ][ " < < query_info . m_URI < < " ] processed with " < < ticks1 - ticks < < " / " < < ticks2 - ticks1 < < " / " < < ticks3 - ticks2 < < " ms " , LOG_LEVEL_2 ) ; \
}
# define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \
2024-04-09 22:52:41 +02:00
else if ( auto_doc < command_type , false > ( s_pattern , " " , false , docs ) & & query_info . m_URI = = s_pattern ) \
2018-12-27 18:50:45 +03:00
{ \
call_found = true ; \
uint64_t ticks = misc_utils : : get_tick_count ( ) ; \
boost : : value_initialized < command_type : : request > req ; \
bool res = epee : : serialization : : load_t_from_binary ( static_cast < command_type : : request & > ( req ) , query_info . m_body ) ; \
CHECK_AND_ASSERT_MES ( res , false , " Failed to parse bin body data, body size= " < < query_info . m_body . size ( ) ) ; \
uint64_t ticks1 = misc_utils : : get_tick_count ( ) ; \
boost : : value_initialized < command_type : : response > resp ; \
res = callback_f ( static_cast < command_type : : request & > ( req ) , static_cast < command_type : : response & > ( resp ) , m_conn_context ) ; \
CHECK_AND_ASSERT_MES ( res , false , " Failed to call " < < # callback_f < < " () while handling " < < s_pattern ) ; \
uint64_t ticks2 = misc_utils : : get_tick_count ( ) ; \
epee : : serialization : : store_t_to_binary ( static_cast < command_type : : response & > ( resp ) , response_info . m_body ) ; \
uint64_t ticks3 = epee : : misc_utils : : get_tick_count ( ) ; \
response_info . m_mime_tipe = " application/octet-stream " ; \
response_info . m_header_info . m_content_type = " application/octet-stream " ; \
LOG_PRINT ( " [HTTP/BIN][ " < < epee : : string_tools : : get_ip_string_from_int32 ( m_conn_context . m_remote_ip ) < < " ][ " < < query_info . m_URI < < " ] processed with " < < ticks1 - ticks < < " / " < < ticks2 - ticks1 < < " / " < < ticks3 - ticks2 < < " ms " , LOG_LEVEL_2 ) ; \
}
2024-10-23 20:05:03 +04:00
# define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request(query_info, response_info, m_conn_context, call_found, docs) && call_found) { return true;}
2023-05-24 23:43:44 +02:00
2018-12-27 18:50:45 +03:00
# define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;}
# define END_URI_MAP2() return true;}
2024-04-09 22:52:41 +02:00
//template<typename command_type_t>
//struct json_command_type_t
//{
// typedef typename epee::json_rpc::request<typename command_type_t::request> request;
// typedef typename epee::json_rpc::request<typename command_type_t::response> response;
//};
2018-12-27 18:50:45 +03:00
2024-04-09 22:52:41 +02:00
//#define JSON_RPC_REFERENCE_MARKER "JSON_RPC"
2018-12-27 18:50:45 +03:00
2024-04-09 22:52:41 +02:00
/ / if ( query_info . m_URI = = JSON_RPC_REFERENCE_MARKER ) { generate_reference = " JSON RPC URL: " uri " \n " ; } \
2018-12-27 18:50:45 +03:00
2024-04-09 22:52:41 +02:00
# define BEGIN_JSON_RPC_MAP(uri) else if(docs.do_generate_documentation || query_info.m_URI == uri) \
2018-12-27 18:50:45 +03:00
{ \
2024-04-09 22:52:41 +02:00
const char * current_zone_json_uri = uri ; \
2018-12-27 18:50:45 +03:00
LOG_PRINT_L4 ( " [JSON_REQUEST_BODY]: " < < ENDL < < query_info . m_body ) ; \
uint64_t ticks = epee : : misc_utils : : get_tick_count ( ) ; \
epee : : serialization : : portable_storage ps ; \
if ( ! ps . load_from_json ( query_info . m_body ) ) \
{ \
boost : : value_initialized < epee : : json_rpc : : error_response > rsp ; \
static_cast < epee : : json_rpc : : error_response & > ( rsp ) . error . code = - 32700 ; \
static_cast < epee : : json_rpc : : error_response & > ( rsp ) . error . message = " Parse error " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( rsp ) , response_info . m_body ) ; \
return true ; \
} \
epee : : serialization : : storage_entry id_ ; \
id_ = epee : : serialization : : storage_entry ( std : : string ( ) ) ; \
ps . get_value ( " id " , id_ , nullptr ) ; \
std : : string callback_name ; \
if ( ! ps . get_value ( " method " , callback_name , nullptr ) ) \
{ \
epee : : json_rpc : : error_response rsp ; \
rsp . jsonrpc = " 2.0 " ; \
rsp . error . code = - 32600 ; \
rsp . error . message = " Invalid Request " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( rsp ) , response_info . m_body ) ; \
return true ; \
} \
if ( false ) return true ; //just a stub to have "else if"
# define PREPARE_OBJECTS_FROM_JSON(command_type) \
call_found = true ; \
boost : : value_initialized < epee : : json_rpc : : request < command_type : : request > > req_ ; \
epee : : json_rpc : : request < command_type : : request > & req = static_cast < epee : : json_rpc : : request < command_type : : request > & > ( req_ ) ; \
if ( ! req . load ( ps ) ) \
{ \
epee : : json_rpc : : error_response fail_resp = AUTO_VAL_INIT ( fail_resp ) ; \
fail_resp . jsonrpc = " 2.0 " ; \
fail_resp . id = req . id ; \
fail_resp . error . code = - 32602 ; \
fail_resp . error . message = " Invalid params " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( fail_resp ) , response_info . m_body ) ; \
return true ; \
} \
uint64_t ticks1 = epee : : misc_utils : : get_tick_count ( ) ; \
boost : : value_initialized < epee : : json_rpc : : response < command_type : : response , epee : : json_rpc : : dummy_error > > resp_ ; \
epee : : json_rpc : : response < command_type : : response , epee : : json_rpc : : dummy_error > & resp = static_cast < epee : : json_rpc : : response < command_type : : response , epee : : json_rpc : : dummy_error > & > ( resp_ ) ; \
resp . jsonrpc = " 2.0 " ; \
resp . id = req . id ;
# define FINALIZE_OBJECTS_TO_JSON(method_name) \
uint64_t ticks2 = epee : : misc_utils : : get_tick_count ( ) ; \
epee : : serialization : : store_t_to_json ( resp , response_info . m_body ) ; \
uint64_t ticks3 = epee : : misc_utils : : get_tick_count ( ) ; \
response_info . m_mime_tipe = " application/json " ; \
response_info . m_header_info . m_content_type = " application/json " ; \
LOG_PRINT ( query_info . m_URI < < " [ " < < method_name < < " ] processed with " < < ticks1 - ticks < < " / " < < ticks2 - ticks1 < < " / " < < ticks3 - ticks2 < < " ms " , LOG_LEVEL_2 ) ;
# define MAP_JON_RPC_WE(method_name, callback_f, command_type) \
2024-04-09 22:52:41 +02:00
else if ( auto_doc < command_type , true > ( current_zone_json_uri , method_name , true , docs ) & & callback_name = = method_name ) \
2018-12-27 18:50:45 +03:00
{ \
2023-05-24 23:43:44 +02:00
call_found = true ; \
2018-12-27 18:50:45 +03:00
PREPARE_OBJECTS_FROM_JSON ( command_type ) \
epee : : json_rpc : : error_response fail_resp = AUTO_VAL_INIT ( fail_resp ) ; \
fail_resp . jsonrpc = " 2.0 " ; \
2020-02-03 18:00:41 +01:00
fail_resp . method = req . method ; \
2018-12-27 18:50:45 +03:00
fail_resp . id = req . id ; \
if ( ! callback_f ( req . params , resp . result , fail_resp . error , m_conn_context ) ) \
{ \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( fail_resp ) , response_info . m_body ) ; \
return true ; \
} \
FINALIZE_OBJECTS_TO_JSON ( method_name ) \
return true ; \
}
# define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \
2024-04-09 22:52:41 +02:00
else if ( auto_doc < command_type , true > ( current_zone_json_uri , method_name , true , docs ) & & callback_name = = method_name ) \
2018-12-27 18:50:45 +03:00
{ \
2023-05-24 23:43:44 +02:00
call_found = true ; \
2018-12-27 18:50:45 +03:00
PREPARE_OBJECTS_FROM_JSON ( command_type ) \
epee : : json_rpc : : error_response fail_resp = AUTO_VAL_INIT ( fail_resp ) ; \
fail_resp . jsonrpc = " 2.0 " ; \
2020-02-03 18:00:41 +01:00
fail_resp . method = req . method ; \
2018-12-27 18:50:45 +03:00
fail_resp . id = req . id ; \
if ( ! callback_f ( req . params , resp . result , fail_resp . error , m_conn_context , response_info ) ) \
{ \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( fail_resp ) , response_info . m_body ) ; \
return true ; \
} \
FINALIZE_OBJECTS_TO_JSON ( method_name ) \
return true ; \
}
# define MAP_JON_RPC(method_name, callback_f, command_type) \
2024-04-09 22:52:41 +02:00
else if ( auto_doc < command_type , true > ( current_zone_json_uri , method_name , true , docs ) & & callback_name = = method_name ) \
2025-07-15 14:30:55 +04:00
{ \
call_found = true ; \
PREPARE_OBJECTS_FROM_JSON ( command_type ) \
if ( ! callback_f ( req . params , resp . result , m_conn_context ) ) \
{ \
epee : : json_rpc : : error_response fail_resp = AUTO_VAL_INIT ( fail_resp ) ; \
fail_resp . jsonrpc = " 2.0 " ; \
fail_resp . method = req . method ; \
fail_resp . id = req . id ; \
fail_resp . error . code = - 32603 ; \
fail_resp . error . message = " Internal error " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( fail_resp ) , response_info . m_body ) ; \
return true ; \
} \
FINALIZE_OBJECTS_TO_JSON ( method_name ) \
return true ; \
}
# define MAP_JON_RPC_CONDITIONAL(method_name, callback_f, command_type, predicate) \
else if ( predicate & & auto_doc < command_type , true > ( current_zone_json_uri , method_name , true , docs ) & & callback_name = = method_name ) \
2018-12-27 18:50:45 +03:00
{ \
2023-05-24 23:43:44 +02:00
call_found = true ; \
2018-12-27 18:50:45 +03:00
PREPARE_OBJECTS_FROM_JSON ( command_type ) \
if ( ! callback_f ( req . params , resp . result , m_conn_context ) ) \
{ \
epee : : json_rpc : : error_response fail_resp = AUTO_VAL_INIT ( fail_resp ) ; \
fail_resp . jsonrpc = " 2.0 " ; \
2020-02-08 18:36:31 +03:00
fail_resp . method = req . method ; \
2018-12-27 18:50:45 +03:00
fail_resp . id = req . id ; \
fail_resp . error . code = - 32603 ; \
fail_resp . error . message = " Internal error " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( fail_resp ) , response_info . m_body ) ; \
return true ; \
} \
FINALIZE_OBJECTS_TO_JSON ( method_name ) \
return true ; \
}
# define MAP_JON_RPC_N(callback_f, command_type) MAP_JON_RPC(command_type::methodname(), callback_f, command_type)
# define END_JSON_RPC_MAP() \
epee : : json_rpc : : error_response rsp ; \
rsp . id = id_ ; \
rsp . jsonrpc = " 2.0 " ; \
2020-02-03 18:19:54 +01:00
rsp . method = callback_name ; \
2018-12-27 18:50:45 +03:00
rsp . error . code = - 32601 ; \
rsp . error . message = " Method not found " ; \
epee : : serialization : : store_t_to_json ( static_cast < epee : : json_rpc : : error_response & > ( rsp ) , response_info . m_body ) ; \
LOG_PRINT_L4 ( " [JSON_RESPONSE_BODY]: " < < ENDL < < query_info . m_body ) ; \
return true ; \
}
2024-04-10 13:19:19 +02:00
namespace epee
{
template < typename t_rpc_server >
2025-03-31 15:37:21 +04:00
bool generate_doc_as_md_files ( const std : : string & folder , t_rpc_server & server , const std : : string & sufix = std : : string ( ) )
2024-04-10 13:19:19 +02:00
{
LOG_PRINT_L0 ( " Dumping RPC auto-generated documents! " ) ;
epee : : net_utils : : http : : http_request_info query_info ;
epee : : net_utils : : http : : http_response_info response_info ;
epee : : net_utils : : connection_context_base conn_context ;
//std::string generate_reference = std::string("WALLET_RPC_COMMANDS_LIST:\n");
bool call_found = false ;
documentation docs ;
docs . do_generate_documentation = true ;
// query_info.m_URI = JSON_RPC_REFERENCE_MARKER;
query_info . m_body = " { \" jsonrpc \" : \" 2.0 \" , \" method \" : \" nonexisting_method \" , \" params \" : {}}, " ;
server . handle_http_request_map ( query_info , response_info , conn_context , call_found , docs ) ;
for ( const auto & de : docs . entries )
{
std : : stringstream ss ;
2024-04-10 14:47:28 +02:00
ss < < de . method_general_decription < < ENDL < < ENDL ; ;
2024-04-10 13:19:19 +02:00
ss < < " URL: ```http:://127.0.0.1:11211 " < < de . uri < < " ``` " < < ENDL ;
ss < < " ### Request: " < < ENDL < < " ```json " < < ENDL < < de . request_json_example < < ENDL < < " ``` " < < ENDL ;
ss < < " ### Request description: " < < ENDL < < " ``` " < < ENDL < < de . request_json_descriptions < < ENDL < < " ``` " < < ENDL ;
ss < < " ### Response: " < < ENDL < < " ```json " < < ENDL < < de . response_json_example < < ENDL < < " ``` " < < ENDL ;
ss < < " ### Response description: " < < ENDL < < " ``` " < < ENDL < < de . response_json_descriptions < < ENDL < < " ``` " < < ENDL ;
2025-03-31 15:37:21 +04:00
ss < < sufix ;
2025-03-31 15:22:14 +04:00
2024-04-10 13:19:19 +02:00
std : : string filename = de . json_method_name ;
if ( ! filename . size ( ) )
{
filename = de . uri ;
2024-04-10 14:17:07 +02:00
if ( filename . front ( ) = = ' / ' )
filename . erase ( filename . begin ( ) ) ;
2024-04-10 13:19:19 +02:00
}
filename + = " .md " ;
bool r = epee : : file_io_utils : : save_string_to_file ( folder + " / " + filename , ss . str ( ) ) ;
if ( ! r )
{
LOG_ERROR ( " Failed to save file " < < filename ) ;
return false ;
}
}
return true ;
}
}