Add basic inbound tunnel information to webui.

This commit is contained in:
EinMByte 2015-09-18 21:37:21 +02:00
parent 19557a0908
commit f04f556b75
5 changed files with 212 additions and 1 deletions

View File

@ -24,6 +24,64 @@ namespace i2p {
namespace client { namespace client {
namespace i2pcontrol { namespace i2pcontrol {
JsonObject::JsonObject(const std::string& value)
: children(), value("\"" + value + "\"")
{
}
JsonObject::JsonObject(int value)
: children(), value(std::to_string(value))
{
}
JsonObject::JsonObject(double v)
: children(), value()
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(2) << v;
value = oss.str();
}
JsonObject& JsonObject::operator[](const std::string& key)
{
return children[key];
}
std::string JsonObject::toString() const
{
if(children.empty())
return value;
std::ostringstream oss;
oss << '{';
for(auto it = children.begin(); it != children.end(); ++it) {
if(it != children.begin())
oss << ',';
oss << '"' << it->first << "\":" << it->second.toString();
}
oss << '}';
return oss.str();
}
JsonObject tunnelToJsonObject(i2p::tunnel::Tunnel* tunnel)
{
JsonObject obj;
std::stringstream ss;
tunnel->GetTunnelConfig()->Print(ss); // TODO: use a JsonObject
obj["layout"] = JsonObject(ss.str());
const auto state = tunnel->GetState();
if(state == i2p::tunnel::eTunnelStateFailed)
obj["state"] = JsonObject("failed");
else if(state == i2p::tunnel::eTunnelStateExpiring)
obj["state"] = JsonObject("expiring");
return obj;
}
I2PControlSession::Response::Response(const std::string& version) I2PControlSession::Response::Response(const std::string& version)
: id(), version(version), error(ErrorCode::None), parameters() : id(), version(version), error(ErrorCode::None), parameters()
{ {
@ -92,6 +150,11 @@ void I2PControlSession::Response::setParam(const std::string& param, double valu
parameters[param] = oss.str(); parameters[param] = oss.str();
} }
void I2PControlSession::Response::setParam(const std::string& param, const JsonObject& value)
{
parameters[param] = value.toString();
}
void I2PControlSession::Response::setError(ErrorCode code) void I2PControlSession::Response::setError(ErrorCode code)
{ {
error = code; error = code;
@ -126,6 +189,8 @@ I2PControlSession::I2PControlSession(boost::asio::io_service& ios, const std::st
routerInfoHandlers[ROUTER_INFO_NET_STATUS] = &I2PControlSession::handleNetStatus; routerInfoHandlers[ROUTER_INFO_NET_STATUS] = &I2PControlSession::handleNetStatus;
routerInfoHandlers[ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlSession::handleTunnelsParticipating; routerInfoHandlers[ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlSession::handleTunnelsParticipating;
routerInfoHandlers[ROUTER_INFO_TUNNELS_CREATION_SUCCESS] = &I2PControlSession::handleTunnelsCreationSuccess; routerInfoHandlers[ROUTER_INFO_TUNNELS_CREATION_SUCCESS] = &I2PControlSession::handleTunnelsCreationSuccess;
routerInfoHandlers[ROUTER_INFO_TUNNELS_IN_LIST] = &I2PControlSession::handleTunnelsInList;
routerInfoHandlers[ROUTER_INFO_TUNNELS_OUT_LIST] = &I2PControlSession::handleTunnelsOutList;
routerInfoHandlers[ROUTER_INFO_BW_IB_1S] = &I2PControlSession::handleInBandwidth1S; routerInfoHandlers[ROUTER_INFO_BW_IB_1S] = &I2PControlSession::handleInBandwidth1S;
routerInfoHandlers[ROUTER_INFO_BW_OB_1S] = &I2PControlSession::handleOutBandwidth1S; routerInfoHandlers[ROUTER_INFO_BW_OB_1S] = &I2PControlSession::handleOutBandwidth1S;
@ -368,6 +433,33 @@ void I2PControlSession::handleTunnelsCreationSuccess(Response& response)
); );
} }
void I2PControlSession::handleTunnelsInList(Response& response)
{
JsonObject list;
for(auto pair : i2p::tunnel::tunnels.GetInboundTunnels()) {
const std::string id = std::to_string(pair.first);
list[id] = tunnelToJsonObject(pair.second.get());
list[id]["bytes"] = JsonObject(
static_cast<int>(pair.second->GetNumReceivedBytes())
);
}
response.setParam(constants::ROUTER_INFO_TUNNELS_IN_LIST, list);
}
void I2PControlSession::handleTunnelsOutList(Response& response)
{
JsonObject list;
for(auto tunnel : i2p::tunnel::tunnels.GetOutboundTunnels()) {
const std::string id = std::to_string(tunnel->GetTunnelID());
list[id] = tunnelToJsonObject(tunnel.get());
list[id]["bytes"] = JsonObject(
static_cast<int>(tunnel->GetNumSentBytes())
);
}
response.setParam(constants::ROUTER_INFO_TUNNELS_OUT_LIST, list);
}
void I2PControlSession::handleInBandwidth1S(Response& response) void I2PControlSession::handleInBandwidth1S(Response& response)
{ {
response.setParam( response.setParam(

View File

@ -9,6 +9,10 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
namespace i2p { namespace i2p {
// Forward declaration
namespace tunnel { class Tunnel; }
namespace client { namespace client {
namespace i2pcontrol { namespace i2pcontrol {
@ -54,7 +58,10 @@ const char ROUTER_INFO_NETDB_FLOODFILLS[] = "i2p.router.netdb.floodfills";
const char ROUTER_INFO_NETDB_LEASESETS[] = "i2p.router.netdb.leasesets"; const char ROUTER_INFO_NETDB_LEASESETS[] = "i2p.router.netdb.leasesets";
const char ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; const char ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
const char ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; const char ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
// TODO: Probably better to use the standard GetRate instead
const char ROUTER_INFO_TUNNELS_CREATION_SUCCESS[] = "i2p.router.net.tunnels.creationsuccessrate"; const char ROUTER_INFO_TUNNELS_CREATION_SUCCESS[] = "i2p.router.net.tunnels.creationsuccessrate";
const char ROUTER_INFO_TUNNELS_IN_LIST[] = "i2p.router.net.tunnels.inbound.list";
const char ROUTER_INFO_TUNNELS_OUT_LIST[] = "i2p.router.net.tunnels.outbound.list";
const char ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; const char ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
const char ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; const char ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
@ -65,6 +72,32 @@ const char ROUTER_MANAGER_RESEED[] = "Reseed";
} // constants } // constants
/**
* Represents a Json object, provides functionality to convert to string.
*/
class JsonObject {
public:
JsonObject() = default;
JsonObject(const std::string& value);
JsonObject(int value);
JsonObject(double value);
JsonObject& operator[](const std::string& key);
std::string toString() const;
private:
std::map<std::string, JsonObject> children;
std::string value;
};
JsonObject tunnelToJsonObject(i2p::tunnel::Tunnel* tunnel);
/** /**
* "Null" I2P control implementation, does not do actual networking. * "Null" I2P control implementation, does not do actual networking.
* @note authentication tokens are per-session * @note authentication tokens are per-session
@ -106,9 +139,22 @@ public:
* @todo escape quotes * @todo escape quotes
*/ */
void setParam(const std::string& param, const std::string& value); void setParam(const std::string& param, const std::string& value);
/**
* Set an ouptut parameter to a specified integer.
*/
void setParam(const std::string& param, int value); void setParam(const std::string& param, int value);
/**
* Set an ouptut parameter to a specified double.
*/
void setParam(const std::string& param, double value); void setParam(const std::string& param, double value);
/**
* Set an ouptut parameter to a specified Json object.
*/
void setParam(const std::string& param, const JsonObject& value);
void setError(ErrorCode code); void setError(ErrorCode code);
void setId(const std::string& identifier); void setId(const std::string& identifier);
@ -187,8 +233,12 @@ private:
void handleNetDbFloodfills(Response& response); void handleNetDbFloodfills(Response& response);
void handleNetDbLeaseSets(Response& response); void handleNetDbLeaseSets(Response& response);
void handleNetStatus(Response& response); void handleNetStatus(Response& response);
void handleTunnelsParticipating(Response& response); void handleTunnelsParticipating(Response& response);
void handleTunnelsCreationSuccess(Response& response); void handleTunnelsCreationSuccess(Response& response);
void handleTunnelsInList(Response& response);
void handleTunnelsOutList(Response& response);
void handleInBandwidth1S(Response& response); void handleInBandwidth1S(Response& response);
void handleOutBandwidth1S(Response& response); void handleOutBandwidth1S(Response& response);

View File

@ -232,7 +232,7 @@ std::string getMimeType(const std::string& filename)
const std::string ext = filename.substr(filename.find_last_of(".")); const std::string ext = filename.substr(filename.find_last_of("."));
if(ext == ".css") if(ext == ".css")
return "text/css"; return "text/css";
else if(ext == ".css") else if(ext == ".js")
return "text/javascript"; return "text/javascript";
else if(ext == ".html" || ext == ".htm") else if(ext == ".html" || ext == ".htm")
return "text/html"; return "text/html";

View File

@ -7,6 +7,9 @@
<li class="menu-item"> <li class="menu-item">
<a href="netdb.html" class="menu-link">Network Database</a> <a href="netdb.html" class="menu-link">Network Database</a>
</li> </li>
<li class="menu-item">
<a href="tunnels.html" class="menu-link">Tunnels</a>
</li>
<li class="menu-item"> <li class="menu-item">
<a href="config.html" class="menu-link">Configure</a> <a href="config.html" class="menu-link">Configure</a>
</li> </li>

66
webui/tunnels.html Normal file
View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Purple I2P 0.10.0 Webconsole</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/main.css">
<script type="text/javascript" src="javascript/I2PControl.js"></script>
<script type="text/javascript">
function updateNetDbInfo(result, session) {
if(session.error) {
alert("Error: " + session.error["message"]);
return;
}
var table = document.getElementById("tunnels").getElementsByTagName("tbody")[0];
for(id in result["i2p.router.net.tunnels.inbound.list"]) {
if(!result["i2p.router.net.tunnels.inbound.list"].hasOwnProperty(id))
continue;
var tunnel = result["i2p.router.net.tunnels.inbound.list"][id];
var row = table.insertRow(table.rows.length);
row.insertCell(0).appendChild(document.createTextNode(id));
row.insertCell(1).appendChild(document.createTextNode(tunnel["status"] ? tunnel["status"] : "running"));
row.insertCell(2).appendChild(document.createTextNode(tunnel["layout"]));
}
}
function requestNetDbInfo(session) {
session.request("RouterInfo", {
"i2p.router.net.tunnels.inbound.list" : "",
}, updateNetDbInfo);
}
window.onload = function() {
var session = new I2PControl.Session("itoopie");
session.start(function() { requestNetDbInfo(session); });
};
</script>
</head>
<body>
<div class="header">
<h1>i2pd router console</h1>
<h2>Tunnel List</h2>
</div>
<div class="content">
<table id="tunnels">
<thead>
<th>Tunnel ID</th>
<th>Status</th>
<th>Overview</th>
</thead>
<tbody>
</tbody>
</table>
</div>
<!--#include virtual="menu.html" -->
<!--#include virtual="footer.html" -->
</body>
</html>