Server improvements and remote machine reboot (#213)
* Add remote reboot feature to Dashboard, Server & Miner * Integrated Pushover push notifications for Offline miners and periodical stats
This commit is contained in:
parent
408e7d3670
commit
de9f64e515
22 changed files with 288 additions and 40 deletions
|
@ -219,9 +219,11 @@ void CCClient::publishClientStatusReport()
|
|||
LOG_WARN("[CC-Client] Command: PUBLISH_CONFIG received -> publish config");
|
||||
publishConfig();
|
||||
}else if (controlCommand.getCommand() == ControlCommand::RESTART) {
|
||||
LOG_WARN("[CC-Client] Command: RESTART received -> restart");
|
||||
LOG_WARN("[CC-Client] Command: RESTART received -> trigger restart");
|
||||
} else if (controlCommand.getCommand() == ControlCommand::SHUTDOWN) {
|
||||
LOG_WARN("[CC-Client] Command: SHUTDOWN received -> shutdown");
|
||||
LOG_WARN("[CC-Client] Command: SHUTDOWN received -> quit");
|
||||
} else if (controlCommand.getCommand() == ControlCommand::REBOOT) {
|
||||
LOG_WARN("[CC-Client] Command: REBOOT received -> trigger reboot");
|
||||
}
|
||||
|
||||
m_self->m_async->data = reinterpret_cast<void*>(controlCommand.getCommand());
|
||||
|
|
|
@ -356,7 +356,7 @@ uint32_t ClientStatus::getAvgTime() const
|
|||
return m_avgTime;
|
||||
}
|
||||
|
||||
std::time_t ClientStatus::getLastStatusUpdate() const
|
||||
uint64_t ClientStatus::getLastStatusUpdate() const
|
||||
{
|
||||
return m_lastStatusUpdate;
|
||||
}
|
||||
|
@ -516,7 +516,8 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
|
|||
}
|
||||
|
||||
auto time_point = std::chrono::system_clock::now();
|
||||
m_lastStatusUpdate = std::chrono::system_clock::to_time_t(time_point);
|
||||
m_lastStatusUpdate = static_cast<uint64_t>(std::chrono::system_clock::to_time_t(time_point));
|
||||
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public:
|
|||
void setAvgTime(uint32_t avgTime);
|
||||
uint32_t getAvgTime() const;
|
||||
|
||||
std::time_t getLastStatusUpdate() const;
|
||||
uint64_t getLastStatusUpdate() const;
|
||||
|
||||
void setUptime(uint64_t uptime);
|
||||
uint64_t getUptime() const;
|
||||
|
@ -203,8 +203,7 @@ private:
|
|||
uint64_t m_uptime;
|
||||
|
||||
uint32_t m_avgTime;
|
||||
|
||||
std::time_t m_lastStatusUpdate;
|
||||
uint64_t m_lastStatusUpdate;
|
||||
};
|
||||
|
||||
#endif /* __CLIENT_STATUS_H__ */
|
||||
|
|
|
@ -97,5 +97,6 @@ bool ControlCommand::isOneTimeCommand() const {
|
|||
return m_command == ControlCommand::UPDATE_CONFIG ||
|
||||
m_command == ControlCommand::PUBLISH_CONFIG ||
|
||||
m_command == ControlCommand::RESTART ||
|
||||
m_command == ControlCommand::SHUTDOWN;
|
||||
m_command == ControlCommand::SHUTDOWN ||
|
||||
m_command == ControlCommand::REBOOT;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,14 @@
|
|||
#include <string>
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
static const char* command_str[6] = {
|
||||
static const char* command_str[7] = {
|
||||
"START",
|
||||
"STOP",
|
||||
"UPDATE_CONFIG",
|
||||
"PUBLISH_CONFIG",
|
||||
"RESTART",
|
||||
"SHUTDOWN"
|
||||
"SHUTDOWN",
|
||||
"REBOOT"
|
||||
};
|
||||
|
||||
class ControlCommand
|
||||
|
@ -39,7 +40,8 @@ public:
|
|||
UPDATE_CONFIG,
|
||||
PUBLISH_CONFIG,
|
||||
RESTART,
|
||||
SHUTDOWN
|
||||
SHUTDOWN,
|
||||
REBOOT
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "log/Log.h"
|
||||
#include <3rdparty/cpp-httplib/httplib.h>
|
||||
#include <3rdparty/rapidjson/document.h>
|
||||
#include <3rdparty/rapidjson/stringbuffer.h>
|
||||
#include <3rdparty/rapidjson/writer.h>
|
||||
|
@ -33,21 +37,34 @@
|
|||
#include <3rdparty/rapidjson/filereadstream.h>
|
||||
#include <3rdparty/rapidjson/error/en.h>
|
||||
#include <3rdparty/rapidjson/prettywriter.h>
|
||||
#include <version.h>
|
||||
#include "log/Log.h"
|
||||
#include "version.h"
|
||||
#include "Service.h"
|
||||
|
||||
uv_mutex_t Service::m_mutex;
|
||||
uv_timer_t Service::m_timer;
|
||||
|
||||
std::map<std::string, ControlCommand> Service::m_clientCommand;
|
||||
std::map<std::string, ClientStatus> Service::m_clientStatus;
|
||||
std::map<std::string, std::list<std::string>> Service::m_clientLog;
|
||||
|
||||
int Service::m_currentServerTime = 0;
|
||||
uint64_t Service::m_currentServerTime = 0;
|
||||
uint64_t Service::m_lastOfflineCheckTime = 0;
|
||||
uint64_t Service::m_lastStatusUpdateTime = 0;
|
||||
|
||||
bool Service::start()
|
||||
{
|
||||
uv_mutex_init(&m_mutex);
|
||||
|
||||
#ifndef XMRIG_NO_TLS
|
||||
if (Options::i()->ccPushoverToken() && Options::i()->ccPushoverUser())
|
||||
{
|
||||
uv_timer_init(uv_default_loop(), &m_timer);
|
||||
uv_timer_start(&m_timer, Service::onPushTimer,
|
||||
static_cast<uint64_t>(TIMER_INTERVAL),
|
||||
static_cast<uint64_t>(TIMER_INTERVAL));
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,6 +72,8 @@ void Service::release()
|
|||
{
|
||||
uv_mutex_lock(&m_mutex);
|
||||
|
||||
uv_timer_stop(&m_timer);
|
||||
|
||||
m_clientCommand.clear();
|
||||
m_clientStatus.clear();
|
||||
m_clientLog.clear();
|
||||
|
@ -156,7 +175,7 @@ unsigned Service::getClientConfig(const Options* options, const std::string& cli
|
|||
data << clientConfig.rdbuf();
|
||||
clientConfig.close();
|
||||
} else {
|
||||
std::ifstream defaultConfig("default_config.json");
|
||||
std::ifstream defaultConfig("default_miner_config.json");
|
||||
if (defaultConfig) {
|
||||
data << defaultConfig.rdbuf();
|
||||
defaultConfig.close();
|
||||
|
@ -230,7 +249,7 @@ unsigned Service::getClientStatusList(std::string& resp)
|
|||
}
|
||||
|
||||
auto time_point = std::chrono::system_clock::now();
|
||||
m_currentServerTime = std::chrono::system_clock::to_time_t(time_point);
|
||||
m_currentServerTime = static_cast<uint64_t>(std::chrono::system_clock::to_time_t(time_point));
|
||||
|
||||
document.AddMember("current_server_time", m_currentServerTime, allocator);
|
||||
document.AddMember("current_version", rapidjson::StringRef(Version::string().c_str()), allocator);
|
||||
|
@ -420,3 +439,100 @@ std::string Service::getClientConfigFileName(const Options* options, const std::
|
|||
|
||||
return clientConfigFileName;
|
||||
}
|
||||
|
||||
void Service::onPushTimer(uv_timer_t* handle)
|
||||
{
|
||||
auto time_point = std::chrono::system_clock::now();
|
||||
auto now = static_cast<uint64_t>(std::chrono::system_clock::to_time_t(time_point) * 1000);
|
||||
|
||||
if (Options::i()->ccPushOfflineMiners()) {
|
||||
sendMinerOfflinePush(now);
|
||||
m_lastOfflineCheckTime = now;
|
||||
}
|
||||
|
||||
if (Options::i()->ccPushPeriodicStatus()) {
|
||||
if (now > (m_lastStatusUpdateTime + STATUS_UPDATE_INTERVAL)) {
|
||||
sendServerStatusPush(now);
|
||||
m_lastStatusUpdateTime = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Service::sendMinerOfflinePush(uint64_t now)
|
||||
{
|
||||
for (auto clientStatus : m_clientStatus) {
|
||||
uint64_t lastStatus = clientStatus.second.getLastStatusUpdate() * 1000;
|
||||
uint64_t offlineThreshold = now - OFFLINE_TRESHOLD_IN_MS;
|
||||
|
||||
if (lastStatus < offlineThreshold) {
|
||||
offlineThreshold = now - (OFFLINE_TRESHOLD_IN_MS + (now - m_lastOfflineCheckTime));
|
||||
if (lastStatus > offlineThreshold) {
|
||||
std::stringstream message;
|
||||
message << "Miner: " << clientStatus.first << " just went offline!";
|
||||
|
||||
LOG_WARN("Send miner went offline push", clientStatus.first.c_str());
|
||||
triggerPush(APP_NAME " Offline Monitor", message.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Service::sendServerStatusPush(uint64_t now)
|
||||
{
|
||||
size_t onlineMiner = 0;
|
||||
size_t offlineMiner = 0;
|
||||
|
||||
double hashrateMedium = 0;
|
||||
double hashrateLong = 0;
|
||||
double avgTime = 0;
|
||||
|
||||
uint64_t sharesGood = 0;
|
||||
uint64_t sharesTotal = 0;
|
||||
uint64_t offlineThreshold = now - OFFLINE_TRESHOLD_IN_MS;
|
||||
|
||||
for (auto clientStatus : m_clientStatus) {
|
||||
if (offlineThreshold < clientStatus.second.getLastStatusUpdate() * 1000) {
|
||||
onlineMiner++;
|
||||
} else {
|
||||
offlineMiner++;
|
||||
}
|
||||
|
||||
hashrateMedium += clientStatus.second.getHashrateMedium();
|
||||
hashrateLong += clientStatus.second.getHashrateLong();
|
||||
|
||||
sharesGood += clientStatus.second.getSharesGood();
|
||||
sharesTotal += clientStatus.second.getSharesTotal();
|
||||
avgTime += clientStatus.second.getAvgTime();
|
||||
}
|
||||
|
||||
if (!m_clientStatus.empty()) {
|
||||
avgTime = avgTime / m_clientStatus.size();
|
||||
}
|
||||
|
||||
std::stringstream message;
|
||||
message << "Miners: " << onlineMiner << " (Online), " << offlineMiner << " (Offline)\n"
|
||||
<< "Shares: " << sharesGood << " (Good), " << sharesTotal - sharesGood << " (Bad)\n"
|
||||
<< "Hashrates: " << hashrateMedium << "h/s (1min), " << hashrateLong << "h/s (15min)\n"
|
||||
<< "Avg. Time: " << avgTime << "s";
|
||||
|
||||
LOG_WARN("Send Server status push");
|
||||
triggerPush(APP_NAME " Status", message.str());
|
||||
}
|
||||
|
||||
void Service::triggerPush(const std::string& title, const std::string& message)
|
||||
{
|
||||
#ifndef XMRIG_NO_TLS
|
||||
std::shared_ptr<httplib::Client> cli = std::make_shared<httplib::SSLClient>("api.pushover.net", 443);
|
||||
|
||||
httplib::Params params;
|
||||
params.emplace("token", Options::i()->ccPushoverToken());
|
||||
params.emplace("user", Options::i()->ccPushoverUser());
|
||||
params.emplace("title", title);
|
||||
params.emplace("message", httplib::detail::encode_url(message));
|
||||
|
||||
auto res = cli->Post("/1/messages.json", params);
|
||||
if (res) {
|
||||
LOG_WARN("Push response: %s", res->body.c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -36,6 +36,10 @@
|
|||
#include "ClientStatus.h"
|
||||
#include "ControlCommand.h"
|
||||
|
||||
#define TIMER_INTERVAL 10000
|
||||
#define OFFLINE_TRESHOLD_IN_MS 60000
|
||||
#define STATUS_UPDATE_INTERVAL 3600000
|
||||
|
||||
class Service
|
||||
{
|
||||
public:
|
||||
|
@ -61,15 +65,22 @@ private:
|
|||
|
||||
static std::string getClientConfigFileName(const Options *options, const std::string &clientId);
|
||||
|
||||
static void onPushTimer(uv_timer_t* handle);
|
||||
static void sendServerStatusPush(uint64_t now);
|
||||
static void sendMinerOfflinePush(uint64_t now);
|
||||
static void triggerPush(const std::string& title, const std::string& message);
|
||||
|
||||
private:
|
||||
static int m_currentServerTime;
|
||||
static uint64_t m_currentServerTime;
|
||||
static uint64_t m_lastOfflineCheckTime;
|
||||
static uint64_t m_lastStatusUpdateTime;
|
||||
|
||||
static std::map<std::string, ClientStatus> m_clientStatus;
|
||||
static std::map<std::string, ControlCommand> m_clientCommand;
|
||||
static std::map<std::string, std::list<std::string>> m_clientLog;
|
||||
|
||||
static uv_mutex_t m_mutex;
|
||||
|
||||
static uv_timer_t m_timer;
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_H__ */
|
||||
|
|
|
@ -59,9 +59,37 @@ static void print_commands()
|
|||
}
|
||||
}
|
||||
|
||||
void Summary::print_pushinfo() {
|
||||
if (Options::i()->ccPushoverToken() && Options::i()->ccPushoverUser())
|
||||
{
|
||||
#ifndef XMRIG_NO_TLS
|
||||
if (Options::i()->colors()) {
|
||||
Log::i()->text("\x1B[01;32m * \x1B[01;37mPUSHSERVICE: \x1B[01;32mEnabled");
|
||||
}
|
||||
else {
|
||||
Log::i()->text(" * PUSHSERVICE: Enabled");
|
||||
}
|
||||
#else
|
||||
if (Options::i()->colors()) {
|
||||
Log::i()->text("\x1B[01;32m * \x1B[01;37mPUSHSERVICE: \x1B[01;31mUnavailable requires TLS");
|
||||
}
|
||||
else {
|
||||
Log::i()->text(" * PUSHSERVICE: Unavailable requires TLS");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (Options::i()->colors()) {
|
||||
Log::i()->text("\x1B[01;32m * \x1B[01;37mPUSHSERVICE: \x1B[01;31mDisabled");
|
||||
}
|
||||
else {
|
||||
Log::i()->text(" * PUSHSERVICE: Disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Summary::print()
|
||||
{
|
||||
print_versions();
|
||||
print_pushinfo();
|
||||
print_commands();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue