mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
201 lines
7.5 KiB
C++
201 lines
7.5 KiB
C++
/*
|
|
* Copyright (c) 2011, Peter Thorson. 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 WebSocket++ Project 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 PETER THORSON 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|
|
#define WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|
|
|
|
#include "../../src/sockets/tls.hpp"
|
|
#include "../../src/websocketpp.hpp"
|
|
|
|
#include "broadcast_handler.hpp"
|
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
|
|
#include <map>
|
|
#include <set>
|
|
#include <sstream>
|
|
|
|
namespace websocketpp {
|
|
namespace broadcast {
|
|
|
|
template <typename endpoint_type>
|
|
class admin_handler : public endpoint_type::handler {
|
|
public:
|
|
typedef admin_handler<endpoint_type> type;
|
|
typedef boost::shared_ptr<type> ptr;
|
|
typedef typename endpoint_type::handler_ptr handler_ptr;
|
|
typedef typename handler<endpoint_type>::ptr broadcast_handler_ptr;
|
|
typedef typename endpoint_type::connection_ptr connection_ptr;
|
|
|
|
admin_handler()
|
|
: m_epoch(boost::posix_time::time_from_string("1970-01-01 00:00:00.000"))
|
|
{}
|
|
|
|
void on_open(connection_ptr connection) {
|
|
if (!m_timer) {
|
|
m_timer.reset(new boost::asio::deadline_timer(connection->get_io_service(),boost::posix_time::seconds(0)));
|
|
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
|
m_timer->async_wait(boost::bind(&type::on_timer,this,boost::asio::placeholders::error));
|
|
}
|
|
|
|
m_connections.insert(connection);
|
|
}
|
|
|
|
// this dummy tls init function will cause all TLS connections to fail.
|
|
// TLS handling for broadcast::handler is usually done by a lobby handler.
|
|
// If you want to use the broadcast handler alone with TLS then return the
|
|
// appropriately filled in context here.
|
|
boost::shared_ptr<boost::asio::ssl::context> on_tls_init() {
|
|
return boost::shared_ptr<boost::asio::ssl::context>();
|
|
}
|
|
|
|
void on_load(connection_ptr connection, handler_ptr old_handler) {
|
|
this->on_open(connection);
|
|
m_lobby = old_handler;
|
|
}
|
|
|
|
void track(broadcast_handler_ptr target) {
|
|
m_broadcast_handler = target;
|
|
}
|
|
|
|
void on_close(connection_ptr connection) {
|
|
m_connections.erase(connection);
|
|
}
|
|
|
|
void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {
|
|
typename std::set<connection_ptr>::iterator it;
|
|
|
|
wscmd::cmd command = wscmd::parse(msg->get_payload());
|
|
|
|
if (command.command == "close") {
|
|
handle_close(connection,command);
|
|
} else {
|
|
command_error(connection,"Invalid Command");
|
|
}
|
|
}
|
|
|
|
void command_error(connection_ptr connection,const std::string msg) {
|
|
std::string str = "{\"type\":\"error\",\"value\":\""+msg+"\"}";
|
|
connection->send(str);
|
|
}
|
|
|
|
// close: - close this connection
|
|
// close:all; close all connections
|
|
void handle_close(connection_ptr connection,const wscmd::cmd& command) {
|
|
if (!m_broadcast_handler) {
|
|
// Unable to connect to local broadcast handler
|
|
return;
|
|
}
|
|
|
|
m_broadcast_handler->close_connection(connection_ptr());
|
|
}
|
|
|
|
long get_ms(boost::posix_time::ptime s) const {
|
|
boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
|
|
boost::posix_time::time_period period(s,now);
|
|
return period.length().total_milliseconds();
|
|
}
|
|
|
|
void on_timer(const boost::system::error_code& error) {
|
|
if (!m_broadcast_handler) {
|
|
// Unable to connect to local broadcast handler
|
|
return;
|
|
}
|
|
|
|
if (m_connections.size() > 0) {
|
|
long milli_seconds = get_ms(m_epoch);
|
|
|
|
std::stringstream update;
|
|
update << "{\"type\":\"stats\""
|
|
<< ",\"timestamp\":" << milli_seconds
|
|
<< ",\"connections\":" << m_broadcast_handler->get_connection_count()
|
|
<< ",\"admin_connections\":" << m_connections.size()
|
|
<< ",\"messages\":[";
|
|
|
|
const msg_map& m = m_broadcast_handler->get_message_stats();
|
|
|
|
msg_map::const_iterator msg_it;
|
|
msg_map::const_iterator last = m.end();
|
|
if (m.size() > 0) {
|
|
last--;
|
|
}
|
|
|
|
for (msg_it = m.begin(); msg_it != m.end(); msg_it++) {
|
|
update << "{\"id\":" << (*msg_it).second.id
|
|
<< ",\"hash\":\"" << (*msg_it).second.hash << "\""
|
|
<< ",\"sent\":" << (*msg_it).second.sent
|
|
<< ",\"acked\":" << (*msg_it).second.acked
|
|
<< ",\"size\":" << (*msg_it).second.size
|
|
<< ",\"time\":" << (*msg_it).second.time
|
|
<< "}" << (msg_it == last ? "" : ",");
|
|
}
|
|
|
|
update << "]}";
|
|
|
|
m_broadcast_handler->clear_message_stats();
|
|
|
|
typename std::set<connection_ptr>::iterator it;
|
|
|
|
websocketpp::message::data_ptr msg = (*m_connections.begin())->get_data_message();
|
|
|
|
if (msg) {
|
|
msg->reset(frame::opcode::TEXT);
|
|
|
|
msg->set_payload(update.str());
|
|
|
|
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
|
(*it)->send(msg);
|
|
}
|
|
} else {
|
|
// error no avaliable message buffers
|
|
}
|
|
}
|
|
|
|
m_timer->expires_from_now(boost::posix_time::milliseconds(250));
|
|
m_timer->async_wait(
|
|
boost::bind(
|
|
&type::on_timer,
|
|
this,
|
|
boost::asio::placeholders::error
|
|
)
|
|
);
|
|
}
|
|
private:
|
|
handler_ptr m_lobby;
|
|
broadcast_handler_ptr m_broadcast_handler;
|
|
|
|
std::set<connection_ptr> m_connections;
|
|
boost::posix_time::ptime m_epoch;
|
|
|
|
boost::shared_ptr<boost::asio::deadline_timer> m_timer;
|
|
};
|
|
|
|
} // namespace broadcast
|
|
} // namespace websocketpp
|
|
|
|
#endif // WEBSOCKETPP_BROADCAST_ADMIN_HANDLER_HPP
|