mirror of
https://github.com/jwinterm/xmr-stak.git
synced 2026-10-21 06:18:34 +02:00
Initial JSON API implementation
This commit is contained in:
+119
-1
@@ -460,6 +460,7 @@ void executor::ex_main()
|
||||
case EV_HTML_HASHRATE:
|
||||
case EV_HTML_RESULTS:
|
||||
case EV_HTML_CONNSTAT:
|
||||
case EV_HTML_JSON:
|
||||
http_report(ev.iName);
|
||||
break;
|
||||
|
||||
@@ -825,6 +826,117 @@ void executor::http_connection_report(std::string& out)
|
||||
out.append(sHtmlConnectionBodyLow);
|
||||
}
|
||||
|
||||
inline const char* hps_format_json(double h, char* buf, size_t l)
|
||||
{
|
||||
if(std::isnormal(h) || h == 0.0)
|
||||
{
|
||||
snprintf(buf, l, "%.1f", h);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "null";
|
||||
}
|
||||
|
||||
void executor::http_json_report(std::string& out)
|
||||
{
|
||||
const char *a, *b, *c;
|
||||
char num_a[32], num_b[32], num_c[32];
|
||||
char hr_buffer[64];
|
||||
std::string hr_thds, res_error, cn_error;
|
||||
|
||||
size_t nthd = pvThreads->size();
|
||||
double fTotal[3] = { 0.0, 0.0, 0.0};
|
||||
hr_thds.reserve(nthd * 32);
|
||||
|
||||
for(size_t i=0; i < nthd; i++)
|
||||
{
|
||||
if(i != 0) hr_thds.append(1, ',');
|
||||
|
||||
double fHps[3];
|
||||
fHps[0] = telem->calc_telemetry_data(2500, i);
|
||||
fHps[1] = telem->calc_telemetry_data(60000, i);
|
||||
fHps[2] = telem->calc_telemetry_data(900000, i);
|
||||
|
||||
fTotal[0] += fHps[0];
|
||||
fTotal[1] += fHps[1];
|
||||
fTotal[2] += fHps[2];
|
||||
|
||||
a = hps_format_json(fHps[0], num_a, sizeof(num_a));
|
||||
b = hps_format_json(fHps[1], num_b, sizeof(num_b));
|
||||
c = hps_format_json(fHps[2], num_c, sizeof(num_c));
|
||||
snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c);
|
||||
hr_thds.append(hr_buffer);
|
||||
}
|
||||
|
||||
a = hps_format_json(fTotal[0], num_a, sizeof(num_a));
|
||||
b = hps_format_json(fTotal[1], num_b, sizeof(num_b));
|
||||
c = hps_format_json(fTotal[2], num_c, sizeof(num_c));
|
||||
snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c);
|
||||
|
||||
a = hps_format_json(fHighestHps, num_a, sizeof(num_a));
|
||||
|
||||
size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes;
|
||||
size_t ln = vMineResults.size();
|
||||
|
||||
for(size_t i=1; i < ln; i++)
|
||||
iTotalRes += vMineResults[i].count;
|
||||
|
||||
jpsock* pool = pick_pool_by_id(dev_pool_id + 1);
|
||||
|
||||
size_t iConnSec = 0;
|
||||
if(pool->is_running() && pool->is_logged_in())
|
||||
{
|
||||
using namespace std::chrono;
|
||||
iConnSec = duration_cast<seconds>(system_clock::now() - tPoolConnTime).count();
|
||||
}
|
||||
|
||||
double fAvgResTime = 0.0;
|
||||
if(iPoolCallTimes.size() > 0)
|
||||
fAvgResTime = double(iConnSec) / iPoolCallTimes.size();
|
||||
|
||||
res_error.reserve((vMineResults.size() - 1) * 128);
|
||||
char buffer[256];
|
||||
for(size_t i=1; i < vMineResults.size(); i++)
|
||||
{
|
||||
if(i != 0) res_error.append(1, ',');
|
||||
|
||||
snprintf(buffer, sizeof(buffer), sJsonApiResultError, int_port(vMineResults[i].count),
|
||||
int_port(vMineResults[i].time.time_since_epoch().count()), vMineResults[i].msg.c_str());
|
||||
res_error.append(buffer);
|
||||
}
|
||||
|
||||
size_t n_calls = iPoolCallTimes.size();
|
||||
size_t iPoolPing = 0;
|
||||
if (n_calls > 1)
|
||||
{
|
||||
//Not-really-but-good-enough median
|
||||
std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end());
|
||||
iPoolPing = iPoolCallTimes[n_calls/2];
|
||||
}
|
||||
|
||||
cn_error.reserve(vSocketLog.size() * 128);
|
||||
for(size_t i=0; i < vSocketLog.size(); i++)
|
||||
{
|
||||
if(i != 0) cn_error.append(1, ',');
|
||||
|
||||
snprintf(buffer, sizeof(buffer), sJsonApiConnectionError,
|
||||
int_port(vSocketLog[i].time.time_since_epoch().count()), vSocketLog[i].msg.c_str());
|
||||
cn_error.append(buffer);
|
||||
}
|
||||
|
||||
size_t bb_size = 1024 + hr_thds.size() + res_error.size() + cn_error.size();
|
||||
std::unique_ptr<char[]> bigbuf( new char[ bb_size ] );
|
||||
|
||||
int bb_len = snprintf(bigbuf.get(), bb_size, sJsonApiFormat,
|
||||
hr_thds.c_str(), hr_buffer, a,
|
||||
int_port(iPoolDiff), int_port(iGoodRes), int_port(iTotalRes), fAvgResTime, int_port(iPoolHashes),
|
||||
int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]), int_port(iTopDiff[4]),
|
||||
int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]), int_port(iTopDiff[8]), int_port(iTopDiff[9]),
|
||||
res_error.c_str(), jconf::inst()->GetPoolAddress(), int_port(iConnSec), int_port(iPoolPing), cn_error.c_str());
|
||||
|
||||
out = std::string(bigbuf.get(), bigbuf.get() + bb_len);
|
||||
}
|
||||
|
||||
void executor::http_report(ex_event_name ev)
|
||||
{
|
||||
assert(pHttpString != nullptr);
|
||||
@@ -842,6 +954,11 @@ void executor::http_report(ex_event_name ev)
|
||||
case EV_HTML_CONNSTAT:
|
||||
http_connection_report(*pHttpString);
|
||||
break;
|
||||
|
||||
case EV_HTML_JSON:
|
||||
http_json_report(*pHttpString);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
@@ -855,7 +972,8 @@ void executor::get_http_report(ex_event_name ev_id, std::string& data)
|
||||
std::lock_guard<std::mutex> lck(httpMutex);
|
||||
|
||||
assert(pHttpString == nullptr);
|
||||
assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS || ev_id == EV_HTML_CONNSTAT);
|
||||
assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS
|
||||
|| ev_id == EV_HTML_CONNSTAT || ev_id == EV_HTML_JSON);
|
||||
|
||||
pHttpString = &data;
|
||||
httpReady = std::promise<void>();
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
void http_hashrate_report(std::string& out);
|
||||
void http_result_report(std::string& out);
|
||||
void http_connection_report(std::string& out);
|
||||
void http_json_report(std::string& out);
|
||||
|
||||
void http_report(ex_event_name ev);
|
||||
void print_report(ex_event_name ev);
|
||||
|
||||
@@ -84,6 +84,13 @@ int httpd::req_handler(void * cls,
|
||||
MHD_add_response_header(rsp, "ETag", sHtmlCssEtag);
|
||||
MHD_add_response_header(rsp, "Content-Type", "text/css; charset=utf-8");
|
||||
}
|
||||
else if(strcasecmp(url, "/api.json") == 0)
|
||||
{
|
||||
executor::inst()->get_http_report(EV_HTML_JSON, str);
|
||||
|
||||
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
|
||||
MHD_add_response_header(rsp, "Content-Type", "application/json; charset=utf-8");
|
||||
}
|
||||
else if(strcasecmp(url, "/h") == 0 || strcasecmp(url, "/hashrate") == 0)
|
||||
{
|
||||
executor::inst()->get_http_report(EV_HTML_HASHRATE, str);
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ struct job_result
|
||||
enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR,
|
||||
EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_RECONNECT,
|
||||
EV_SWITCH_POOL, EV_DEV_POOL_EXIT, EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT,
|
||||
EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT };
|
||||
EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT, EV_HTML_JSON };
|
||||
|
||||
/*
|
||||
This is how I learned to stop worrying and love c++11 =).
|
||||
|
||||
+38
-3
@@ -27,12 +27,12 @@ extern const char sHtmlCssFile [] =
|
||||
"a:active {"
|
||||
"color: rgb(204, 122, 0);"
|
||||
"}"
|
||||
|
||||
|
||||
".all {"
|
||||
"max-width:600px;"
|
||||
"margin: auto;"
|
||||
"}"
|
||||
|
||||
|
||||
".header {"
|
||||
"background-color: rgb(30, 30, 30);"
|
||||
"color: white;"
|
||||
@@ -167,6 +167,41 @@ extern const char sHtmlResultBodyHigh [] =
|
||||
extern const char sHtmlResultTableRow [] =
|
||||
"<tr><td colspan='2'>%s</td></tr><tr><td>%llu</td><td>%s</td></tr>";
|
||||
|
||||
extern const char sHtmlResultBodyLow [] =
|
||||
extern const char sHtmlResultBodyLow[] =
|
||||
"</table></div></div></body></html>";
|
||||
|
||||
extern const char sJsonApiThdHashrate[] =
|
||||
"[%s,%s,%s]";
|
||||
|
||||
extern const char sJsonApiResultError[] =
|
||||
"{\"count\":%llu,\"last_seen\":%llu,\"text\":\"%s\"}";
|
||||
|
||||
extern const char sJsonApiConnectionError[] =
|
||||
"{\"last_seen\":%llu,\"text\":\"%s\"}";
|
||||
|
||||
extern const char sJsonApiFormat [] =
|
||||
"{"
|
||||
"\"hashrate\":{"
|
||||
"\"threads\":[%s],"
|
||||
"\"total\":%s,"
|
||||
"\"highest\":%s"
|
||||
"},"
|
||||
|
||||
"\"results\":{"
|
||||
"\"diff_current\":%llu,"
|
||||
"\"shares_good\":%llu,"
|
||||
"\"shares_total\":%llu,"
|
||||
"\"avg_time\":%.1f,"
|
||||
"\"hashes_total\":%llu,"
|
||||
"\"best\":[%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu],"
|
||||
"\"error_log\":[%s]"
|
||||
"},"
|
||||
|
||||
"\"connection\":{"
|
||||
"\"pool\": \"%s\","
|
||||
"\"uptime\":%llu,"
|
||||
"\"ping\":%llu,"
|
||||
"\"error_log\":[%s]"
|
||||
"}"
|
||||
"}";
|
||||
|
||||
|
||||
@@ -17,3 +17,8 @@ extern const char sHtmlConnectionBodyLow[];
|
||||
extern const char sHtmlResultBodyHigh[];
|
||||
extern const char sHtmlResultTableRow[];
|
||||
extern const char sHtmlResultBodyLow[];
|
||||
|
||||
extern const char sJsonApiThdHashrate[];
|
||||
extern const char sJsonApiResultError[];
|
||||
extern const char sJsonApiConnectionError[];
|
||||
extern const char sJsonApiFormat[];
|
||||
|
||||
Reference in New Issue
Block a user