mirror of
https://github.com/xmrig/xmrig.git
synced 2025-01-03 09:29:46 +00:00
Restored API.
This commit is contained in:
parent
e39ddeeea2
commit
f8f9d6c0ef
16 changed files with 272 additions and 352 deletions
|
@ -205,15 +205,17 @@ endif()
|
||||||
|
|
||||||
if (WITH_HTTPD)
|
if (WITH_HTTPD)
|
||||||
set(HTTPD_SOURCES
|
set(HTTPD_SOURCES
|
||||||
src/api/Api.h
|
|
||||||
src/api/interfaces/IApiRequest.h
|
|
||||||
src/api/requests/ApiRequest.h
|
|
||||||
src/api/requests/ApiRequest.cpp
|
|
||||||
src/api/requests/HttpApiRequest.h
|
|
||||||
src/api/Httpd.h
|
|
||||||
src/api/Api.cpp
|
src/api/Api.cpp
|
||||||
src/api/requests/HttpApiRequest.cpp
|
src/api/Api.h
|
||||||
src/api/Httpd.cpp
|
src/api/Httpd.cpp
|
||||||
|
src/api/Httpd.h
|
||||||
|
src/api/interfaces/IApiRequest.h
|
||||||
|
src/api/requests/ApiRequest.cpp
|
||||||
|
src/api/requests/ApiRequest.h
|
||||||
|
src/api/requests/HttpApiRequest.cpp
|
||||||
|
src/api/requests/HttpApiRequest.h
|
||||||
|
src/api/v1/ApiRouter.cpp
|
||||||
|
src/api/v1/ApiRouter.h
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
set(HTTPD_SOURCES "")
|
set(HTTPD_SOURCES "")
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "api/Api.h"
|
#include "api/Api.h"
|
||||||
#include "api/interfaces/IApiListener.h"
|
#include "api/interfaces/IApiListener.h"
|
||||||
#include "api/requests/HttpApiRequest.h"
|
#include "api/requests/HttpApiRequest.h"
|
||||||
|
#include "api/v1/ApiRouter.h"
|
||||||
#include "base/tools/Buffer.h"
|
#include "base/tools/Buffer.h"
|
||||||
#include "common/crypto/keccak.h"
|
#include "common/crypto/keccak.h"
|
||||||
#include "core/config/Config.h"
|
#include "core/config/Config.h"
|
||||||
|
@ -51,11 +52,16 @@ xmrig::Api::Api(Controller *controller) :
|
||||||
controller->addListener(this);
|
controller->addListener(this);
|
||||||
|
|
||||||
genId(m_controller->config()->apiId());
|
genId(m_controller->config()->apiId());
|
||||||
|
|
||||||
|
m_v1 = new ApiRouter(controller);
|
||||||
|
addListener(m_v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
xmrig::Api::~Api()
|
xmrig::Api::~Api()
|
||||||
{
|
{
|
||||||
|
delete m_v1;
|
||||||
|
|
||||||
# ifdef XMRIG_FEATURE_HTTP
|
# ifdef XMRIG_FEATURE_HTTP
|
||||||
delete m_httpd;
|
delete m_httpd;
|
||||||
# endif
|
# endif
|
||||||
|
@ -103,10 +109,12 @@ void xmrig::Api::onConfigChanged(Config *config, Config *previousConfig)
|
||||||
|
|
||||||
void xmrig::Api::exec(IApiRequest &request)
|
void xmrig::Api::exec(IApiRequest &request)
|
||||||
{
|
{
|
||||||
if (request.method() == IApiRequest::METHOD_GET && request.url() == "/1/summary") {
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) {
|
||||||
request.accept();
|
request.accept();
|
||||||
request.reply().AddMember("id", rapidjson::StringRef(m_id), request.doc().GetAllocator());
|
request.reply().AddMember("id", StringRef(m_id), request.doc().GetAllocator());
|
||||||
request.reply().AddMember("worker_id", rapidjson::StringRef(m_workerId), request.doc().GetAllocator());;
|
request.reply().AddMember("worker_id", StringRef(m_workerId), request.doc().GetAllocator());;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IApiListener *listener : m_listeners) {
|
for (IApiListener *listener : m_listeners) {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
namespace xmrig {
|
namespace xmrig {
|
||||||
|
|
||||||
|
|
||||||
|
class ApiRouter;
|
||||||
class Controller;
|
class Controller;
|
||||||
class Httpd;
|
class Httpd;
|
||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
|
@ -65,6 +66,7 @@ private:
|
||||||
void genId(const String &id);
|
void genId(const String &id);
|
||||||
void genWorkerId(const String &id);
|
void genWorkerId(const String &id);
|
||||||
|
|
||||||
|
ApiRouter *m_v1;
|
||||||
char m_id[32];
|
char m_id[32];
|
||||||
char m_workerId[128];
|
char m_workerId[128];
|
||||||
Controller *m_controller;
|
Controller *m_controller;
|
||||||
|
|
|
@ -1,292 +0,0 @@
|
||||||
/* XMRig
|
|
||||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
|
||||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
|
||||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
|
||||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
|
||||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
|
||||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
|
||||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
|
||||||
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <uv.h>
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
# include "winsock2.h"
|
|
||||||
#else
|
|
||||||
# include "unistd.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "api/ApiRouter.h"
|
|
||||||
#include "base/tools/Buffer.h"
|
|
||||||
#include "common/api/HttpReply.h"
|
|
||||||
#include "common/api/HttpRequest.h"
|
|
||||||
#include "common/cpu/Cpu.h"
|
|
||||||
#include "common/crypto/keccak.h"
|
|
||||||
#include "common/Platform.h"
|
|
||||||
#include "core/Config.h"
|
|
||||||
#include "core/Controller.h"
|
|
||||||
#include "interfaces/IThread.h"
|
|
||||||
#include "rapidjson/document.h"
|
|
||||||
#include "rapidjson/prettywriter.h"
|
|
||||||
#include "rapidjson/stringbuffer.h"
|
|
||||||
#include "version.h"
|
|
||||||
#include "workers/Hashrate.h"
|
|
||||||
#include "workers/Workers.h"
|
|
||||||
|
|
||||||
|
|
||||||
static inline double normalize(double d)
|
|
||||||
{
|
|
||||||
if (!isnormal(d)) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return floor(d * 100.0) / 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ApiRouter::ApiRouter(xmrig::Controller *controller) :
|
|
||||||
m_controller(controller)
|
|
||||||
{
|
|
||||||
memset(m_workerId, 0, sizeof(m_workerId));
|
|
||||||
|
|
||||||
setWorkerId(controller->config()->apiWorkerId());
|
|
||||||
genId(controller->config()->apiId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ApiRouter::~ApiRouter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::ApiRouter::get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const
|
|
||||||
{
|
|
||||||
rapidjson::Document doc;
|
|
||||||
|
|
||||||
if (req.match("/1/config")) {
|
|
||||||
if (req.isRestricted()) {
|
|
||||||
reply.status = 403;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_controller->config()->getJSON(doc);
|
|
||||||
|
|
||||||
return finalize(reply, doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.match("/1/threads")) {
|
|
||||||
getThreads(doc);
|
|
||||||
|
|
||||||
return finalize(reply, doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.SetObject();
|
|
||||||
|
|
||||||
getIdentify(doc);
|
|
||||||
getMiner(doc);
|
|
||||||
getHashrate(doc);
|
|
||||||
|
|
||||||
return finalize(reply, doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply)
|
|
||||||
{
|
|
||||||
if (req.method() == xmrig::HttpRequest::Put && req.match("/1/config")) {
|
|
||||||
m_controller->config()->reload(req.body());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply.status = 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig)
|
|
||||||
{
|
|
||||||
updateWorkerId(config->apiWorkerId(), previousConfig->apiWorkerId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const
|
|
||||||
{
|
|
||||||
rapidjson::StringBuffer buffer(nullptr, 4096);
|
|
||||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
|
||||||
writer.SetMaxDecimalPlaces(10);
|
|
||||||
doc.Accept(writer);
|
|
||||||
|
|
||||||
reply.status = 200;
|
|
||||||
reply.buf = strdup(buffer.GetString());
|
|
||||||
reply.size = buffer.GetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::genId(const char *id)
|
|
||||||
{
|
|
||||||
memset(m_id, 0, sizeof(m_id));
|
|
||||||
|
|
||||||
if (id && strlen(id) > 0) {
|
|
||||||
strncpy(m_id, id, sizeof(m_id) - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uv_interface_address_t *interfaces;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
if (uv_interface_addresses(&interfaces, &count) < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
if (!interfaces[i].is_internal && interfaces[i].address.address4.sin_family == AF_INET) {
|
|
||||||
uint8_t hash[200];
|
|
||||||
const size_t addrSize = sizeof(interfaces[i].phys_addr);
|
|
||||||
const size_t inSize = strlen(APP_KIND) + addrSize + sizeof(uint16_t);
|
|
||||||
const uint16_t port = static_cast<uint16_t>(m_controller->config()->http().port());
|
|
||||||
|
|
||||||
uint8_t *input = new uint8_t[inSize]();
|
|
||||||
memcpy(input, &port, sizeof(uint16_t));
|
|
||||||
memcpy(input + sizeof(uint16_t), interfaces[i].phys_addr, addrSize);
|
|
||||||
memcpy(input + sizeof(uint16_t) + addrSize, APP_KIND, strlen(APP_KIND));
|
|
||||||
|
|
||||||
xmrig::keccak(input, inSize, hash);
|
|
||||||
xmrig::Buffer::toHex(hash, 8, m_id);
|
|
||||||
|
|
||||||
delete [] input;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uv_free_interface_addresses(interfaces, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::getHashrate(rapidjson::Document &doc) const
|
|
||||||
{
|
|
||||||
auto &allocator = doc.GetAllocator();
|
|
||||||
|
|
||||||
rapidjson::Value hashrate(rapidjson::kObjectType);
|
|
||||||
rapidjson::Value total(rapidjson::kArrayType);
|
|
||||||
rapidjson::Value threads(rapidjson::kArrayType);
|
|
||||||
|
|
||||||
const Hashrate *hr = Workers::hashrate();
|
|
||||||
|
|
||||||
total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator);
|
|
||||||
total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator);
|
|
||||||
total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < Workers::threads(); i++) {
|
|
||||||
rapidjson::Value thread(rapidjson::kArrayType);
|
|
||||||
thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator);
|
|
||||||
thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator);
|
|
||||||
thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator);
|
|
||||||
|
|
||||||
threads.PushBack(thread, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashrate.AddMember("total", total, allocator);
|
|
||||||
hashrate.AddMember("highest", normalize(hr->highest()), allocator);
|
|
||||||
hashrate.AddMember("threads", threads, allocator);
|
|
||||||
doc.AddMember("hashrate", hashrate, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::getIdentify(rapidjson::Document &doc) const
|
|
||||||
{
|
|
||||||
doc.AddMember("id", rapidjson::StringRef(m_id), doc.GetAllocator());
|
|
||||||
doc.AddMember("worker_id", rapidjson::StringRef(m_workerId), doc.GetAllocator());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::getMiner(rapidjson::Document &doc) const
|
|
||||||
{
|
|
||||||
using namespace xmrig;
|
|
||||||
auto &allocator = doc.GetAllocator();
|
|
||||||
|
|
||||||
rapidjson::Value cpu(rapidjson::kObjectType);
|
|
||||||
cpu.AddMember("brand", rapidjson::StringRef(Cpu::info()->brand()), allocator);
|
|
||||||
cpu.AddMember("aes", Cpu::info()->hasAES(), allocator);
|
|
||||||
cpu.AddMember("x64", Cpu::info()->isX64(), allocator);
|
|
||||||
cpu.AddMember("sockets", Cpu::info()->sockets(), allocator);
|
|
||||||
|
|
||||||
doc.AddMember("version", APP_VERSION, allocator);
|
|
||||||
doc.AddMember("kind", APP_KIND, allocator);
|
|
||||||
doc.AddMember("ua", rapidjson::StringRef(Platform::userAgent()), allocator);
|
|
||||||
doc.AddMember("cpu", cpu, allocator);
|
|
||||||
doc.AddMember("algo", rapidjson::StringRef(m_controller->config()->algorithm().name()), allocator);
|
|
||||||
doc.AddMember("hugepages", Workers::hugePages() > 0, allocator);
|
|
||||||
doc.AddMember("donate_level", m_controller->config()->pools().donateLevel(), allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::getThreads(rapidjson::Document &doc) const
|
|
||||||
{
|
|
||||||
doc.SetObject();
|
|
||||||
auto &allocator = doc.GetAllocator();
|
|
||||||
const Hashrate *hr = Workers::hashrate();
|
|
||||||
|
|
||||||
Workers::threadsSummary(doc);
|
|
||||||
|
|
||||||
const std::vector<xmrig::IThread *> &threads = m_controller->config()->threads();
|
|
||||||
rapidjson::Value list(rapidjson::kArrayType);
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
for (const xmrig::IThread *thread : threads) {
|
|
||||||
rapidjson::Value value = thread->toAPI(doc);
|
|
||||||
|
|
||||||
rapidjson::Value hashrate(rapidjson::kArrayType);
|
|
||||||
hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator);
|
|
||||||
hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator);
|
|
||||||
hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
|
|
||||||
value.AddMember("hashrate", hashrate, allocator);
|
|
||||||
list.PushBack(value, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.AddMember("threads", list, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::setWorkerId(const char *id)
|
|
||||||
{
|
|
||||||
memset(m_workerId, 0, sizeof(m_workerId));
|
|
||||||
|
|
||||||
if (id && strlen(id) > 0) {
|
|
||||||
strncpy(m_workerId, id, sizeof(m_workerId) - 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gethostname(m_workerId, sizeof(m_workerId) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ApiRouter::updateWorkerId(const char *id, const char *previousId)
|
|
||||||
{
|
|
||||||
if (id == previousId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id != nullptr && previousId != nullptr && strcmp(id, previousId) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setWorkerId(id);
|
|
||||||
}
|
|
|
@ -25,10 +25,12 @@
|
||||||
|
|
||||||
#include "api/requests/HttpApiRequest.h"
|
#include "api/requests/HttpApiRequest.h"
|
||||||
#include "base/net/http/HttpRequest.h"
|
#include "base/net/http/HttpRequest.h"
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
|
|
||||||
|
|
||||||
xmrig::HttpApiRequest::HttpApiRequest(const HttpRequest &req, bool restricted) :
|
xmrig::HttpApiRequest::HttpApiRequest(const HttpRequest &req, bool restricted) :
|
||||||
ApiRequest(SOURCE_HTTP, restricted),
|
ApiRequest(SOURCE_HTTP, restricted),
|
||||||
|
m_parsed(false),
|
||||||
m_req(req),
|
m_req(req),
|
||||||
m_res(req.id()),
|
m_res(req.id()),
|
||||||
m_url(req.url.c_str())
|
m_url(req.url.c_str())
|
||||||
|
@ -36,20 +38,39 @@ xmrig::HttpApiRequest::HttpApiRequest(const HttpRequest &req, bool restricted) :
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rapidjson::Value &xmrig::HttpApiRequest::json() const
|
||||||
|
{
|
||||||
|
return m_body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
xmrig::IApiRequest::Method xmrig::HttpApiRequest::method() const
|
xmrig::IApiRequest::Method xmrig::HttpApiRequest::method() const
|
||||||
{
|
{
|
||||||
return static_cast<IApiRequest::Method>(m_req.method);
|
return static_cast<IApiRequest::Method>(m_req.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HttpApiRequest::accept()
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
ApiRequest::accept();
|
||||||
|
|
||||||
|
if (!m_parsed && !m_req.body.empty()) {
|
||||||
|
m_parsed = true;
|
||||||
|
m_body.Parse<kParseCommentsFlag | kParseTrailingCommasFlag>(m_req.body.c_str());
|
||||||
|
|
||||||
|
if (m_body.HasParseError()) {
|
||||||
|
reply().AddMember("error", StringRef(GetParseError_En(m_body.GetParseError())), doc().GetAllocator());;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::HttpApiRequest::done(int status)
|
void xmrig::HttpApiRequest::done(int status)
|
||||||
{
|
{
|
||||||
ApiRequest::done(status);
|
ApiRequest::done(status);
|
||||||
|
|
||||||
if (status >= 400) {
|
|
||||||
reply().AddMember("status", status, doc().GetAllocator());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_res.setStatus(status);
|
m_res.setStatus(status);
|
||||||
m_res.end();
|
m_res.end();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,15 +44,17 @@ public:
|
||||||
HttpApiRequest(const HttpRequest &req, bool restricted);
|
HttpApiRequest(const HttpRequest &req, bool restricted);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline const rapidjson::Value &json() const override { return m_body; }
|
|
||||||
inline rapidjson::Document &doc() override { return m_res.doc(); }
|
inline rapidjson::Document &doc() override { return m_res.doc(); }
|
||||||
inline rapidjson::Value &reply() override { return m_res.doc(); }
|
inline rapidjson::Value &reply() override { return m_res.doc(); }
|
||||||
inline const String &url() const override { return m_url; }
|
inline const String &url() const override { return m_url; }
|
||||||
|
|
||||||
|
const rapidjson::Value &json() const override;
|
||||||
Method method() const override;
|
Method method() const override;
|
||||||
|
void accept() override;
|
||||||
void done(int status) override;
|
void done(int status) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_parsed;
|
||||||
const HttpRequest &m_req;
|
const HttpRequest &m_req;
|
||||||
HttpApiResponse m_res;
|
HttpApiResponse m_res;
|
||||||
rapidjson::Document m_body;
|
rapidjson::Document m_body;
|
||||||
|
|
179
src/api/v1/ApiRouter.cpp
Normal file
179
src/api/v1/ApiRouter.cpp
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/* XMRig
|
||||||
|
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||||
|
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||||
|
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||||
|
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||||
|
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||||
|
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||||
|
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||||
|
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "api/interfaces/IApiRequest.h"
|
||||||
|
#include "api/v1/ApiRouter.h"
|
||||||
|
#include "common/cpu/Cpu.h"
|
||||||
|
#include "common/Platform.h"
|
||||||
|
#include "core/config/Config.h"
|
||||||
|
#include "core/Controller.h"
|
||||||
|
#include "interfaces/IThread.h"
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "workers/Hashrate.h"
|
||||||
|
#include "workers/Workers.h"
|
||||||
|
|
||||||
|
|
||||||
|
static inline double normalize(double d)
|
||||||
|
{
|
||||||
|
if (!isnormal(d)) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return floor(d * 100.0) / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xmrig::ApiRouter::ApiRouter(xmrig::Controller *controller) :
|
||||||
|
m_controller(controller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xmrig::ApiRouter::~ApiRouter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::ApiRouter::onRequest(IApiRequest &request)
|
||||||
|
{
|
||||||
|
printf("xmrig::ApiRouter::onRequest\n %d", request.method());
|
||||||
|
|
||||||
|
if (request.method() == IApiRequest::METHOD_GET) {
|
||||||
|
if (request.url() == "/1/summary" || request.url() == "/api.json") {
|
||||||
|
request.accept();
|
||||||
|
getMiner(request.reply(), request.doc());
|
||||||
|
getHashrate(request.reply(), request.doc());
|
||||||
|
}
|
||||||
|
else if (request.url() == "/1/threads") {
|
||||||
|
request.accept();
|
||||||
|
getThreads(request.reply(), request.doc());
|
||||||
|
}
|
||||||
|
else if (request.url() == "/1/config") {
|
||||||
|
if (request.isRestricted()) {
|
||||||
|
return request.done(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_controller->config()->getJSON(request.doc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request.method() == IApiRequest::METHOD_PUT || request.method() == IApiRequest::METHOD_POST) {
|
||||||
|
if (request.url() == "/1/config") {
|
||||||
|
request.accept();
|
||||||
|
|
||||||
|
if (!m_controller->config()->reload(request.json())) {
|
||||||
|
return request.done(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.done(204);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::ApiRouter::getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
auto &allocator = doc.GetAllocator();
|
||||||
|
|
||||||
|
Value hashrate(kObjectType);
|
||||||
|
Value total(kArrayType);
|
||||||
|
Value threads(kArrayType);
|
||||||
|
|
||||||
|
const Hashrate *hr = Workers::hashrate();
|
||||||
|
|
||||||
|
total.PushBack(normalize(hr->calc(Hashrate::ShortInterval)), allocator);
|
||||||
|
total.PushBack(normalize(hr->calc(Hashrate::MediumInterval)), allocator);
|
||||||
|
total.PushBack(normalize(hr->calc(Hashrate::LargeInterval)), allocator);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Workers::threads(); i++) {
|
||||||
|
Value thread(kArrayType);
|
||||||
|
thread.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator);
|
||||||
|
thread.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator);
|
||||||
|
thread.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator);
|
||||||
|
|
||||||
|
threads.PushBack(thread, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashrate.AddMember("total", total, allocator);
|
||||||
|
hashrate.AddMember("highest", normalize(hr->highest()), allocator);
|
||||||
|
hashrate.AddMember("threads", threads, allocator);
|
||||||
|
reply.AddMember("hashrate", hashrate, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::ApiRouter::getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
auto &allocator = doc.GetAllocator();
|
||||||
|
|
||||||
|
Value cpu(kObjectType);
|
||||||
|
cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator);
|
||||||
|
cpu.AddMember("aes", Cpu::info()->hasAES(), allocator);
|
||||||
|
cpu.AddMember("x64", Cpu::info()->isX64(), allocator);
|
||||||
|
cpu.AddMember("sockets", Cpu::info()->sockets(), allocator);
|
||||||
|
|
||||||
|
reply.AddMember("version", APP_VERSION, allocator);
|
||||||
|
reply.AddMember("kind", APP_KIND, allocator);
|
||||||
|
reply.AddMember("ua", StringRef(Platform::userAgent()), allocator);
|
||||||
|
reply.AddMember("cpu", cpu, allocator);
|
||||||
|
reply.AddMember("algo", StringRef(m_controller->config()->algorithm().name()), allocator);
|
||||||
|
reply.AddMember("hugepages", Workers::hugePages() > 0, allocator);
|
||||||
|
reply.AddMember("donate_level", m_controller->config()->pools().donateLevel(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::ApiRouter::getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const
|
||||||
|
{
|
||||||
|
using namespace rapidjson;
|
||||||
|
auto &allocator = doc.GetAllocator();
|
||||||
|
const Hashrate *hr = Workers::hashrate();
|
||||||
|
|
||||||
|
Workers::threadsSummary(doc);
|
||||||
|
|
||||||
|
const std::vector<xmrig::IThread *> &threads = m_controller->config()->threads();
|
||||||
|
Value list(kArrayType);
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (const xmrig::IThread *thread : threads) {
|
||||||
|
Value value = thread->toAPI(doc);
|
||||||
|
|
||||||
|
Value hashrate(kArrayType);
|
||||||
|
hashrate.PushBack(normalize(hr->calc(i, Hashrate::ShortInterval)), allocator);
|
||||||
|
hashrate.PushBack(normalize(hr->calc(i, Hashrate::MediumInterval)), allocator);
|
||||||
|
hashrate.PushBack(normalize(hr->calc(i, Hashrate::LargeInterval)), allocator);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
value.AddMember("hashrate", hashrate, allocator);
|
||||||
|
list.PushBack(value, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.AddMember("threads", list, allocator);
|
||||||
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "net/NetworkState.h"
|
#include "net/NetworkState.h"
|
||||||
#include "base/kernel/interfaces/IControllerListener.h"
|
#include "api/interfaces/IApiListener.h"
|
||||||
#include "rapidjson/fwd.h"
|
#include "rapidjson/fwd.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,37 +35,30 @@ class Hashrate;
|
||||||
|
|
||||||
|
|
||||||
namespace xmrig {
|
namespace xmrig {
|
||||||
class Controller;
|
|
||||||
class HttpReply;
|
|
||||||
class HttpRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ApiRouter : public xmrig::IControllerListener
|
class Controller;
|
||||||
|
|
||||||
|
|
||||||
|
class ApiRouter : public xmrig::IApiListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ApiRouter(xmrig::Controller *controller);
|
ApiRouter(xmrig::Controller *controller);
|
||||||
~ApiRouter() override;
|
~ApiRouter() override;
|
||||||
|
|
||||||
void get(const xmrig::HttpRequest &req, xmrig::HttpReply &reply) const;
|
|
||||||
void exec(const xmrig::HttpRequest &req, xmrig::HttpReply &reply);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onConfigChanged(xmrig::Config *config, xmrig::Config *previousConfig) override;
|
void onRequest(IApiRequest &request) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void finalize(xmrig::HttpReply &reply, rapidjson::Document &doc) const;
|
void getHashrate(rapidjson::Value &reply, rapidjson::Document &doc) const;
|
||||||
void genId(const char *id);
|
void getMiner(rapidjson::Value &reply, rapidjson::Document &doc) const;
|
||||||
void getHashrate(rapidjson::Document &doc) const;
|
void getThreads(rapidjson::Value &reply, rapidjson::Document &doc) const;
|
||||||
void getIdentify(rapidjson::Document &doc) const;
|
|
||||||
void getMiner(rapidjson::Document &doc) const;
|
|
||||||
void getThreads(rapidjson::Document &doc) const;
|
|
||||||
void setWorkerId(const char *id);
|
|
||||||
void updateWorkerId(const char *id, const char *previousId);
|
|
||||||
|
|
||||||
char m_id[32];
|
Controller *m_controller;
|
||||||
char m_workerId[128];
|
|
||||||
xmrig::Controller *m_controller;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace xmrig
|
||||||
|
|
||||||
|
|
||||||
#endif /* XMRIG_APIROUTER_H */
|
#endif /* XMRIG_APIROUTER_H */
|
|
@ -343,21 +343,21 @@ bool xmrig::CommonConfig::parseUint64(int key, uint64_t arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::CommonConfig::parseJSON(const rapidjson::Document &doc)
|
void xmrig::CommonConfig::parseJSON(const rapidjson::Value &json)
|
||||||
{
|
{
|
||||||
const rapidjson::Value &pools = doc["pools"];
|
const rapidjson::Value &pools = json["pools"];
|
||||||
if (pools.IsArray()) {
|
if (pools.IsArray()) {
|
||||||
m_pools.load(pools);
|
m_pools.load(pools);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef XMRIG_DEPRECATED
|
# ifdef XMRIG_DEPRECATED
|
||||||
const rapidjson::Value &api = doc["api"];
|
const rapidjson::Value &api = json["api"];
|
||||||
if (api.IsObject() && api.HasMember("port")) {
|
if (api.IsObject() && api.HasMember("port")) {
|
||||||
m_upgrade = true;
|
m_upgrade = true;
|
||||||
m_http.load(api);
|
m_http.load(api);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_http.load(doc["http"]);
|
m_http.load(json["http"]);
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
m_http.load(doc["http"]);
|
m_http.load(doc["http"]);
|
||||||
|
|
|
@ -71,7 +71,7 @@ protected:
|
||||||
bool parseBoolean(int key, bool enable) override;
|
bool parseBoolean(int key, bool enable) override;
|
||||||
bool parseString(int key, const char *arg) override;
|
bool parseString(int key, const char *arg) override;
|
||||||
bool parseUint64(int key, uint64_t arg) override;
|
bool parseUint64(int key, uint64_t arg) override;
|
||||||
void parseJSON(const rapidjson::Document &doc) override;
|
void parseJSON(const rapidjson::Value &json) override;
|
||||||
void setFileName(const char *fileName) override;
|
void setFileName(const char *fileName) override;
|
||||||
|
|
||||||
Algorithm m_algorithm;
|
Algorithm m_algorithm;
|
||||||
|
|
|
@ -48,8 +48,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
xmrig::ConfigWatcher *xmrig::ConfigLoader::m_watcher = nullptr;
|
namespace xmrig {
|
||||||
xmrig::IConfigListener *xmrig::ConfigLoader::m_listener = nullptr;
|
|
||||||
|
ConfigWatcher *ConfigLoader::m_watcher = nullptr;
|
||||||
|
IConfigListener *ConfigLoader::m_listener = nullptr;
|
||||||
|
|
||||||
|
} // namespace xmrig
|
||||||
|
|
||||||
|
|
||||||
#ifndef ARRAY_SIZE
|
#ifndef ARRAY_SIZE
|
||||||
|
@ -84,26 +88,26 @@ bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const char *json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const rapidjson::Document &doc)
|
bool xmrig::ConfigLoader::loadFromJSON(xmrig::IConfig *config, const rapidjson::Value &json)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(config_options); i++) {
|
||||||
parseJSON(config, &config_options[i], doc);
|
parseJSON(config, &config_options[i], json);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rapidjson::Value &api = doc["api"];
|
const rapidjson::Value &api = json["api"];
|
||||||
if (api.IsObject()) {
|
if (api.IsObject()) {
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(api_options); i++) {
|
||||||
parseJSON(config, &api_options[i], api);
|
parseJSON(config, &api_options[i], api);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config->parseJSON(doc);
|
config->parseJSON(json);
|
||||||
|
|
||||||
return config->finalize();
|
return config->finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool xmrig::ConfigLoader::reload(xmrig::IConfig *oldConfig, const char *json)
|
bool xmrig::ConfigLoader::reload(xmrig::IConfig *oldConfig, const rapidjson::Value &json)
|
||||||
{
|
{
|
||||||
IConfig *config = Config::create();
|
IConfig *config = Config::create();
|
||||||
if (!loadFromJSON(config, json)) {
|
if (!loadFromJSON(config, json)) {
|
||||||
|
@ -134,7 +138,7 @@ bool xmrig::ConfigLoader::watch(IConfig *config)
|
||||||
|
|
||||||
assert(m_watcher == nullptr);
|
assert(m_watcher == nullptr);
|
||||||
|
|
||||||
m_watcher = new xmrig::ConfigWatcher(config->fileName(), m_listener);
|
m_watcher = new ConfigWatcher(config->fileName(), m_listener);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +229,7 @@ bool xmrig::ConfigLoader::getJSON(const char *fileName, rapidjson::Document &doc
|
||||||
|
|
||||||
bool xmrig::ConfigLoader::parseArg(xmrig::IConfig *config, int key, const char *arg)
|
bool xmrig::ConfigLoader::parseArg(xmrig::IConfig *config, int key, const char *arg)
|
||||||
{
|
{
|
||||||
if (key == xmrig::IConfig::ConfigKey) {
|
if (key == IConfig::ConfigKey) {
|
||||||
return loadFromFile(config, arg);
|
return loadFromFile(config, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ class ConfigLoader
|
||||||
public:
|
public:
|
||||||
static bool loadFromFile(IConfig *config, const char *fileName);
|
static bool loadFromFile(IConfig *config, const char *fileName);
|
||||||
static bool loadFromJSON(IConfig *config, const char *json);
|
static bool loadFromJSON(IConfig *config, const char *json);
|
||||||
static bool loadFromJSON(IConfig *config, const rapidjson::Document &doc);
|
static bool loadFromJSON(IConfig *config, const rapidjson::Value &json);
|
||||||
static bool reload(IConfig *oldConfig, const char *json);
|
static bool reload(IConfig *oldConfig, const rapidjson::Value &json);
|
||||||
static bool watch(IConfig *config);
|
static bool watch(IConfig *config);
|
||||||
static IConfig *load(Process *process, IConfigListener *listener);
|
static IConfig *load(Process *process, IConfigListener *listener);
|
||||||
static void release();
|
static void release();
|
||||||
|
@ -67,4 +67,5 @@ private:
|
||||||
|
|
||||||
} /* namespace xmrig */
|
} /* namespace xmrig */
|
||||||
|
|
||||||
|
|
||||||
#endif /* XMRIG_CONFIGLOADER_H */
|
#endif /* XMRIG_CONFIGLOADER_H */
|
||||||
|
|
|
@ -150,7 +150,7 @@ public:
|
||||||
virtual const Algorithm &algorithm() const = 0;
|
virtual const Algorithm &algorithm() const = 0;
|
||||||
virtual const String &fileName() const = 0;
|
virtual const String &fileName() const = 0;
|
||||||
virtual void getJSON(rapidjson::Document &doc) const = 0;
|
virtual void getJSON(rapidjson::Document &doc) const = 0;
|
||||||
virtual void parseJSON(const rapidjson::Document &doc) = 0;
|
virtual void parseJSON(const rapidjson::Value &json) = 0;
|
||||||
virtual void setFileName(const char *fileName) = 0;
|
virtual void setFileName(const char *fileName) = 0;
|
||||||
|
|
||||||
static IConfig *create();
|
static IConfig *create();
|
||||||
|
|
|
@ -55,7 +55,7 @@ xmrig::Config::Config() : xmrig::CommonConfig(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool xmrig::Config::reload(const char *json)
|
bool xmrig::Config::reload(const rapidjson::Value &json)
|
||||||
{
|
{
|
||||||
return xmrig::ConfigLoader::reload(this, json);
|
return xmrig::ConfigLoader::reload(this, json);
|
||||||
}
|
}
|
||||||
|
@ -277,11 +277,11 @@ bool xmrig::Config::parseUint64(int key, uint64_t arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::Config::parseJSON(const rapidjson::Document &doc)
|
void xmrig::Config::parseJSON(const rapidjson::Value &json)
|
||||||
{
|
{
|
||||||
CommonConfig::parseJSON(doc);
|
CommonConfig::parseJSON(json);
|
||||||
|
|
||||||
const rapidjson::Value &threads = doc["threads"];
|
const rapidjson::Value &threads = json["threads"];
|
||||||
|
|
||||||
if (threads.IsArray()) {
|
if (threads.IsArray()) {
|
||||||
for (const rapidjson::Value &value : threads.GetArray()) {
|
for (const rapidjson::Value &value : threads.GetArray()) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ public:
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
|
|
||||||
bool reload(const char *json);
|
bool reload(const rapidjson::Value &json);
|
||||||
|
|
||||||
void getJSON(rapidjson::Document &doc) const override;
|
void getJSON(rapidjson::Document &doc) const override;
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ protected:
|
||||||
bool parseBoolean(int key, bool enable) override;
|
bool parseBoolean(int key, bool enable) override;
|
||||||
bool parseString(int key, const char *arg) override;
|
bool parseString(int key, const char *arg) override;
|
||||||
bool parseUint64(int key, uint64_t arg) override;
|
bool parseUint64(int key, uint64_t arg) override;
|
||||||
void parseJSON(const rapidjson::Document &doc) override;
|
void parseJSON(const rapidjson::Value &json) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parseInt(int key, int arg);
|
bool parseInt(int key, int arg);
|
||||||
|
|
|
@ -166,7 +166,7 @@ void xmrig::Network::onPause(IStrategy *strategy)
|
||||||
void xmrig::Network::onRequest(IApiRequest &request)
|
void xmrig::Network::onRequest(IApiRequest &request)
|
||||||
{
|
{
|
||||||
# ifdef XMRIG_FEATURE_API
|
# ifdef XMRIG_FEATURE_API
|
||||||
if (request.method() == IApiRequest::METHOD_GET && request.url() == "/1/summary") {
|
if (request.method() == IApiRequest::METHOD_GET && (request.url() == "/1/summary" || request.url() == "/api.json")) {
|
||||||
request.accept();
|
request.accept();
|
||||||
|
|
||||||
getResults(request.reply(), request.doc());
|
getResults(request.reply(), request.doc());
|
||||||
|
|
Loading…
Reference in a new issue