#include #include #include #include #include namespace fc { FC_REGISTER_EXCEPTIONS( (timeout_exception) (file_not_found_exception) (parse_error_exception) (invalid_arg_exception) (invalid_operation_exception) (key_not_found_exception) (bad_cast_exception) (out_of_range_exception) (canceled_exception) (assert_exception) (eof_exception) ) namespace detail { class exception_impl { public: std::string _name; std::string _what; int64_t _code; log_messages _elog; }; } unhandled_exception::unhandled_exception( log_message&& m, std::exception_ptr e ) :exception( fc::move(m) ) { _inner = e; } unhandled_exception::unhandled_exception( const exception& r ) :exception(r) { } unhandled_exception::unhandled_exception( log_messages m ) :exception() { my->_elog = fc::move(m); } std::exception_ptr unhandled_exception::get_inner_exception()const { return _inner; } NO_RETURN void unhandled_exception::dynamic_rethrow_exception()const { if( !(_inner == std::exception_ptr()) ) std::rethrow_exception( _inner ); else { fc::exception::dynamic_rethrow_exception(); } } std::shared_ptr unhandled_exception::dynamic_copy_exception()const { auto e = std::make_shared( *this ); e->_inner = _inner; return e; } exception::exception( int64_t code, const std::string& name_value, const std::string& what_value ) :my( new detail::exception_impl() ) { my->_code = code; my->_what = what_value; my->_name = name_value; } exception::exception( log_message&& msg, int64_t code, const std::string& name_value, const std::string& what_value ) :my( new detail::exception_impl() ) { my->_code = code; my->_what = what_value; my->_name = name_value; my->_elog.push_back( fc::move( msg ) ); } exception::exception( const exception& c ) :my( new detail::exception_impl(*c.my) ) { } exception::exception( exception&& c ) :my( fc::move(c.my) ){} const char* exception::name()const throw() { return my->_name.c_str(); } const char* exception::what()const throw() { return my->_what.c_str(); } int64_t exception::code()const throw() { return my->_code; } exception::~exception(){} void to_variant( const exception& e, variant& v ) { v = mutable_variant_object( "code", e.code() ) ( "name", e.name() ) ( "message", e.what() ) ( "stack", e.get_log() ); } void from_variant( const variant& v, exception& ll ) { auto obj = v.get_object(); if( obj.contains( "stack" ) ) ll.my->_elog = obj["stack"].as(); if( obj.contains( "code" ) ) ll.my->_code = obj["code"].as_int64(); if( obj.contains( "name" ) ) ll.my->_name = obj["name"].as_string(); if( obj.contains( "message" ) ) ll.my->_what = obj["message"].as_string(); } const log_messages& exception::get_log()const { return my->_elog; } void exception::append_log( log_message m ) { my->_elog.emplace_back( fc::move(m) ); } /** * Generates a detailed string including file, line, method, * and other information that is generally only useful for * developers. */ string exception::to_detail_string( log_level ll )const { fc::stringstream ss; ss << variant(my->_code).as_string() <<"\n"; for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) { ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; ss << " " << json::to_string( itr->get_data() )<<"\n"; ss << " " << itr->get_context().to_string(); ++itr; if( itr != my->_elog.end() ) ss<<"\n"; } return ss.str(); } /** * Generates a user-friendly error report. */ string exception::to_string( log_level ll )const { fc::stringstream ss; ss << what() << "(" << variant(my->_code).as_string() <<")\n"; for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr ) { ss << fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; // ss << " " << itr->get_context().to_string() <<"\n"; } return ss.str(); } void NO_RETURN exception_factory::rethrow( const exception& e )const { auto itr = _registered_exceptions.find( e.code() ); if( itr != _registered_exceptions.end() ) itr->second->rethrow( e ); throw e; } /** * Rethrows the exception restoring the proper type based upon * the error code. This is used to propagate exception types * across conversions to/from JSON */ NO_RETURN void exception::dynamic_rethrow_exception()const { exception_factory::instance().rethrow( *this ); } exception_ptr exception::dynamic_copy_exception()const { return std::make_shared(*this); } fc::string except_str() { return boost::current_exception_diagnostic_information(); } void throw_bad_enum_cast( int64_t i, const char* e ) { FC_THROW_EXCEPTION( bad_cast_exception, "invalid index '${key}' in enum '${enum}'", ("key",i)("enum",e) ); } void throw_bad_enum_cast( const char* k, const char* e ) { FC_THROW_EXCEPTION( bad_cast_exception, "invalid name '${key}' in enum '${enum}'", ("key",k)("enum",e) ); } } // fc