Added online/offline status to dashboard client Id column

* Added external client IP to dashboard client Id column tooltip
* Added client info (cpu, cores, cpu features, current configured threads, current hash mode ..) to client id column tooltip
This commit is contained in:
BenDroid 2017-11-13 22:35:53 +01:00
parent 947910f8e6
commit dfe56bbc21
9 changed files with 332 additions and 60 deletions

View file

@ -12,6 +12,8 @@
.right{text-align:right;}
.center{text-align:center;}
.toolbar { float: right; padding-left: 10pt;}
.online { color: green}
.offline { color: red}
</style>
<script type="text/javascript" language="javascript" src="//code.jquery.com/jquery-1.12.4.js"></script>
@ -26,10 +28,7 @@ $.fn.dataTable.ext.search.push(
var hide = document.getElementById("hideOffline").checked;
var lastStatus = settings.aoData[dataIndex]._aData.client_status.last_status_update * 1000;
var threshold = new Date().getTime() - 10*60*1000;
console.log("lastStatus: " + new Date(lastStatus));
console.log("threshold: " + new Date(threshold));
var threshold = new Date().getTime() - 60 * 1000;
if (lastStatus > threshold || !hide) {
return true;
@ -50,7 +49,7 @@ $(document).ready(function() {
dataSrc : 'client_status_list'
},
columns: [
{ data: "client_status.client_id"},
{ data: "client_status.client_id", render: clientInfo},
{ data: "client_status.current_pool"},
{ data: "client_status.current_status"},
{ data: "client_status.current_algo_name"},
@ -138,14 +137,14 @@ $(document).ready(function() {
}, 0 );
// Update footer
$( api.column(4).footer()).html(sumHashrateShort);
$( api.column(5).footer()).html(sumHashrateMedium);
$( api.column(6).footer()).html(sumHashrateLong);
$( api.column(7).footer()).html(sumHashrateHighest);
$( api.column(8).footer()).html(sumHashesTotal);
$( api.column(9).footer()).html(avgTimeTotal);
$( api.column(10).footer()).html(sumSharesGood);
$( api.column(11).footer()).html(sumSharedTotal);
$(api.column(4).footer()).html(sumHashrateShort);
$(api.column(5).footer()).html(sumHashrateMedium);
$(api.column(6).footer()).html(sumHashrateLong);
$(api.column(7).footer()).html(sumHashrateHighest);
$(api.column(8).footer()).html(sumHashesTotal);
$(api.column(9).footer()).html(avgTimeTotal);
$(api.column(10).footer()).html(sumSharesGood);
$(api.column(11).footer()).html(sumSharedTotal);
}
});
@ -179,7 +178,7 @@ $(document).ready(function() {
var htmlContent = "<div class='form-group' id='editor' data-value='" + clientId + "'>" +
"<label for='config'>Config for: " + clientId + "</label>"+
"<textarea class='form-control' rows='20' id='config'>" +
JSON.stringify(jsonClientConfig,undefined, 2); +
JSON.stringify(jsonClientConfig,undefined, 2) +
"</textarea>" +
"</div>";
@ -187,7 +186,7 @@ $(document).ready(function() {
$('#editConfig').modal('show');
},
error: function (data) {
alert("Unable to fetch " + clientId + "_config.json or default_config.json, please check your configuration!");
alert("Unable to fetch " + clientId + "_config.json or default_config.json, please check your Server configuration and the the config files are located on the Server!");
}
});
}
@ -223,9 +222,40 @@ $(document).ready(function() {
function laststatus( data, type, row ) {
var date = new Date(data*1000);
return '<span data-toggle="tooltip" title="' + date + '">' + jQuery.timeago(date) + '</span>';
}
function clientInfo( data, type, row ) {
var tooltip = "CPU: " + row.client_status.cpu_brand;
tooltip += '\n';
tooltip += "CPU Flags: " + (row.client_status.cpu_has_aes ? "AES-NI " : "");
tooltip += (row.client_status.cpu_is_x64 ? "x64" : "");
tooltip += '\n';
tooltip += "CPU Cache L2/L3: " + (row.client_status.cpu_l2 / 1024) + " MB/"+ (row.client_status.cpu_l3 / 1024) + " MB";
tooltip += '\n';
tooltip += "Huge Pages: " + (row.client_status.hugepages_available ? " available, " : " unavailable, ");
tooltip += (row.client_status.hugepages_enabled ? "enabled" : "disabled");
tooltip += '\n';
tooltip += "Threads: " + row.client_status.current_threads;
tooltip += (row.client_status.double_hash_mode ? " [double hash mode]" :"");
tooltip += '\n';
tooltip += "Client IP: " + row.client_status.external_ip;
tooltip += '\n';
tooltip += "Status: ";
var lastStatus = row.client_status.last_status_update * 1000;
var threshold = new Date().getTime() - 60 * 1000;
if (lastStatus > threshold) {
tooltip += "Online";
return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="online">' + data + '</div></span>';
}
else {
tooltip += "Offline";
return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="offline">' + data + '</div></span>';
}
}
function round( data, type, row ) {
return Math.round(data * 100) / 100;
}

View file

@ -25,10 +25,12 @@
#include <fstream>
#include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h>
#include <Platform.h>
#include "CCClient.h"
#include "App.h"
#include "Platform.h"
#include "Cpu.h"
#include "Mem.h"
#include "ControlCommand.h"
#include "api/NetworkState.h"
@ -69,6 +71,19 @@ CCClient::CCClient(const Options *options)
m_clientStatus.setCurrentAlgoName(m_options->algoName());
}
m_clientStatus.setHugepagesEnabled(Mem::isHugepagesEnabled());
m_clientStatus.setHugepages(Mem::isHugepagesAvailable());
m_clientStatus.setDoubleHashMode(Mem::isDoubleHash());
m_clientStatus.setCpuBrand(Cpu::brand());
m_clientStatus.setCpuAES(Cpu::hasAES());
m_clientStatus.setCpuCores(Cpu::cores());
m_clientStatus.setCpuX64(Cpu::isX64());
m_clientStatus.setCpuL2(Cpu::l2());
m_clientStatus.setCpuL3(Cpu::l3());
m_clientStatus.setCurrentThreads(Cpu::threads());
if (m_options->ccToken() != nullptr) {
m_authorization = std::string("Bearer ") + m_self->m_options->ccToken();
}

View file

@ -43,6 +43,16 @@ ClientStatus::ClientStatus()
}
ClientStatus::Status ClientStatus::getCurrentStatus() const
{
return m_currentStatus;
}
void ClientStatus::setCurrentStatus(Status currentStatus)
{
m_currentStatus = currentStatus;
}
std::string ClientStatus::getClientId() const
{
return m_clientId;
@ -73,14 +83,74 @@ std::string ClientStatus::getCurrentAlgoName() const
return m_currentAlgoName;
}
ClientStatus::Status ClientStatus::getCurrentStatus() const
std::string ClientStatus::getCpuBrand() const
{
return m_currentStatus;
return m_cpuBrand;
}
void ClientStatus::setCurrentStatus(Status currentStatus)
void ClientStatus::setCpuBrand(const std::string& cpuBrand)
{
m_currentStatus = currentStatus;
m_cpuBrand = cpuBrand;
}
std::string ClientStatus::getExternalIp() const
{
return m_externalIp;
}
void ClientStatus::setExternalIp(const std::string& externalIp)
{
m_externalIp = externalIp;
}
bool ClientStatus::hasHugepages() const
{
return m_hasHugepages;
}
void ClientStatus::setHugepages(bool hasHugepages)
{
m_hasHugepages = hasHugepages;
}
bool ClientStatus::isHugepagesEnabled() const
{
return m_isHugepagesEnabled;
}
void ClientStatus::setHugepagesEnabled(bool hugepagesEnabled)
{
m_isHugepagesEnabled = hugepagesEnabled;
}
bool ClientStatus::isDoubleHashMode() const
{
return m_isDoubleHashMode;
}
void ClientStatus::setDoubleHashMode(bool isDoubleHashMode)
{
m_isDoubleHashMode = isDoubleHashMode;
}
bool ClientStatus::isCpuX64() const
{
return m_isCpuX64;
}
void ClientStatus::setCpuX64(bool isCpuX64)
{
m_isCpuX64 = isCpuX64;
}
bool ClientStatus::hasCpuAES() const
{
return m_hasCpuAES;
}
void ClientStatus::setCpuAES(bool hasCpuAES)
{
m_hasCpuAES = hasCpuAES;
}
double ClientStatus::getHashrateShort() const
@ -113,6 +183,56 @@ void ClientStatus::setHashrateLong(double hashrateLong)
m_hashrateLong = hashrateLong;
}
void ClientStatus::setHashrateHighest(double hashrateHighest)
{
m_hashrateHighest = hashrateHighest;
}
double ClientStatus::getHashrateHighest() const
{
return m_hashrateHighest;
}
int ClientStatus::getCurrentThreads() const
{
return m_currentThreads;
}
void ClientStatus::setCurrentThreads(int currentThreads)
{
m_currentThreads = currentThreads;
}
int ClientStatus::getCpuCores() const
{
return m_cpuCores;
}
void ClientStatus::setCpuCores(int cpuCores)
{
m_cpuCores = cpuCores;
}
int ClientStatus::getCpuL2() const
{
return m_cpuL2;
}
void ClientStatus::setCpuL2(int cpuL2)
{
m_cpuL2 = cpuL2;
}
int ClientStatus::getCpuL3() const
{
return m_cpuL3;
}
void ClientStatus::setCpuL3(int cpuL3)
{
m_cpuL3 = cpuL3;
}
uint64_t ClientStatus::getSharesGood() const
{
return m_sharesGood;
@ -142,17 +262,6 @@ void ClientStatus::setHashesTotal(uint64_t hashesTotal)
{
m_hashesTotal = hashesTotal;
}
void ClientStatus::setHashrateHighest(double hashrateHighest)
{
m_hashrateHighest = hashrateHighest;
}
double ClientStatus::getHashrateHighest() const
{
return m_hashrateHighest;
}
void ClientStatus::setAvgTime(uint32_t avgTime)
{
m_avgTime = avgTime;
@ -176,6 +285,10 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
{
rapidjson::Value::ConstObject clientStatus = document["client_status"].GetObject();
if (clientStatus.HasMember("current_status")) {
m_currentStatus = toStatus(clientStatus["current_status"].GetString());
}
if (clientStatus.HasMember("client_id")) {
m_clientId = clientStatus["client_id"].GetString();
}
@ -184,14 +297,38 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_currentPool = clientStatus["current_pool"].GetString();
}
if (clientStatus.HasMember("current_status")) {
m_currentStatus = toStatus(clientStatus["current_status"].GetString());
}
if (clientStatus.HasMember("current_algo_name")) {
m_currentAlgoName = clientStatus["current_algo_name"].GetString();
}
if (clientStatus.HasMember("cpu_brand")) {
m_cpuBrand = clientStatus["cpu_brand"].GetString();
}
if (clientStatus.HasMember("external_ip")) {
m_externalIp = clientStatus["external_ip"].GetString();
}
if (clientStatus.HasMember("hugepages_available")) {
m_hasHugepages = clientStatus["hugepages_available"].GetBool();
}
if (clientStatus.HasMember("hugepages_enabled")) {
m_isHugepagesEnabled = clientStatus["hugepages_enabled"].GetBool();
}
if (clientStatus.HasMember("double_hash_mode")) {
m_isDoubleHashMode = clientStatus["double_hash_mode"].GetBool();
}
if (clientStatus.HasMember("cpu_is_x64")) {
m_isCpuX64 = clientStatus["cpu_is_x64"].GetBool();
}
if (clientStatus.HasMember("cpu_has_aes")) {
m_hasCpuAES = clientStatus["cpu_has_aes"].GetBool();
}
if (clientStatus.HasMember("hashrate_short")) {
m_hashrateShort = clientStatus["hashrate_short"].GetDouble();
}
@ -208,8 +345,20 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_hashrateHighest = clientStatus["hashrate_highest"].GetDouble();
}
if (clientStatus.HasMember("avg_time")) {
m_avgTime = clientStatus["avg_time"].GetUint();
if (clientStatus.HasMember("current_threads")) {
m_currentThreads = clientStatus["current_threads"].GetInt();
}
if (clientStatus.HasMember("cpu_cores")) {
m_cpuCores = clientStatus["cpu_cores"].GetInt();
}
if (clientStatus.HasMember("cpu_l2")) {
m_cpuL2 = clientStatus["cpu_l2"].GetInt();
}
if (clientStatus.HasMember("cpu_l3")) {
m_cpuL3 = clientStatus["cpu_l3"].GetInt();
}
if (clientStatus.HasMember("shares_good")) {
@ -224,6 +373,10 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_hashesTotal = clientStatus["hashes_total"].GetUint64();
}
if (clientStatus.HasMember("avg_time")) {
m_avgTime = clientStatus["avg_time"].GetUint();
}
auto time_point = std::chrono::system_clock::now();
m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point);
@ -239,21 +392,36 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::
{
rapidjson::Value clientStatus(rapidjson::kObjectType);
clientStatus.AddMember("current_status", rapidjson::StringRef(toString(m_currentStatus)), allocator);
clientStatus.AddMember("client_id", rapidjson::StringRef(m_clientId.c_str()), allocator);
clientStatus.AddMember("current_pool", rapidjson::StringRef(m_currentPool.c_str()), allocator);
clientStatus.AddMember("current_status", rapidjson::StringRef(toString(m_currentStatus)), allocator);
clientStatus.AddMember("current_algo_name", rapidjson::StringRef(m_currentAlgoName.c_str()), allocator);
clientStatus.AddMember("cpu_brand", rapidjson::StringRef(m_cpuBrand.c_str()), allocator);
clientStatus.AddMember("external_ip", rapidjson::StringRef(m_externalIp.c_str()), allocator);
clientStatus.AddMember("hugepages_available", m_hasHugepages, allocator);
clientStatus.AddMember("hugepages_enabled", m_isHugepagesEnabled, allocator);
clientStatus.AddMember("double_hash_mode", m_isDoubleHashMode, allocator);
clientStatus.AddMember("cpu_is_x64", m_isCpuX64, allocator);
clientStatus.AddMember("cpu_has_aes", m_hasCpuAES, allocator);
clientStatus.AddMember("hashrate_short", m_hashrateShort, allocator);
clientStatus.AddMember("hashrate_medium", m_hashrateMedium, allocator);
clientStatus.AddMember("hashrate_long", m_hashrateLong, allocator);
clientStatus.AddMember("hashrate_highest", m_hashrateHighest, allocator);
clientStatus.AddMember("avg_time", m_avgTime, allocator);
clientStatus.AddMember("current_threads", m_currentThreads, allocator);
clientStatus.AddMember("cpu_cores", m_cpuCores, allocator);
clientStatus.AddMember("cpu_l2", m_cpuL2, allocator);
clientStatus.AddMember("cpu_l3", m_cpuL3, allocator);
clientStatus.AddMember("shares_good", m_sharesGood, allocator);
clientStatus.AddMember("shares_total", m_sharesTotal, allocator);
clientStatus.AddMember("hashes_total", m_hashesTotal, allocator);
clientStatus.AddMember("avg_time", m_avgTime, allocator);
clientStatus.AddMember("last_status_update", m_lastStatusUpdate, allocator);
return clientStatus;

View file

@ -27,7 +27,7 @@
#include <string>
#include <ctime>
#include "rapidjson/document.h"
#include <rapidjson/document.h>
class ClientStatus
{
@ -58,6 +58,9 @@ public:
return Status::RUNNING;
}
Status getCurrentStatus() const;
void setCurrentStatus(Status currentStatus);
std::string getClientId() const;
void setClientId(const std::string& clientId);
@ -67,8 +70,26 @@ public:
std::string getCurrentAlgoName() const;
void setCurrentAlgoName(const std::string &algoName);
Status getCurrentStatus() const;
void setCurrentStatus(Status currentStatus);
std::string getCpuBrand() const;
void setCpuBrand(const std::string &cpuBrand);
std::string getExternalIp() const;
void setExternalIp(const std::string &externalIp);
bool hasHugepages() const;
void setHugepages(bool hasHugepages);
bool isHugepagesEnabled() const;
void setHugepagesEnabled(bool hugepagesEnabled);
bool isDoubleHashMode() const;
void setDoubleHashMode(bool isDoubleHashMode);
bool isCpuX64() const;
void setCpuX64(bool isCpuX64);
bool hasCpuAES() const;
void setCpuAES(bool hasCpuAES);
double getHashrateShort() const;
void setHashrateShort(double hashrateShort);
@ -79,6 +100,21 @@ public:
double getHashrateLong() const;
void setHashrateLong(double hashrateLong);
void setHashrateHighest(double hashrateHighest);
double getHashrateHighest() const;
int getCurrentThreads() const;
void setCurrentThreads(int currentThreads);
int getCpuCores() const;
void setCpuCores(int cpuCores);
int getCpuL2() const;
void setCpuL2(int cpuL2);
int getCpuL3() const;
void setCpuL3(int cpuL3);
uint64_t getSharesGood() const;
void setSharesGood(uint64_t sharesGood);
@ -88,9 +124,6 @@ public:
uint64_t getHashesTotal() const;
void setHashesTotal(uint64_t hashesTotal);
void setHashrateHighest(double hashrateHighest);
double getHashrateHighest() const;
void setAvgTime(uint32_t avgTime);
uint32_t getAvgTime() const;
@ -113,12 +146,25 @@ private:
std::string m_clientId;
std::string m_currentPool;
std::string m_currentAlgoName;
std::string m_cpuBrand;
std::string m_externalIp;
bool m_hasHugepages;
bool m_isHugepagesEnabled;
bool m_isDoubleHashMode;
bool m_isCpuX64;
bool m_hasCpuAES;
double m_hashrateShort;
double m_hashrateMedium;
double m_hashrateLong;
double m_hashrateHighest;
int m_currentThreads;
int m_cpuCores;
int m_cpuL2;
int m_cpuL3;
uint64_t m_sharesGood;
uint64_t m_sharesTotal;
uint64_t m_hashesTotal;

View file

@ -212,15 +212,26 @@ int Httpd::handlePOST(const Httpd* httpd, struct MHD_Connection* connection, con
} else {
std::string resp;
std::string url(urlPtr);
std::string clientIp;
std::string clientId;
const MHD_ConnectionInfo *info = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
if (info) {
char clientHost[NI_MAXHOST];
int ec = getnameinfo(info->client_addr, sizeof(*info->client_addr), clientHost, sizeof(clientHost),
0, 0, NI_NUMERICHOST|NI_NUMERICSERV);
if (ec == 0) {
clientIp = std::string(clientHost);
}
}
const char* clientIdPtr = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "clientId");
if (clientIdPtr)
{
if (clientIdPtr) {
clientId = std::string(clientIdPtr);
}
unsigned status = Service::handlePOST(httpd->m_options, url, clientId, cc->data.str(), resp);
unsigned status = Service::handlePOST(httpd->m_options, url, clientIp, clientId, cc->data.str(), resp);
MHD_Response* rsp = nullptr;
if (!resp.empty()) {

View file

@ -86,16 +86,18 @@ unsigned Service::handleGET(const Options* options, const std::string& url, cons
return resultCode;
}
unsigned Service::handlePOST(const Options* options, const std::string& url, const std::string& clientId, const std::string& data, std::string& resp)
unsigned Service::handlePOST(const Options* options, const std::string& url, const std::string& clientIp,
const std::string& clientId, const std::string& data, std::string& resp)
{
uv_mutex_lock(&m_mutex);
unsigned resultCode = MHD_HTTP_NOT_FOUND;
LOG_INFO("POST(url='%s', clientId='%s', dataLen='%d')", url.c_str(), clientId.c_str(), data.length());
LOG_INFO("POST(url='%s', clientIp='%s', clientId='%s', dataLen='%d')",
url.c_str(), clientId.c_str(), clientIp.c_str(), data.length());
if (url.rfind("/client/setClientStatus", 0) == 0) {
resultCode = setClientStatus(clientId, data, resp);
resultCode = setClientStatus(clientIp, clientId, data, resp);
} else if (url.rfind("/admin/setClientConfig", 0) == 0) {
resultCode = setClientConfig(options, clientId, data, resp);
} else if (url.rfind("/admin/setClientCommand", 0) == 0) {
@ -204,7 +206,7 @@ unsigned Service::getClientStatusList(std::string& resp)
return MHD_HTTP_OK;
}
unsigned Service::setClientStatus(const std::string& clientId, const std::string& data, std::string& resp)
unsigned Service::setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp)
{
int resultCode = MHD_HTTP_BAD_REQUEST;
@ -214,6 +216,7 @@ unsigned Service::setClientStatus(const std::string& clientId, const std::string
ClientStatus clientStatus;
clientStatus.parseFromJson(document);
clientStatus.setExternalIp(clientIp);
m_clientStatus[clientId] = clientStatus;

View file

@ -43,7 +43,7 @@ public:
static void release();
static unsigned handleGET(const Options* options, const std::string& url, const std::string& clientId, std::string& resp);
static unsigned handlePOST(const Options* options, const std::string& url, const std::string& clientId, const std::string& data, std::string& resp);
static unsigned handlePOST(const Options* options, const std::string& url, const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp);
private:
static unsigned getClientConfig(const Options* options, const std::string& clientId, std::string& resp);
@ -51,7 +51,7 @@ private:
static unsigned getClientStatusList(std::string& resp);
static unsigned getAdminPage(const Options* options, std::string& resp);
static unsigned setClientStatus(const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientStatus(const std::string& clientIp, const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientCommand(const std::string& clientId, const std::string& data, std::string& resp);
static unsigned setClientConfig(const Options* options, const std::string &clientId, const std::string &data, std::string &resp);

View file

@ -49,7 +49,7 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) :
keccak(reinterpret_cast<const uint8_t *>(user), static_cast<int>(strlen(user)), hash, sizeof(hash));
Job::toHex(hash, 32, userId);
Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 4444, userId, nullptr, false, true);
Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, true);
m_client = new Client(-1, agent, this);
m_client->setUrl(url);

View file

@ -29,22 +29,21 @@
#define APP_ID "xmrigCC"
#define APP_NAME "XMRigCC"
#define APP_DESC "XMRigCC Command'n'Control Server"
#define APP_VERSION "1.0.9"
#define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id"
# else
#define APP_ID "xmrigCC"
#define APP_NAME "XMRigCC"
#define APP_DESC "XMRigCC CPU miner"
#define APP_VERSION "2.4.2"
#define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id"
#endif
#define APP_VERSION "1.0.9 (based on XMRig 2.4.2)"
#define APP_DOMAIN ""
#define APP_SITE "https://github.com/Bendr0id/xmrigCC"
#define APP_KIND "cpu"
#define APP_VER_MAJOR 2
#define APP_VER_MINOR 4
#define APP_VER_BUILD 2
#define APP_VER_MAJOR 1
#define APP_VER_MINOR 0
#define APP_VER_BUILD 9
#define APP_VER_REV 0
#ifdef _MSC_VER