#include #include #include #include #include #include #include #include #include #include namespace fc { namespace http { namespace detail { using websocketpp::connection_hdl; typedef websocketpp::server websocket_server_type; template class websocket_connection_impl : public websocket_connection { public: websocket_connection_impl( T con ) :_ws_connection(con){} virtual void send_message( const std::string& message ) { _ws_connection->send( message ); } T _ws_connection; }; class websocket_server_impl { public: websocket_server_impl() :_server_thread( fc::thread::current() ) { _server.init_asio(&fc::asio::default_io_service()); _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ wlog( "on open server" ); auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _connections[hdl] = _factory( new_con ); }).wait(); }); _server.set_message_handler( [&]( connection_hdl hdl, websocket_server_type::message_ptr msg ){ _server_thread.async( [&](){ auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); wdump(("server")(msg->get_payload())); current_con->second->on_message( msg->get_payload() ); }).wait(); }); _server.set_close_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ _connections.erase( hdl ); }).wait(); }); _server.set_fail_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ _connections.erase( hdl ); }).wait(); }); } typedef std::map > con_map; con_map _connections; fc::thread& _server_thread; websocket_server_type _server; session_factory _factory; }; typedef websocketpp::client websocket_client_type; typedef websocket_client_type::connection_ptr websocket_client_connection_type; class websocket_client_impl { public: typedef websocket_client_type::message_ptr message_ptr; websocket_client_impl() :_client_thread( fc::thread::current() ) { _client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ elog( "default open client" ); }); _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ wlog("start wait"); _client_thread.async( [&](){ wdump((msg->get_payload())); _session->on_message( msg->get_payload() ); }).wait(); wlog("done wait"); }); _client.set_close_handler( [=]( connection_hdl hdl ){ wlog("start wait"); _client_thread.async( [&](){ _session.reset(); } ).wait(); wlog("done wait"); }); _client.set_fail_handler( [=]( connection_hdl hdl ){ wlog("start wait"); _client_thread.async( [&](){ _session.reset(); } ).wait(); wlog("done wait"); }); _client.init_asio( &fc::asio::default_io_service() ); } fc::promise::ptr _connected; fc::thread& _client_thread; websocket_client_type _client; websocket_session_ptr _session; websocket_connection_ptr _connection; }; } // namespace detail websocket_server::websocket_server():my( new detail::websocket_server_impl() ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const session_factory& factory ) { my->_factory = factory; } void websocket_server::listen( uint16_t port ) { my->_server.listen(port); } void websocket_server::start_accept() { my->_server.start_accept(); } websocket_client::websocket_client():my( new detail::websocket_client_impl() ) {} websocket_client::~websocket_client(){} websocket_session_ptr websocket_client::connect( const std::string& uri, const session_factory& factory ) { try { wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; my->_connected = fc::promise::ptr( new fc::promise("websocket::connect") ); my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ auto con = my->_client.get_con_from_hdl(hdl); my->_connection = std::make_shared>( con ); my->_session = factory( my->_connection ); my->_connected->set_value(); }); auto con = my->_client.get_connection( uri, ec ); if( ec ) { FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); } my->_client.connect(con); my->_connected->wait(); return my->_session; } FC_CAPTURE_AND_RETHROW( (uri) ) } } } // fc::http