Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed JSONRPC error handling #135

Merged
merged 2 commits into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/fc/exception/exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ namespace fc
aes_error_code = 18,
overflow_code = 19,
underflow_code = 20,
divide_by_zero_code = 21
divide_by_zero_code = 21,
method_not_found_exception_code = 22
};

/**
Expand Down Expand Up @@ -273,6 +274,7 @@ namespace fc
FC_DECLARE_EXCEPTION( key_not_found_exception, key_not_found_exception_code, "Key Not Found" );
FC_DECLARE_EXCEPTION( bad_cast_exception, bad_cast_exception_code, "Bad Cast" );
FC_DECLARE_EXCEPTION( out_of_range_exception, out_of_range_exception_code, "Out of Range" );
FC_DECLARE_EXCEPTION( method_not_found_exception, method_not_found_exception_code, "Method Not Found" );

/** @brief if an operation is unsupported or not valid this may be thrown */
FC_DECLARE_EXCEPTION( invalid_operation_exception,
Expand Down
4 changes: 3 additions & 1 deletion include/fc/network/http/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace fc {
enum status_code {
OK = 200,
RecordCreated = 201,
NoContent = 204,
BadRequest = 400,
NotAuthorized = 401,
NotFound = 404,
Expand All @@ -35,6 +36,7 @@ namespace fc {
int status;
std::vector<header> headers;
std::vector<char> body;
std::string body_as_string;
};

struct request
Expand Down Expand Up @@ -79,4 +81,4 @@ namespace fc {

#include <fc/reflect/reflect.hpp>
FC_REFLECT( fc::http::header, (key)(val) )

FC_REFLECT( fc::http::reply, (status)(headers)(body)(body_as_string) )
9 changes: 5 additions & 4 deletions include/fc/network/http/websocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>
#include <boost/any.hpp>
#include <fc/network/ip.hpp>
#include <fc/network/http/connection.hpp>
#include <fc/signals.hpp>

namespace fc { namespace http {
Expand All @@ -12,7 +13,7 @@ namespace fc { namespace http {
class websocket_tls_server_impl;
class websocket_client_impl;
class websocket_tls_client_impl;
} // namespace detail;
} // namespace detail

class websocket_connection
{
Expand All @@ -21,10 +22,10 @@ namespace fc { namespace http {
virtual void send_message( const std::string& message ) = 0;
virtual void close( int64_t code, const std::string& reason ){};
void on_message( const std::string& message ) { _on_message(message); }
string on_http( const std::string& message ) { return _on_http(message); }
fc::http::reply on_http( const std::string& message ) { return _on_http(message); }

void on_message_handler( const std::function<void(const std::string&)>& h ) { _on_message = h; }
void on_http_handler( const std::function<std::string(const std::string&)>& h ) { _on_http = h; }
void on_http_handler( const std::function<fc::http::reply(const std::string&)>& h ) { _on_http = h; }

void set_session_data( boost::any d ){ _session_data = std::move(d); }
boost::any& get_session_data() { return _session_data; }
Expand All @@ -35,7 +36,7 @@ namespace fc { namespace http {
private:
boost::any _session_data;
std::function<void(const std::string&)> _on_message;
std::function<string(const std::string&)> _on_http;
std::function<fc::http::reply(const std::string&)> _on_http;
};
typedef std::shared_ptr<websocket_connection> websocket_connection_ptr;

Expand Down
8 changes: 6 additions & 2 deletions include/fc/rpc/api_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,17 @@ namespace fc {
variant call( const string& name, const variants& args )
{
auto itr = _by_name.find(name);
FC_ASSERT( itr != _by_name.end(), "no method with name '${name}'", ("name",name)("api",_by_name) );
if( itr == _by_name.end() )
FC_THROW_EXCEPTION( method_not_found_exception, "No method with name '${name}'",
("name",name)("api",_by_name) );
return call( itr->second, args );
}

variant call( uint32_t method_id, const variants& args )
{
FC_ASSERT( method_id < _methods.size() );
if( method_id >= _methods.size() )
FC_THROW_EXCEPTION( method_not_found_exception, "No method with id '${id}'",
("id",method_id)("api",_by_name) );
return _methods[method_id](args);
}

Expand Down
27 changes: 15 additions & 12 deletions include/fc/rpc/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
namespace fc { namespace rpc {
struct request
{
optional<uint64_t> id;
optional<variant> id;
std::string method;
variants params;
optional<std::string> jsonrpc;
};

struct error_object
Expand All @@ -20,13 +21,15 @@ namespace fc { namespace rpc {

struct response
{
response(){}
response( int64_t i, fc::variant r ):id(i),result(r){}
response( int64_t i, error_object r ):id(i),error(r){}
response( int64_t i, fc::variant r, string j ):id(i),jsonrpc(j),result(r){}
response( int64_t i, error_object r, string j ):id(i),jsonrpc(j),error(r){}
int64_t id = 0;
optional<std::string> jsonrpc;
response() {}
response( const optional<variant>& _id, const variant& _result,
const optional<string>& version = optional<string>() )
: id(_id), jsonrpc(version), result(_result) {}
response( const optional<variant>& _id, const error_object& error,
const optional<string>& version = optional<string>() )
: id(_id), jsonrpc(version), error(error) {}
optional<variant> id;
optional<std::string> jsonrpc;
optional<fc::variant> result;
optional<error_object> error;
};
Expand All @@ -44,20 +47,20 @@ namespace fc { namespace rpc {
void handle_reply( const response& response );

request start_remote_call( const string& method_name, variants args );
variant wait_for_response( uint64_t request_id );
variant wait_for_response( const variant& request_id );

void close();

void on_unhandled( const std::function<variant(const string&,const variants&)>& unhandled );

private:
uint64_t _next_id = 1;
std::unordered_map<uint64_t, fc::promise<variant>::ptr> _awaiting;
std::map<variant, fc::promise<variant>::ptr> _awaiting;
std::unordered_map<std::string, method> _methods;
std::function<variant(const string&,const variants&)> _unhandled;
std::function<variant(const string&,const variants&)> _unhandled;
};
} } // namespace fc::rpc

FC_REFLECT( fc::rpc::request, (id)(method)(params) );
FC_REFLECT( fc::rpc::request, (id)(method)(params)(jsonrpc) );
FC_REFLECT( fc::rpc::error_object, (code)(message)(data) )
FC_REFLECT( fc::rpc::response, (id)(jsonrpc)(result)(error) )
10 changes: 4 additions & 6 deletions include/fc/rpc/websocket_api.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#pragma once
#include <fc/network/http/websocket.hpp>
#include <fc/rpc/api_connection.hpp>
#include <fc/rpc/state.hpp>
#include <fc/network/http/websocket.hpp>
#include <fc/io/json.hpp>
#include <fc/reflect/variant.hpp>

namespace fc { namespace rpc {

Expand All @@ -26,9 +24,9 @@ namespace fc { namespace rpc {
variants args = variants() ) override;

protected:
std::string on_message(
const std::string& message,
bool send_message = true );
response on_message( const std::string& message );
response on_request( const variant& message );
void on_response( const variant& message );

std::shared_ptr<fc::http::websocket_connection> _connection;
fc::rpc::state _rpc_state;
Expand Down
10 changes: 5 additions & 5 deletions include/fc/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,11 +658,11 @@ namespace fc
variant operator - ( const variant& a, const variant& b );
variant operator * ( const variant& a, const variant& b );
variant operator / ( const variant& a, const variant& b );
variant operator == ( const variant& a, const variant& b );
variant operator != ( const variant& a, const variant& b );
variant operator < ( const variant& a, const variant& b );
variant operator > ( const variant& a, const variant& b );
variant operator ! ( const variant& a );
bool operator == ( const variant& a, const variant& b );
bool operator != ( const variant& a, const variant& b );
bool operator < ( const variant& a, const variant& b );
bool operator > ( const variant& a, const variant& b );
bool operator ! ( const variant& a );
} // namespace fc

#include <fc/reflect/reflect.hpp>
Expand Down
15 changes: 9 additions & 6 deletions src/network/http/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
#endif

#include <fc/io/json.hpp>
#include <fc/optional.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/rpc/websocket_api.hpp>
#include <fc/variant.hpp>
#include <fc/thread/thread.hpp>
#include <fc/asio.hpp>
Expand Down Expand Up @@ -239,10 +242,10 @@ namespace fc { namespace http {
wdump(("server")(request_body));

fc::async([current_con, request_body, con] {
std::string response = current_con->on_http(request_body);
idump((response));
con->set_body( response );
con->set_status( websocketpp::http::status_code::ok );
fc::http::reply response = current_con->on_http(request_body);
idump( (response) );
con->set_body( std::move( response.body_as_string ) );
con->set_status( websocketpp::http::status_code::value(response.status) );
con->send_http_response();
current_con->closed();
}, "call on_http");
Expand Down Expand Up @@ -364,8 +367,8 @@ namespace fc { namespace http {
wdump(("server")(con->get_request_body()));
auto response = current_con->on_http( con->get_request_body() );
idump((response));
con->set_body( response );
con->set_status( websocketpp::http::status_code::ok );
con->set_body( std::move( response.body_as_string ) );
con->set_status( websocketpp::http::status_code::value( response.status ) );
} catch ( const fc::exception& e )
{
edump((e.to_detail_string()));
Expand Down
5 changes: 3 additions & 2 deletions src/rpc/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ variant state::local_call( const string& method_name, const variants& args )

void state::handle_reply( const response& response )
{
auto await = _awaiting.find( response.id );
FC_ASSERT( response.id, "Response without ID: ${response}", ("response",response) );
auto await = _awaiting.find( *response.id );
FC_ASSERT( await != _awaiting.end(), "Unknown Response ID: ${id}", ("id",response.id)("response",response) );
if( response.result )
await->second->set_value( *response.result );
Expand All @@ -48,7 +49,7 @@ request state::start_remote_call( const string& method_name, variants args )
_awaiting[*request.id] = fc::promise<variant>::ptr( new fc::promise<variant>("json_connection::async_call") );
return request;
}
variant state::wait_for_response( uint64_t request_id )
variant state::wait_for_response( const variant& request_id )
{
auto itr = _awaiting.find(request_id);
FC_ASSERT( itr != _awaiting.end() );
Expand Down
Loading