Fixed some bugs in Dashboard

* Added client Version to tooltip
* Add version check and "update available" notification to Dashboard
This commit is contained in:
BenDroid 2017-11-23 19:27:48 +01:00
parent 2fd4539643
commit ee0dd98eeb
7 changed files with 142 additions and 100 deletions

View file

@ -28,10 +28,11 @@ build_script:
- cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 .. - cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 ..
- msbuild xmrig.sln /p:Configuration=Release - msbuild xmrig.sln /p:Configuration=Release
after_build: after_build:
- cd c:\xmrigCC - cd c:\xmrigCC
- cmd: 7z a xmrigCC-win64.zip "c:\xmrigCC\build\Release\*.*" "c:\xmrigCC\src\*config*" "c:\xmrigCC\index.html" - cmd: 7z a xmrigCC-mvc-win64.zip "c:\xmrigCC\build\Release\*.*" "c:\xmrigCC\src\*config*" "c:\xmrigCC\index.html"
- cmd: dir - cmd: dir
artifacts: artifacts:
- path: xmrigCC-win64.zip - path: xmrigCC-mvc-win64.zip

View file

@ -27,19 +27,14 @@ $.fn.dataTable.ext.search.push(
function( settings, data, dataIndex ) { function( settings, data, dataIndex ) {
var hide = document.getElementById("hideOffline").checked; var hide = document.getElementById("hideOffline").checked;
var lastStatus = settings.aoData[dataIndex]._aData.client_status.last_status_update * 1000; return (isOnline(settings.aoData[dataIndex]._aData.client_status.last_status_update * 1000) || !hide);
var threshold = new Date().getTime() - 60 * 1000;
if (lastStatus > threshold || !hide) {
return true;
}
else {
return false;
}
} }
); );
$(document).ready(function() { $(document).ready(function() {
var latestRelease = "";
var table = $('#clientStatusList').DataTable({ var table = $('#clientStatusList').DataTable({
dom: '<"toolbar">frtip', dom: '<"toolbar">frtip',
processing : true, processing : true,
@ -80,63 +75,35 @@ $(document).ready(function() {
"footerCallback": function ( row, data, start, end, display ) { "footerCallback": function ( row, data, start, end, display ) {
var api = this.api(); var api = this.api();
sumHashrateShort = round(api var sumHashrateShort = 0;
.column(4) var sumHashrateMedium = 0;
.data() var sumHashrateLong = 0;
.reduce( function (a, b) { var sumHashrateHighest = 0;
return a + b; var sumHashesTotal = 0;
}, 0 )); var avgTimeTotal = 0;
var sumSharesGood = 0;
var sumSharedTotal = 0;
sumHashrateMedium = round(api for (var i = 0; i < data.length; ++i) {
.column(5) if (isOnline(data[i].client_status.last_status_update * 1000)) {
.data() sumHashrateShort += data[i].client_status.hashrate_short;
.reduce( function (a, b) { sumHashrateMedium += data[i].client_status.hashrate_medium;
return a + b; sumHashrateLong += data[i].client_status.hashrate_long;
}, 0 )); sumHashrateHighest += data[i].client_status.hashrate_highest;
sumHashesTotal += data[i].client_status.hashes_total;
avgTimeTotal = (avgTimeTotal + data[i].client_status.avg_time) / 2;
sumSharesGood += data[i].client_status.shares_good;
sumSharedTotal += data[i].client_status.shares_total;
}
}
sumHashrateLong = round(api sumHashrateShort = round(sumHashrateShort);
.column(6) sumHashrateMedium = round(sumHashrateMedium);
.data() sumHashrateLong = round(sumHashrateLong);
.reduce( function (a, b) { sumHashrateHighest = round(sumHashrateHighest);
return a + b; avgTimeTotal = round(avgTimeTotal);
}, 0 ));
sumHashrateHighest = round(api // update footer
.column(7)
.data()
.reduce( function (a, b) {
return a + b;
}, 0 ));
sumHashesTotal = api
.column(8)
.data()
.reduce( function (a, b) {
return a + b;
}, 0 );
avgTimeTotal = round(api
.column(9)
.data()
.reduce( function (a, b) {
return a + b;
}, 0 )/end);
sumSharesGood = api
.column(10)
.data()
.reduce( function (a, b) {
return a + b;
}, 0 );
sumSharedTotal = api
.column(11)
.data()
.reduce( function (a, b) {
return a + b;
}, 0 );
// Update footer
$(api.column(4).footer()).html(sumHashrateShort); $(api.column(4).footer()).html(sumHashrateShort);
$(api.column(5).footer()).html(sumHashrateMedium); $(api.column(5).footer()).html(sumHashrateMedium);
$(api.column(6).footer()).html(sumHashrateLong); $(api.column(6).footer()).html(sumHashrateLong);
@ -145,6 +112,24 @@ $(document).ready(function() {
$(api.column(9).footer()).html(avgTimeTotal); $(api.column(9).footer()).html(avgTimeTotal);
$(api.column(10).footer()).html(sumSharesGood); $(api.column(10).footer()).html(sumSharesGood);
$(api.column(11).footer()).html(sumSharedTotal); $(api.column(11).footer()).html(sumSharedTotal);
// check version
if (latestRelease === "" && $(api).context[0].json !== undefined) {
$.ajax({
url: "https://api.github.com/repos/Bendr0id/xmrigCC/releases/latest",
type: 'GET',
dataType: "json",
success: function (release) {
latestRelease = release.tag_name;
if (latestRelease !== $(api).context[0].json.current_version) {
$("#notificationBar").html('<div class="alert alert-info alert-dismissable fade in">' +
'<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>' +
'<a href="https://github.com/Bendr0id/xmrigCC/releases/latest"><strong>Update!</strong> XMRigCC v' + latestRelease + ' is available for download\n</a>' +
'</div>');
}
}
});
}
} }
}); });
@ -232,26 +217,27 @@ function laststatus( data, type, row ) {
function clientInfo( data, type, row ) { function clientInfo( data, type, row ) {
if (type !== 'sort') { if (type !== 'sort') {
var tooltip = "CPU: " + row.client_status.cpu_brand + " [" + row.client_status.cpu_cores + " cores]"; var tooltip = "CPU: " + row.client_status.cpu_brand + " [" + row.client_status.cpu_cores + " cores]";
tooltip += '\n'; tooltip += '\n';
tooltip += "CPU Flags: " + (row.client_status.cpu_has_aes ? "AES-NI " : ""); tooltip += "CPU Flags: " + (row.client_status.cpu_has_aes ? "AES-NI " : "");
tooltip += (row.client_status.cpu_is_x64 ? "x64" : ""); tooltip += (row.client_status.cpu_is_x64 ? "x64" : "");
tooltip += '\n'; tooltip += '\n';
tooltip += "CPU Cache L2/L3: " + (row.client_status.cpu_l2 / 1024) + " MB/"+ (row.client_status.cpu_l3 / 1024) + " MB"; tooltip += "CPU Cache L2/L3: " + (row.client_status.cpu_l2 / 1024) + " MB/"+ (row.client_status.cpu_l3 / 1024) + " MB";
tooltip += '\n'; tooltip += '\n';
tooltip += "Huge Pages: " + (row.client_status.hugepages_available ? " available, " : " unavailable, "); tooltip += "Huge Pages: " + (row.client_status.hugepages_available ? " available, " : " unavailable, ");
tooltip += (row.client_status.hugepages_enabled ? "enabled" : "disabled"); tooltip += (row.client_status.hugepages_enabled ? "enabled" : "disabled");
tooltip += '\n'; tooltip += '\n';
tooltip += "Used Threads: " + row.client_status.current_threads; tooltip += "Used Threads: " + row.client_status.current_threads;
tooltip += (row.client_status.double_hash_mode ? " [double hash mode]" :""); tooltip += (row.client_status.double_hash_mode ? " [double hash mode]" :"");
tooltip += '\n'; tooltip += '\n';
tooltip += "Client IP: " + row.client_status.external_ip; tooltip += "Client IP: " + row.client_status.external_ip;
tooltip += '\n'; tooltip += '\n';
tooltip += "Status: "; tooltip += "Version: " + row.client_status.version;
tooltip += '\n';
tooltip += "Status: ";
var lastStatus = row.client_status.last_status_update * 1000; var lastStatus = row.client_status.last_status_update * 1000;
var threshold = new Date().getTime() - 60 * 1000; if (isOnline(lastStatus)) {
if (lastStatus > threshold) {
tooltip += "Online"; tooltip += "Online";
return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="online">' + data + '</div></span>'; return '<span data-toggle="tooltip" title="'+ tooltip + '"><div class="online">' + data + '</div></span>';
} }
@ -268,12 +254,22 @@ function round( data, type, row ) {
return Math.round(data * 100) / 100; return Math.round(data * 100) / 100;
} }
function isOnline(lastStatus) {
var threshold = new Date().getTime() - 60 * 1000;
if (lastStatus > threshold) {
return true;
} else {
return false;
}
}
</script> </script>
</head> </head>
<body> <body>
<br/> <br/>
<div style="width: 90%; margin:0 auto;"> <div style="width: 90%; margin:0 auto;">
<div id="notificationBar"></div>
<div class="center"> <div class="center">
<h1>XMRigCC Dashboard</h1> <h1>XMRigCC Dashboard</h1>
</div> </div>

View file

@ -25,6 +25,7 @@
#include <fstream> #include <fstream>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include <version.h>
#include "CCClient.h" #include "CCClient.h"
#include "App.h" #include "App.h"
@ -41,16 +42,18 @@
#if _WIN32 #if _WIN32
# include "winsock2.h" # include "winsock2.h"
#else #else
# include "unistd.h" # include "unistd.h"
#endif #endif
CCClient *CCClient::m_self = nullptr; CCClient* CCClient::m_self = nullptr;
uv_mutex_t CCClient::m_mutex; uv_mutex_t CCClient::m_mutex;
CCClient::CCClient(Options* options, uv_async_t* async) CCClient::CCClient(Options* options, uv_async_t* async)
: m_options(options), : m_options(options),
m_async(async) m_async(async)
{ {
uv_mutex_init(&m_mutex); uv_mutex_init(&m_mutex);
@ -59,10 +62,10 @@ CCClient::CCClient(Options* options, uv_async_t* async)
std::string clientId; std::string clientId;
if (m_options->ccWorkerId()) { if (m_options->ccWorkerId()) {
clientId = m_options->ccWorkerId(); clientId = m_options->ccWorkerId();
} else{ } else {
char hostname[128]; char hostname[128];
memset(hostname, 0, sizeof(hostname)); memset(hostname, 0, sizeof(hostname));
gethostname(hostname, sizeof(hostname)-1); gethostname(hostname, sizeof(hostname) - 1);
clientId = std::string(hostname); clientId = std::string(hostname);
} }
@ -76,6 +79,7 @@ CCClient::CCClient(Options* options, uv_async_t* async)
m_clientStatus.setHugepages(Mem::isHugepagesAvailable()); m_clientStatus.setHugepages(Mem::isHugepagesAvailable());
m_clientStatus.setDoubleHashMode(Mem::isDoubleHash()); m_clientStatus.setDoubleHashMode(Mem::isDoubleHash());
m_clientStatus.setVersion(Version::string());
m_clientStatus.setCpuBrand(Cpu::brand()); m_clientStatus.setCpuBrand(Cpu::brand());
m_clientStatus.setCpuAES(Cpu::hasAES()); m_clientStatus.setCpuAES(Cpu::hasAES());
m_clientStatus.setCpuCores(Cpu::cores()); m_clientStatus.setCpuCores(Cpu::cores());
@ -98,7 +102,7 @@ CCClient::~CCClient()
m_self = nullptr; m_self = nullptr;
} }
void CCClient::updateHashrate(const Hashrate *hashrate) void CCClient::updateHashrate(const Hashrate* hashrate)
{ {
if (m_self) { if (m_self) {
uv_mutex_lock(&m_mutex); uv_mutex_lock(&m_mutex);
@ -113,7 +117,7 @@ void CCClient::updateHashrate(const Hashrate *hashrate)
} }
void CCClient::updateNetworkState(const NetworkState &network) void CCClient::updateNetworkState(const NetworkState& network)
{ {
if (m_self) { if (m_self) {
uv_mutex_lock(&m_mutex); uv_mutex_lock(&m_mutex);
@ -139,7 +143,7 @@ void CCClient::publishClientStatusReport()
LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s", LOG_ERR("[CC-Client] error: unable to performRequest POST -> http://%s:%d%s",
m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str());
} else if (res->status != 200) { } else if (res->status != 200) {
LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(), LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(),
m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_options->ccPort(), requestUrl.c_str());
} else { } else {
ControlCommand controlCommand; ControlCommand controlCommand;
@ -161,7 +165,7 @@ void CCClient::publishClientStatusReport()
LOG_WARN("[CC-Client] Command: SHUTDOWN received -> shutdown"); LOG_WARN("[CC-Client] Command: SHUTDOWN received -> shutdown");
} }
m_self->m_async->data = reinterpret_cast<void *>(controlCommand.getCommand()); m_self->m_async->data = reinterpret_cast<void*>(controlCommand.getCommand());
uv_async_send(m_self->m_async); uv_async_send(m_self->m_async);
} else { } else {
LOG_ERR("[CC-Client] Unknown command received from CC Server."); LOG_ERR("[CC-Client] Unknown command received from CC Server.");
@ -179,7 +183,7 @@ void CCClient::updateConfig()
LOG_ERR("[CC-Client] error: unable to performRequest GET -> http://%s:%d%s", LOG_ERR("[CC-Client] error: unable to performRequest GET -> http://%s:%d%s",
m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_options->ccHost(), m_self->m_options->ccPort(), requestUrl.c_str());
} else if (res->status != 200) { } else if (res->status != 200) {
LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(), LOG_ERR("[CC-Client] error: \"%d\" -> http://%s:%d%s", res->status, m_self->m_options->ccHost(),
m_self->m_options->ccPort(), requestUrl.c_str()); m_self->m_options->ccPort(), requestUrl.c_str());
} else { } else {
rapidjson::Document document; rapidjson::Document document;
@ -198,7 +202,7 @@ void CCClient::updateConfig()
} else { } else {
LOG_ERR("[CC-Client] Not able to store client config to file %s.", m_self->m_options->configFile()); LOG_ERR("[CC-Client] Not able to store client config to file %s.", m_self->m_options->configFile());
} }
} else{ } else {
LOG_ERR("[CC-Client] Not able to store client config. received client config is broken!"); LOG_ERR("[CC-Client] Not able to store client config. received client config is broken!");
} }
} }
@ -244,7 +248,7 @@ void CCClient::onThreadStarted(void* handle)
uv_run(&m_self->m_client_loop, UV_RUN_DEFAULT); uv_run(&m_self->m_client_loop, UV_RUN_DEFAULT);
} }
void CCClient::onReport(uv_timer_t *handle) void CCClient::onReport(uv_timer_t* handle)
{ {
if (m_self) { if (m_self) {
m_self->publishClientStatusReport(); m_self->publishClientStatusReport();

View file

@ -115,6 +115,16 @@ void ClientStatus::setExternalIp(const std::string& externalIp)
m_externalIp = externalIp; m_externalIp = externalIp;
} }
std::string ClientStatus::getVersion() const
{
return m_version;
}
void ClientStatus::setVersion(const std::string& version)
{
m_version = version;
}
bool ClientStatus::hasHugepages() const bool ClientStatus::hasHugepages() const
{ {
return m_hasHugepages; return m_hasHugepages;
@ -321,6 +331,10 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
m_externalIp = clientStatus["external_ip"].GetString(); m_externalIp = clientStatus["external_ip"].GetString();
} }
if (clientStatus.HasMember("version")) {
m_version = clientStatus["version"].GetString();
}
if (clientStatus.HasMember("hugepages_available")) { if (clientStatus.HasMember("hugepages_available")) {
m_hasHugepages = clientStatus["hugepages_available"].GetBool(); m_hasHugepages = clientStatus["hugepages_available"].GetBool();
} }
@ -411,6 +425,7 @@ rapidjson::Value ClientStatus::toJson(rapidjson::MemoryPoolAllocator<rapidjson::
clientStatus.AddMember("current_algo_name", rapidjson::StringRef(m_currentAlgoName.c_str()), 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("cpu_brand", rapidjson::StringRef(m_cpuBrand.c_str()), allocator);
clientStatus.AddMember("external_ip", rapidjson::StringRef(m_externalIp.c_str()), allocator); clientStatus.AddMember("external_ip", rapidjson::StringRef(m_externalIp.c_str()), allocator);
clientStatus.AddMember("version", rapidjson::StringRef(m_version.c_str()), allocator);
clientStatus.AddMember("hugepages_available", m_hasHugepages, allocator); clientStatus.AddMember("hugepages_available", m_hasHugepages, allocator);
clientStatus.AddMember("hugepages_enabled", m_isHugepagesEnabled, allocator); clientStatus.AddMember("hugepages_enabled", m_isHugepagesEnabled, allocator);

View file

@ -68,13 +68,16 @@ public:
void setCurrentPool(const std::string& currentPool); void setCurrentPool(const std::string& currentPool);
std::string getCurrentAlgoName() const; std::string getCurrentAlgoName() const;
void setCurrentAlgoName(const std::string &algoName); void setCurrentAlgoName(const std::string& algoName);
std::string getCpuBrand() const; std::string getCpuBrand() const;
void setCpuBrand(const std::string &cpuBrand); void setCpuBrand(const std::string& cpuBrand);
std::string getExternalIp() const; std::string getExternalIp() const;
void setExternalIp(const std::string &externalIp); void setExternalIp(const std::string& externalIp);
std::string getVersion() const;
void setVersion(const std::string& version);
bool hasHugepages() const; bool hasHugepages() const;
void setHugepages(bool hasHugepages); void setHugepages(bool hasHugepages);
@ -148,6 +151,7 @@ private:
std::string m_currentAlgoName; std::string m_currentAlgoName;
std::string m_cpuBrand; std::string m_cpuBrand;
std::string m_externalIp; std::string m_externalIp;
std::string m_version;
bool m_hasHugepages; bool m_hasHugepages;
bool m_isHugepagesEnabled; bool m_isHugepagesEnabled;

View file

@ -32,6 +32,7 @@
#include <3rdparty/rapidjson/filereadstream.h> #include <3rdparty/rapidjson/filereadstream.h>
#include <3rdparty/rapidjson/error/en.h> #include <3rdparty/rapidjson/error/en.h>
#include <3rdparty/rapidjson/prettywriter.h> #include <3rdparty/rapidjson/prettywriter.h>
#include <version.h>
#include "log/Log.h" #include "log/Log.h"
#include "Service.h" #include "Service.h"
@ -194,6 +195,7 @@ unsigned Service::getClientStatusList(std::string& resp)
clientStatusList.PushBack(clientStatusEntry, allocator); clientStatusList.PushBack(clientStatusEntry, allocator);
} }
document.AddMember("current_version", rapidjson::StringRef(Version::string().c_str()), allocator);
document.AddMember("client_status_list", clientStatusList, allocator); document.AddMember("client_status_list", clientStatusList, allocator);
rapidjson::StringBuffer buffer(0, 4096); rapidjson::StringBuffer buffer(0, 4096);

View file

@ -36,14 +36,14 @@
#define APP_DESC "XMRigCC CPU miner" #define APP_DESC "XMRigCC CPU miner"
#define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id" #define APP_COPYRIGHT "Copyright (C) 2017- BenDr0id"
#endif #endif
#define APP_VERSION "1.1.0 (based on XMRig 2.4.2)" #define APP_VERSION "1.1.1 (based on XMRig 2.4.2)"
#define APP_DOMAIN "" #define APP_DOMAIN ""
#define APP_SITE "https://github.com/Bendr0id/xmrigCC" #define APP_SITE "https://github.com/Bendr0id/xmrigCC"
#define APP_KIND "cpu" #define APP_KIND "cpu"
#define APP_VER_MAJOR 1 #define APP_VER_MAJOR 1
#define APP_VER_MINOR 1 #define APP_VER_MINOR 1
#define APP_VER_BUILD 0 #define APP_VER_BUILD 1
#define APP_VER_REV 0 #define APP_VER_REV 0
#ifdef _MSC_VER #ifdef _MSC_VER
@ -62,4 +62,24 @@
# endif # endif
#endif #endif
#include <string>
class Version
{
public:
inline static std::string string()
{
std::string version = std::to_string(APP_VER_MAJOR) + std::string(".") + std::to_string(APP_VER_MINOR) +
std::string(".") + std::to_string(APP_VER_BUILD);
return version;
}
inline static int code()
{
std::string version = std::to_string(APP_VER_MAJOR) + std::to_string(APP_VER_MINOR) + std::to_string(APP_VER_BUILD);
return std::stoi(version);
}
};
#endif /* __VERSION_H__ */ #endif /* __VERSION_H__ */