diff options
-rw-r--r-- | executor.cpp | 120 | ||||
-rw-r--r-- | executor.h | 1 | ||||
-rw-r--r-- | httpd.cpp | 7 | ||||
-rw-r--r-- | msgstruct.h | 2 | ||||
-rw-r--r-- | webdesign.cpp | 41 | ||||
-rw-r--r-- | webdesign.h | 5 |
6 files changed, 171 insertions, 5 deletions
diff --git a/executor.cpp b/executor.cpp index 383c53e..6388c4b 100644 --- a/executor.cpp +++ b/executor.cpp @@ -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); diff --git a/msgstruct.h b/msgstruct.h index d3b1709..6f4a6fb 100644 --- a/msgstruct.h +++ b/msgstruct.h @@ -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 =). diff --git a/webdesign.cpp b/webdesign.cpp index 958d312..e07b015 100644 --- a/webdesign.cpp +++ b/webdesign.cpp @@ -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]" + "}" +"}"; + diff --git a/webdesign.h b/webdesign.h index a516afb..92639a0 100644 --- a/webdesign.h +++ b/webdesign.h @@ -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[]; |