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:
Ben Gräf 2018-11-28 08:59:44 +01:00 committed by GitHub
parent 408e7d3670
commit de9f64e515
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 288 additions and 40 deletions

View file

@ -206,7 +206,20 @@
} }
}, },
{ {
text: '<i class="fa fa-power-off"> Shutdown miner</i>', text: '<i class="fa fa-refresh"> Reebot machine</i>',
className: 'btn-warning',
enabled: false,
action: function () {
table.rows({selected: true}).eq(0).each(function (index) {
var row = table.row(index);
var data = row.data();
sendAction("REBOOT", data.client_status.client_id);
});
}
},
{
text: '<i class="fa fa-sign-out"> Stop miner</i>',
className: 'btn-danger', className: 'btn-danger',
enabled: false, enabled: false,
action: function () { action: function () {

View file

@ -258,6 +258,15 @@ void App::shutdown()
m_self->stop(false); m_self->stop(false);
} }
void App::reboot()
{
auto rebootCmd = m_self->m_options->ccRebootCmd();
if (rebootCmd) {
system(rebootCmd);
shutdown();
}
}
void App::onSignal(uv_signal_t* handle, int signum) void App::onSignal(uv_signal_t* handle, int signum)
{ {
switch (signum) switch (signum)
@ -299,6 +308,9 @@ void App::onCommandReceived(uv_async_t* async)
case ControlCommand::SHUTDOWN: case ControlCommand::SHUTDOWN:
App::shutdown(); App::shutdown();
break; break;
case ControlCommand::REBOOT:
App::reboot();
break;
case ControlCommand::PUBLISH_CONFIG:; case ControlCommand::PUBLISH_CONFIG:;
break; break;
} }

View file

@ -47,6 +47,7 @@ public:
static void restart(); static void restart();
static void shutdown(); static void shutdown();
static void reboot();
protected: protected:
void onConsoleCommand(char command) override; void onConsoleCommand(char command) override;

View file

@ -53,10 +53,10 @@ CpuImpl::CpuImpl()
} }
void CpuImpl::optimizeParameters(size_t& threadsCount, size_t& hashFactor, void CpuImpl::optimizeParameters(size_t& threadsCount, size_t& hashFactor,
Options::Algo algo, size_t maxCpuUsage, bool safeMode) Options::Algo algo, PowVariant powVariant, size_t maxCpuUsage, bool safeMode)
{ {
// limits hashfactor to maximum possible value defined by compiler flag // limits hashfactor to maximum possible value defined by compiler flag
hashFactor = std::min(hashFactor, algo == Options::ALGO_CRYPTONIGHT_HEAVY ? 3 : static_cast<size_t>(MAX_NUM_HASH_BLOCKS)); hashFactor = std::min(hashFactor, (algo == Options::ALGO_CRYPTONIGHT_HEAVY || powVariant == POW_XFH) ? 3 : static_cast<size_t>(MAX_NUM_HASH_BLOCKS));
if (!safeMode && threadsCount > 0 && hashFactor > 0) if (!safeMode && threadsCount > 0 && hashFactor > 0)
{ {
@ -81,7 +81,7 @@ void CpuImpl::optimizeParameters(size_t& threadsCount, size_t& hashFactor,
size_t maximumReasonableFactor = std::max(cache / algoBlockSize, static_cast<size_t>(1ul)); size_t maximumReasonableFactor = std::max(cache / algoBlockSize, static_cast<size_t>(1ul));
size_t maximumReasonableThreadCount = std::min(maximumReasonableFactor, m_totalThreads); size_t maximumReasonableThreadCount = std::min(maximumReasonableFactor, m_totalThreads);
size_t maximumReasonableHashFactor = std::min(maximumReasonableFactor, algo == Options::ALGO_CRYPTONIGHT_HEAVY ? 3 : static_cast<size_t>(MAX_NUM_HASH_BLOCKS)); size_t maximumReasonableHashFactor = std::min(maximumReasonableFactor, (algo == Options::ALGO_CRYPTONIGHT_HEAVY || powVariant == POW_XFH) ? 3 : static_cast<size_t>(MAX_NUM_HASH_BLOCKS));
if (safeMode) { if (safeMode) {
if (threadsCount > maximumReasonableThreadCount) { if (threadsCount > maximumReasonableThreadCount) {
@ -141,10 +141,10 @@ void Cpu::init()
CpuImpl::instance().init(); CpuImpl::instance().init();
} }
void Cpu::optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, void Cpu::optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, PowVariant powVariant,
size_t maxCpuUsage, bool safeMode) size_t maxCpuUsage, bool safeMode)
{ {
CpuImpl::instance().optimizeParameters(threadsCount, hashFactor, algo, maxCpuUsage, safeMode); CpuImpl::instance().optimizeParameters(threadsCount, hashFactor, algo, powVariant, maxCpuUsage, safeMode);
} }
int Cpu::setThreadAffinity(size_t threadId, int64_t affinityMask) int Cpu::setThreadAffinity(size_t threadId, int64_t affinityMask)

View file

@ -39,7 +39,7 @@ public:
static void init(); static void init();
static void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, static void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, PowVariant powVariant,
size_t maxCpuUsage, bool safeMode); size_t maxCpuUsage, bool safeMode);
static int setThreadAffinity(size_t threadId, int64_t affinityMask); static int setThreadAffinity(size_t threadId, int64_t affinityMask);

View file

@ -38,7 +38,7 @@ public:
CpuImpl(); CpuImpl();
void init(); void init();
void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, void optimizeParameters(size_t& threadsCount, size_t& hashFactor, Options::Algo algo, PowVariant powVariant,
size_t maxCpuUsage, bool safeMode); size_t maxCpuUsage, bool safeMode);
int setThreadAffinity(size_t threadId, int64_t affinityMask); int setThreadAffinity(size_t threadId, int64_t affinityMask);

View file

@ -99,7 +99,8 @@ Options:\n"
--cc-worker-id=ID custom worker-id for CC Server\n\ --cc-worker-id=ID custom worker-id for CC Server\n\
--cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)\n\ --cc-update-interval-s=N status update interval in seconds (default: 10 min: 1)\n\
--cc-use-remote-logging enable remote logging on CC Server\n\ --cc-use-remote-logging enable remote logging on CC Server\n\
--cc-upload-config-on-startup upload current miner config to CC Server on startup\n" --cc-upload-config-on-startup upload current miner config to CC Server on startup\n\
--cc-reboot-cmd command/bat to execute to Reboot miner\n"
# endif # endif
# endif # endif
@ -114,6 +115,10 @@ Options:\n"
--cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\ --cc-key-file=FILE when tls is turned on, use this to point to the right key file (default: server.key) \n\
--cc-client-log-lines-history=N maximum lines of log history kept per miner (default: 100)\n\ --cc-client-log-lines-history=N maximum lines of log history kept per miner (default: 100)\n\
--cc-client-config-folder=FOLDER Folder contains the client config files\n\ --cc-client-config-folder=FOLDER Folder contains the client config files\n\
--cc-pushover-user-key pushover user for push messages\n\
--cc-pushover-api-token your user key for pushover notifications\n\
--cc-push-miner-offline-info api token/keytoken of the application for pushover notifications\n\
--cc-push-periodic-mining-status send periodic mining status push\n\
--cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n" --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n"
# endif # endif
"\ "\
@ -187,6 +192,11 @@ static struct option const options[] = {
{ "cc-use-remote-logging", 0, nullptr, 4017 }, { "cc-use-remote-logging", 0, nullptr, 4017 },
{ "cc-client-log-lines-history", 1, nullptr, 4018 }, { "cc-client-log-lines-history", 1, nullptr, 4018 },
{ "cc-upload-config-on-startup", 0, nullptr, 4019 }, { "cc-upload-config-on-startup", 0, nullptr, 4019 },
{ "cc-reboot-cmd", 1, nullptr, 4021 },
{ "cc-pushover-user-key", 1, nullptr, 4022 },
{ "cc-pushover-api-token", 1, nullptr, 4023 },
{ "cc-push-miner-offline-info", 0, nullptr, 4024 },
{ "cc-push-periodic-mining-status", 0, nullptr, 4025 },
{ "daemonized", 0, nullptr, 4011 }, { "daemonized", 0, nullptr, 4011 },
{ "doublehash-thread-mask", 1, nullptr, 4013 }, { "doublehash-thread-mask", 1, nullptr, 4013 },
{ "multihash-thread-mask", 1, nullptr, 4013 }, { "multihash-thread-mask", 1, nullptr, 4013 },
@ -252,6 +262,7 @@ static struct option const cc_client_options[] = {
{ "use-tls", 0, nullptr, 4016 }, { "use-tls", 0, nullptr, 4016 },
{ "use-remote-logging", 0, nullptr, 4017 }, { "use-remote-logging", 0, nullptr, 4017 },
{ "upload-config-on-startup", 0, nullptr, 4019 }, { "upload-config-on-startup", 0, nullptr, 4019 },
{ "reboot-cmd", 1, nullptr, 4021 },
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
@ -266,6 +277,10 @@ static struct option const cc_server_options[] = {
{ "key-file", 1, nullptr, 4015 }, { "key-file", 1, nullptr, 4015 },
{ "use-tls", 0, nullptr, 4016 }, { "use-tls", 0, nullptr, 4016 },
{ "client-log-lines-history", 1, nullptr, 4018 }, { "client-log-lines-history", 1, nullptr, 4018 },
{ "pushover-user-key", 1, nullptr, 4022 },
{ "pushover-api-token", 1, nullptr, 4023 },
{ "push-miner-offline-info", 0, nullptr, 4024 },
{ "push-periodic-mining-status", 0, nullptr, 4025 },
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
@ -337,6 +352,8 @@ Options::Options(int argc, char **argv) :
m_ccUseTls(false), m_ccUseTls(false),
m_ccUseRemoteLogging(true), m_ccUseRemoteLogging(true),
m_ccUploadConfigOnStartup(true), m_ccUploadConfigOnStartup(true),
m_ccPushOfflineMiners(false),
m_ccPushPeriodicStatus(false),
m_fileName(Platform::defaultConfigName()), m_fileName(Platform::defaultConfigName()),
m_apiToken(nullptr), m_apiToken(nullptr),
m_apiWorkerId(nullptr), m_apiWorkerId(nullptr),
@ -351,6 +368,9 @@ Options::Options(int argc, char **argv) :
m_ccCustomDashboard(nullptr), m_ccCustomDashboard(nullptr),
m_ccKeyFile(nullptr), m_ccKeyFile(nullptr),
m_ccCertFile(nullptr), m_ccCertFile(nullptr),
m_ccRebootCmd(nullptr),
m_ccPushoverUser(nullptr),
m_ccPushoverToken(nullptr),
m_algo(ALGO_CRYPTONIGHT), m_algo(ALGO_CRYPTONIGHT),
m_algoVariant(AV0_AUTO), m_algoVariant(AV0_AUTO),
m_aesni(AESNI_AUTO), m_aesni(AESNI_AUTO),
@ -609,6 +629,21 @@ bool Options::parseArg(int key, const char *arg)
case 4020: /* --asm-optimization */ case 4020: /* --asm-optimization */
return parseAsmOptimization(arg); return parseAsmOptimization(arg);
case 4021: /* --cc-reboot-cmd */
m_ccRebootCmd = strdup(arg);
case 4022: /* --cc-pushover-user-key */
m_ccPushoverUser = strdup(arg);
case 4023: /* --cc-pushover-api-token */
m_ccPushoverToken = strdup(arg);
case 4024: /* --cc-push-miner-offline-info */
return parseBoolean(key, false);
case 4025: /* --cc-push-periodic-mining-status */
return parseBoolean(key, false);
case 't': /* --threads */ case 't': /* --threads */
if (strncmp(arg, "all", 3) == 0) { if (strncmp(arg, "all", 3) == 0) {
m_threads = Cpu::threads(); m_threads = Cpu::threads();
@ -849,6 +884,14 @@ bool Options::parseBoolean(int key, bool enable)
m_ccUploadConfigOnStartup = enable; m_ccUploadConfigOnStartup = enable;
break; break;
case 4024: /* --cc-push-miner-offline-info */
m_ccPushOfflineMiners = enable;
break;
case 4025: /* --cc-push-periodic-mining-status */
m_ccPushPeriodicStatus = enable;
break;
default: default:
break; break;
} }
@ -1151,12 +1194,12 @@ void Options::optimizeAlgorithmConfiguration()
m_aesni = aesniFromCpu; m_aesni = aesniFromCpu;
} }
if (m_algo == Options::ALGO_CRYPTONIGHT_HEAVY && m_hashFactor > 3) { if ((m_algo == Options::ALGO_CRYPTONIGHT_HEAVY || m_powVariant == PowVariant::POW_XFH) && m_hashFactor > 3) {
fprintf(stderr, "Maximum supported hashfactor for cryptonight-heavy is: 3\n"); fprintf(stderr, "Maximum supported hashfactor for cryptonight-heavy and XFH is: 3\n");
m_hashFactor = 3; m_hashFactor = 3;
} }
Cpu::optimizeParameters(m_threads, m_hashFactor, m_algo, m_maxCpuUsage, m_safe); Cpu::optimizeParameters(m_threads, m_hashFactor, m_algo, m_powVariant, m_maxCpuUsage, m_safe);
} }
bool Options::parseCCUrl(const char* url) bool Options::parseCCUrl(const char* url)

View file

@ -75,6 +75,8 @@ public:
inline bool ccUseTls() const { return m_ccUseTls; } inline bool ccUseTls() const { return m_ccUseTls; }
inline bool ccUseRemoteLogging() const { return m_ccUseRemoteLogging; } inline bool ccUseRemoteLogging() const { return m_ccUseRemoteLogging; }
inline bool ccUploadConfigOnStartup() const { return m_ccUploadConfigOnStartup; } inline bool ccUploadConfigOnStartup() const { return m_ccUploadConfigOnStartup; }
inline bool ccPushOfflineMiners() const { return m_ccPushOfflineMiners; }
inline bool ccPushPeriodicStatus() const { return m_ccPushPeriodicStatus; }
inline const char *fileName() const { return m_fileName; } inline const char *fileName() const { return m_fileName; }
inline const char *apiToken() const { return m_apiToken; } inline const char *apiToken() const { return m_apiToken; }
inline const char *apiWorkerId() const { return m_apiWorkerId; } inline const char *apiWorkerId() const { return m_apiWorkerId; }
@ -89,6 +91,9 @@ public:
inline const char *ccCustomDashboard() const { return m_ccCustomDashboard == nullptr ? "index.html" : m_ccCustomDashboard; } inline const char *ccCustomDashboard() const { return m_ccCustomDashboard == nullptr ? "index.html" : m_ccCustomDashboard; }
inline const char *ccKeyFile() const { return m_ccKeyFile == nullptr ? "server.key" : m_ccKeyFile; } inline const char *ccKeyFile() const { return m_ccKeyFile == nullptr ? "server.key" : m_ccKeyFile; }
inline const char *ccCertFile() const { return m_ccCertFile == nullptr ? "server.pem" : m_ccCertFile; } inline const char *ccCertFile() const { return m_ccCertFile == nullptr ? "server.pem" : m_ccCertFile; }
inline const char *ccRebootCmd() const { return (m_ccRebootCmd != nullptr && strlen(m_ccRebootCmd) > 0) ? m_ccRebootCmd : nullptr; }
inline const char *ccPushoverUser() const { return (m_ccPushoverUser != nullptr && strlen(m_ccPushoverUser) > 0) ? m_ccPushoverUser : nullptr; }
inline const char *ccPushoverToken() const { return (m_ccPushoverToken != nullptr && strlen(m_ccPushoverToken) > 0) ? m_ccPushoverToken : nullptr; }
inline const std::vector<Url*> &pools() const { return m_pools; } inline const std::vector<Url*> &pools() const { return m_pools; }
inline Algo algo() const { return m_algo; } inline Algo algo() const { return m_algo; }
inline PowVariant powVariant() const { return m_powVariant; } inline PowVariant powVariant() const { return m_powVariant; }
@ -152,6 +157,8 @@ private:
bool m_ccUseTls; bool m_ccUseTls;
bool m_ccUseRemoteLogging; bool m_ccUseRemoteLogging;
bool m_ccUploadConfigOnStartup; bool m_ccUploadConfigOnStartup;
bool m_ccPushOfflineMiners;
bool m_ccPushPeriodicStatus;
const char* m_fileName; const char* m_fileName;
char *m_apiToken; char *m_apiToken;
char *m_apiWorkerId; char *m_apiWorkerId;
@ -166,6 +173,9 @@ private:
char *m_ccCustomDashboard; char *m_ccCustomDashboard;
char *m_ccKeyFile; char *m_ccKeyFile;
char *m_ccCertFile; char *m_ccCertFile;
char *m_ccRebootCmd;
char *m_ccPushoverUser;
char *m_ccPushoverToken;
Algo m_algo; Algo m_algo;
AlgoVariant m_algoVariant; AlgoVariant m_algoVariant;
AesNi m_aesni; AesNi m_aesni;

View file

@ -29,6 +29,8 @@ class Summary
{ {
public: public:
static void print(); static void print();
static void print_pushinfo();
}; };

View file

@ -219,9 +219,11 @@ void CCClient::publishClientStatusReport()
LOG_WARN("[CC-Client] Command: PUBLISH_CONFIG received -> publish config"); LOG_WARN("[CC-Client] Command: PUBLISH_CONFIG received -> publish config");
publishConfig(); publishConfig();
}else if (controlCommand.getCommand() == ControlCommand::RESTART) { }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) { } 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()); m_self->m_async->data = reinterpret_cast<void*>(controlCommand.getCommand());

View file

@ -356,7 +356,7 @@ uint32_t ClientStatus::getAvgTime() const
return m_avgTime; return m_avgTime;
} }
std::time_t ClientStatus::getLastStatusUpdate() const uint64_t ClientStatus::getLastStatusUpdate() const
{ {
return m_lastStatusUpdate; return m_lastStatusUpdate;
} }
@ -516,7 +516,8 @@ bool ClientStatus::parseFromJson(const rapidjson::Document& document)
} }
auto time_point = std::chrono::system_clock::now(); 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; result = true;
} }

View file

@ -148,7 +148,7 @@ public:
void setAvgTime(uint32_t avgTime); void setAvgTime(uint32_t avgTime);
uint32_t getAvgTime() const; uint32_t getAvgTime() const;
std::time_t getLastStatusUpdate() const; uint64_t getLastStatusUpdate() const;
void setUptime(uint64_t uptime); void setUptime(uint64_t uptime);
uint64_t getUptime() const; uint64_t getUptime() const;
@ -203,8 +203,7 @@ private:
uint64_t m_uptime; uint64_t m_uptime;
uint32_t m_avgTime; uint32_t m_avgTime;
uint64_t m_lastStatusUpdate;
std::time_t m_lastStatusUpdate;
}; };
#endif /* __CLIENT_STATUS_H__ */ #endif /* __CLIENT_STATUS_H__ */

View file

@ -97,5 +97,6 @@ bool ControlCommand::isOneTimeCommand() const {
return m_command == ControlCommand::UPDATE_CONFIG || return m_command == ControlCommand::UPDATE_CONFIG ||
m_command == ControlCommand::PUBLISH_CONFIG || m_command == ControlCommand::PUBLISH_CONFIG ||
m_command == ControlCommand::RESTART || m_command == ControlCommand::RESTART ||
m_command == ControlCommand::SHUTDOWN; m_command == ControlCommand::SHUTDOWN ||
m_command == ControlCommand::REBOOT;
} }

View file

@ -21,13 +21,14 @@
#include <string> #include <string>
#include "rapidjson/document.h" #include "rapidjson/document.h"
static const char* command_str[6] = { static const char* command_str[7] = {
"START", "START",
"STOP", "STOP",
"UPDATE_CONFIG", "UPDATE_CONFIG",
"PUBLISH_CONFIG", "PUBLISH_CONFIG",
"RESTART", "RESTART",
"SHUTDOWN" "SHUTDOWN",
"REBOOT"
}; };
class ControlCommand class ControlCommand
@ -39,7 +40,8 @@ public:
UPDATE_CONFIG, UPDATE_CONFIG,
PUBLISH_CONFIG, PUBLISH_CONFIG,
RESTART, RESTART,
SHUTDOWN SHUTDOWN,
REBOOT
}; };
public: public:

View file

@ -26,6 +26,10 @@
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <iostream>
#include "log/Log.h"
#include <3rdparty/cpp-httplib/httplib.h>
#include <3rdparty/rapidjson/document.h> #include <3rdparty/rapidjson/document.h>
#include <3rdparty/rapidjson/stringbuffer.h> #include <3rdparty/rapidjson/stringbuffer.h>
#include <3rdparty/rapidjson/writer.h> #include <3rdparty/rapidjson/writer.h>
@ -33,21 +37,34 @@
#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 "version.h"
#include "log/Log.h"
#include "Service.h" #include "Service.h"
uv_mutex_t Service::m_mutex; uv_mutex_t Service::m_mutex;
uv_timer_t Service::m_timer;
std::map<std::string, ControlCommand> Service::m_clientCommand; std::map<std::string, ControlCommand> Service::m_clientCommand;
std::map<std::string, ClientStatus> Service::m_clientStatus; std::map<std::string, ClientStatus> Service::m_clientStatus;
std::map<std::string, std::list<std::string>> Service::m_clientLog; 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() bool Service::start()
{ {
uv_mutex_init(&m_mutex); 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; return true;
} }
@ -55,6 +72,8 @@ void Service::release()
{ {
uv_mutex_lock(&m_mutex); uv_mutex_lock(&m_mutex);
uv_timer_stop(&m_timer);
m_clientCommand.clear(); m_clientCommand.clear();
m_clientStatus.clear(); m_clientStatus.clear();
m_clientLog.clear(); m_clientLog.clear();
@ -156,7 +175,7 @@ unsigned Service::getClientConfig(const Options* options, const std::string& cli
data << clientConfig.rdbuf(); data << clientConfig.rdbuf();
clientConfig.close(); clientConfig.close();
} else { } else {
std::ifstream defaultConfig("default_config.json"); std::ifstream defaultConfig("default_miner_config.json");
if (defaultConfig) { if (defaultConfig) {
data << defaultConfig.rdbuf(); data << defaultConfig.rdbuf();
defaultConfig.close(); defaultConfig.close();
@ -230,7 +249,7 @@ unsigned Service::getClientStatusList(std::string& resp)
} }
auto time_point = std::chrono::system_clock::now(); 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_server_time", m_currentServerTime, allocator);
document.AddMember("current_version", rapidjson::StringRef(Version::string().c_str()), 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; 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
}

View file

@ -36,6 +36,10 @@
#include "ClientStatus.h" #include "ClientStatus.h"
#include "ControlCommand.h" #include "ControlCommand.h"
#define TIMER_INTERVAL 10000
#define OFFLINE_TRESHOLD_IN_MS 60000
#define STATUS_UPDATE_INTERVAL 3600000
class Service class Service
{ {
public: public:
@ -61,15 +65,22 @@ private:
static std::string getClientConfigFileName(const Options *options, const std::string &clientId); 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: 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, ClientStatus> m_clientStatus;
static std::map<std::string, ControlCommand> m_clientCommand; static std::map<std::string, ControlCommand> m_clientCommand;
static std::map<std::string, std::list<std::string>> m_clientLog; static std::map<std::string, std::list<std::string>> m_clientLog;
static uv_mutex_t m_mutex; static uv_mutex_t m_mutex;
static uv_timer_t m_timer;
}; };
#endif /* __SERVICE_H__ */ #endif /* __SERVICE_H__ */

View file

@ -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() void Summary::print()
{ {
print_versions(); print_versions();
print_pushinfo();
print_commands(); print_commands();
} }

View file

@ -36,6 +36,7 @@
"worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used)
"update-interval-s": 10, // status update interval in seconds (default: 10 min: 1) "update-interval-s": 10, // status update interval in seconds (default: 10 min: 1)
"use-remote-logging" : true, // enable remote logging on CC Server "use-remote-logging" : true, // enable remote logging on CC Server
"upload-config-on-startup" : true // upload current miner config to CC Server on startup "upload-config-on-startup" : true, // upload current miner config to CC Server on startup
"reboot-cmd" : "" // command to execute to reboot the OS
} }
} }

View file

@ -13,6 +13,11 @@
"pass": "pass", // admin pass for access CC Dashboard "pass": "pass", // admin pass for access CC Dashboard
"client-config-folder" : null, // folder which contains the client-config files (null=current) "client-config-folder" : null, // folder which contains the client-config files (null=current)
"client-log-lines-history" : 100, // maximum lines of log history kept per miner "client-log-lines-history" : 100, // maximum lines of log history kept per miner
"custom-dashboard" : "index.html" // dashboard html file "custom-dashboard" : "index.html", // dashboard html file
// Pushnotification Howto @ https://github.com/Bendr0id/xmrigCC/wiki/Setup-Pushover
"pushover-user-key" : "", // your user key for pushover notifications
"pushover-api-token" : "", // api token/keytoken of the application for pushover notifications
"push-miner-offline-info" : true, // push notification for offline miners
"push-periodic-mining-status" : true // push periodic status notification (every hour)
} }
} }

View file

@ -36,6 +36,7 @@
"worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used)
"update-interval-s": 10, // status update interval in seconds (default: 10 min: 1) "update-interval-s": 10, // status update interval in seconds (default: 10 min: 1)
"use-remote-logging" : true, // enable remote logging on CC Server "use-remote-logging" : true, // enable remote logging on CC Server
"upload-config-on-startup" : true // upload current miner config to CC Server on startup "upload-config-on-startup" : true, // upload current miner config to CC Server on startup
"reboot-cmd" : "" // command to execute to reboot the OS
} }
} }

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.8.4 (based on XMRig)" #define APP_VERSION "1.8.5-beta1 (based on XMRig)"
#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 8 #define APP_VER_MINOR 8
#define APP_VER_BUILD 4 #define APP_VER_BUILD 5
#define APP_VER_REV 0 #define APP_VER_REV 0
#ifndef NDEBUG #ifndef NDEBUG

View file

@ -32,10 +32,10 @@ void setMockedCpu(size_t numProcessors, size_t numCores, size_t numPusPerCore, s
Cpu::init(); Cpu::init();
} }
std::pair<size_t, size_t> testOptimize(size_t numThreads, size_t hashFactor, Options::Algo algo, bool safeMode, std::pair<size_t, size_t> testOptimize(size_t numThreads, size_t hashFactor, Options::Algo algo, PowVariant powVariant, bool safeMode,
size_t maxCpuUsage = 100) size_t maxCpuUsage = 100)
{ {
Cpu::optimizeParameters(numThreads, hashFactor, algo, maxCpuUsage, safeMode); Cpu::optimizeParameters(numThreads, hashFactor, algo, powVariant, maxCpuUsage, safeMode);
return std::pair<size_t, size_t>(numThreads, hashFactor); return std::pair<size_t, size_t>(numThreads, hashFactor);
} }