Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 67 additions & 36 deletions src/cpp/common/py_monero_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ py::object PyGenUtils::ptree_to_pyobject(const boost::property_tree::ptree& tree
lst.append(ptree_to_pyobject(child.second));
}
return lst;
}
}
else {
py::dict d;
if (!tree.get_value<std::string>().empty()) {
Expand Down Expand Up @@ -212,6 +212,36 @@ rapidjson::Value PyMoneroJsonRequest::to_rapidjson_val(rapidjson::Document::Allo
return root;
}

PyMoneroRpcConnection::PyMoneroRpcConnection(const std::string& uri, const std::string& username, const std::string& password, const std::string& proxy_uri, const std::string& zmq_uri, int priority, uint64_t timeout) {
if (!uri.empty()) m_uri = uri;
else m_uri = boost::none;
if (!proxy_uri.empty()) m_proxy_uri = proxy_uri;
else m_proxy_uri = boost::none;
if (!zmq_uri.empty()) m_zmq_uri = zmq_uri;
else m_zmq_uri = boost::none;
m_priority = priority;
m_timeout = timeout;
set_credentials(username, password);
}

PyMoneroRpcConnection::PyMoneroRpcConnection(const monero::monero_rpc_connection& rpc) {
m_uri = rpc.m_uri;
m_proxy_uri = rpc.m_proxy_uri;
set_credentials(rpc.m_username.value_or(""), rpc.m_password.value_or(""));
}

PyMoneroRpcConnection::PyMoneroRpcConnection(const PyMoneroRpcConnection& rpc) {
m_uri = rpc.m_uri;
m_proxy_uri = rpc.m_proxy_uri;
m_zmq_uri = rpc.m_zmq_uri;
m_priority = rpc.m_priority;
m_timeout = rpc.m_timeout;
m_is_online = rpc.m_is_online;
m_is_authenticated = rpc.m_is_authenticated;
m_response_time = rpc.m_response_time;
set_credentials(rpc.m_username.value_or(""), rpc.m_password.value_or(""));
}

int PyMoneroRpcConnection::compare(std::shared_ptr<PyMoneroRpcConnection> c1, std::shared_ptr<PyMoneroRpcConnection> c2, std::shared_ptr<PyMoneroRpcConnection> current_connection) {
// current connection is first
if (c1 == current_connection) return -1;
Expand Down Expand Up @@ -255,37 +285,39 @@ void PyMoneroRpcConnection::set_credentials(const std::string& username, const s
if (m_http_client->is_connected()) {
m_http_client->disconnect();
}
}
else {
} else {
auto factory = new net::http::client_factory();
m_http_client = factory->create();
}

if (username.empty()) {
m_username = boost::none;
}

if (password.empty()) {
m_password = boost::none;
}
bool username_empty = username.empty();
bool password_empty = password.empty();

if (!password.empty() || !username.empty()) {
if (password.empty()) {
throw PyMoneroError("username cannot be empty because password is not empty");
if (!username_empty || !password_empty) {
if (password_empty) {
throw PyMoneroError("password cannot be empty because username is not empty");
}

if (username.empty()) {
throw PyMoneroError("password cannot be empty because username is not empty");
if (username_empty) {
throw PyMoneroError("username cannot be empty because password is not empty");
}
}

if (m_username != username || m_password != password) {
bool username_equals = (m_username == boost::none && username_empty) || (m_username != boost::none && *m_username == username);
bool password_equals = (m_password == boost::none && password_empty) || (m_password != boost::none && *m_password == password);

if (!username_equals || !password_equals) {
m_is_online = boost::none;
m_is_authenticated = boost::none;
}

m_username = username;
m_password = password;
if (!username_empty && !password_empty) {
m_username = username;
m_password = password;
} else {
m_username = boost::none;
m_password = boost::none;
}
}

void PyMoneroRpcConnection::set_attribute(const std::string& key, const std::string& val) {
Expand Down Expand Up @@ -319,24 +351,23 @@ bool PyMoneroRpcConnection::check_connection(int timeout_ms) {
boost::optional<bool> is_online_before = m_is_online;
boost::optional<bool> is_authenticated_before = m_is_authenticated;
boost::lock_guard<boost::recursive_mutex> lock(m_mutex);
auto start = std::chrono::high_resolution_clock::now();
try {
if (!m_http_client) throw std::runtime_error("http client not set");
if (m_http_client->is_connected()) {
m_http_client->disconnect();
}

if (m_proxy_uri != boost::none) {
if (m_proxy_uri != boost::none && !m_proxy_uri.get().empty()) {
if(!m_http_client->set_proxy(m_proxy_uri.get())) {
throw std::runtime_error("Could not set proxy");
}
}

if(m_username != boost::none && !m_username->empty() && m_password != boost::none && !m_password->empty()) {
auto credentials = std::make_shared<epee::net_utils::http::login>();

credentials->username = *m_username;
credentials->password = *m_password;

m_credentials = *credentials;
}

Expand All @@ -345,20 +376,14 @@ bool PyMoneroRpcConnection::check_connection(int timeout_ms) {
}

m_http_client->connect(std::chrono::milliseconds(timeout_ms));
auto start = std::chrono::high_resolution_clock::now();
PyMoneroJsonRequest request("get_version");
auto response = send_json_request(request);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if (response->m_result == boost::none) {
throw PyMoneroRpcError(-1, "Invalid JSON RPC response");
}

std::vector<long> heights;
heights.reserve(100);
for(long i = 0; i < 100; i++) heights.push_back(i);
py::dict params;
params["heights"] = heights;
send_binary_request("get_blocks_by_height.bin", params);
m_is_online = true;
m_is_authenticated = true;
m_response_time = duration.count();

return is_online_before != m_is_online || is_authenticated_before != m_is_authenticated;
}
catch (const PyMoneroRpcError& ex) {
m_is_online = false;
Expand All @@ -370,18 +395,24 @@ bool PyMoneroRpcConnection::check_connection(int timeout_ms) {
m_is_authenticated = false;
}
else if (ex.code == 404) {
// fallback to latency check
m_is_online = true;
m_is_authenticated = true;
}

return false;
}
catch (const std::exception& ex) {
m_is_online = false;
m_is_authenticated = boost::none;
m_response_time = boost::none;
return false;
}

if (*m_is_online) {
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
m_response_time = duration.count();
}

return is_online_before != m_is_online || is_authenticated_before != m_is_authenticated;
}

void PyMoneroConnectionManager::add_listener(const std::shared_ptr<monero_connection_manager_listener> &listener) {
Expand Down
52 changes: 11 additions & 41 deletions src/cpp/common/py_monero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class PyGenUtils {
public:
PyGenUtils() {}

static py::object convert_value(const std::string& val);
static py::object convert_value(const std::string& val);
static py::object ptree_to_pyobject(const boost::property_tree::ptree& tree);
static boost::property_tree::ptree pyobject_to_ptree(const py::object& obj);
static boost::property_tree::ptree parse_json_string(const std::string &json);
Expand Down Expand Up @@ -141,7 +141,7 @@ class PyMoneroRequestParams : public PySerializableStruct {
class PyMoneroRequestEmptyParams : public PyMoneroRequestParams {
public:
PyMoneroRequestEmptyParams() {}

rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override { rapidjson::Value root(rapidjson::kObjectType); return root; };
};

Expand All @@ -150,7 +150,7 @@ class PyMoneroPathRequest : public PyMoneroRequest {
boost::optional<std::shared_ptr<PyMoneroRequestParams>> m_params;

PyMoneroPathRequest() { }

PyMoneroPathRequest(std::string method, boost::optional<py::object> params = boost::none) {
m_method = method;
if (params != boost::none) m_params = std::make_shared<PyMoneroRequestParams>(params);
Expand Down Expand Up @@ -312,34 +312,9 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection {

static int compare(std::shared_ptr<PyMoneroRpcConnection> c1, std::shared_ptr<PyMoneroRpcConnection> c2, std::shared_ptr<PyMoneroRpcConnection> current_connection);

PyMoneroRpcConnection(const std::string& uri = "", const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", int priority = 0, uint64_t timeout = 0) {
m_uri = uri;
m_username = username;
m_password = password;
m_zmq_uri = zmq_uri;
m_priority = priority;
m_timeout = timeout;
m_proxy_uri = proxy_uri;
set_credentials(username, password);
}

PyMoneroRpcConnection(const PyMoneroRpcConnection& rpc) {
m_uri = rpc.m_uri;
m_username = rpc.m_username;
m_password = rpc.m_password;
m_zmq_uri = rpc.m_zmq_uri;
m_proxy_uri = rpc.m_proxy_uri;
m_is_authenticated = rpc.m_is_authenticated;
set_credentials(m_username.value_or(""), m_password.value_or(""));
}

PyMoneroRpcConnection(const monero::monero_rpc_connection& rpc) {
m_uri = rpc.m_uri;
m_username = rpc.m_username;
m_password = rpc.m_password;
m_proxy_uri = rpc.m_proxy_uri;
set_credentials(m_username.value_or(""), m_password.value_or(""));
}
PyMoneroRpcConnection(const std::string& uri = "", const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", int priority = 0, uint64_t timeout = 0);
PyMoneroRpcConnection(const PyMoneroRpcConnection& rpc);
PyMoneroRpcConnection(const monero::monero_rpc_connection& rpc);

bool is_onion() const;
bool is_i2p() const;
Expand Down Expand Up @@ -389,8 +364,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection {
PyMoneroJsonResponse response;

int result = invoke_post("/json_rpc", request, response, timeout);

if (result != 200) throw std::runtime_error("HTTP error: code " + std::to_string(result));
if (result != 200) throw PyMoneroRpcError(result, "HTTP error: code " + std::to_string(result));

return std::make_shared<PyMoneroJsonResponse>(response);
}
Expand All @@ -400,8 +374,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection {

if (request.m_method == boost::none || request.m_method->empty()) throw std::runtime_error("No RPC method set in path request");
int result = invoke_post(std::string("/") + request.m_method.get(), request, response, timeout);

if (result != 200) throw std::runtime_error("HTTP error: code " + std::to_string(result));
if (result != 200) throw PyMoneroRpcError(result, "HTTP error: code " + std::to_string(result));

return std::make_shared<PyMoneroPathResponse>(response);
}
Expand All @@ -415,7 +388,7 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection {

const epee::net_utils::http::http_response_info* response = invoke_post(uri, body, timeout);
int result = response->m_response_code;
if (result != 200) throw std::runtime_error("HTTP error: code " + std::to_string(result));
if (result != 200) throw PyMoneroRpcError(result, "HTTP error: code " + std::to_string(result));

auto res = std::make_shared<PyMoneroBinaryResponse>();
res->m_binary = response->m_body;
Expand All @@ -428,22 +401,19 @@ class PyMoneroRpcConnection : public monero::monero_rpc_connection {
inline boost::optional<py::object> send_json_request(const std::string method, boost::optional<py::object> parameters) {
PyMoneroJsonRequest request(method, parameters);
auto response = send_json_request(request);

return response->get_result();
}

inline boost::optional<py::object> send_path_request(const std::string method, boost::optional<py::object> parameters) {
PyMoneroPathRequest request(method, parameters);
auto response = send_path_request(request);

return response->get_response();
}

inline boost::optional<py::object> send_binary_request(const std::string method, boost::optional<py::object> parameters) {
inline boost::optional<std::string> send_binary_request(const std::string method, boost::optional<py::object> parameters) {
PyMoneroBinaryRequest request(method, parameters);
auto response = send_binary_request(request);

return response->get_response();
return response->m_binary;
}

protected:
Expand Down
45 changes: 34 additions & 11 deletions src/cpp/py_monero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PYBIND11_MODULE(monero, m) {
m.doc() = "";

auto py_serializable_struct = py::class_<monero::serializable_struct, PySerializableStruct, std::shared_ptr<monero::serializable_struct>>(m, "SerializableStruct");
auto py_monero_rpc_connection = py::class_<monero::monero_rpc_connection, PyMoneroRpcConnection, std::shared_ptr<monero_rpc_connection>>(m, "MoneroRpcConnection");
auto py_monero_rpc_connection = py::class_<monero::monero_rpc_connection, monero::serializable_struct, PyMoneroRpcConnection, std::shared_ptr<monero_rpc_connection>>(m, "MoneroRpcConnection");
auto py_monero_connection_manager_listener = py::class_<monero_connection_manager_listener, PyMoneroConnectionManagerListener, std::shared_ptr<monero_connection_manager_listener>>(m, "MoneroConnectionManagerListener");
auto py_monero_connection_manager = py::class_<PyMoneroConnectionManager, std::shared_ptr<PyMoneroConnectionManager>>(m, "MoneroConnectionManager");

Expand Down Expand Up @@ -301,26 +301,44 @@ PYBIND11_MODULE(monero, m) {
// monero_rpc_connection
py_monero_rpc_connection
.def(py::init<const std::string&, const std::string&, const::std::string&, const std::string&, const std::string&, int, uint64_t>(), py::arg("uri") = "", py::arg("username") = "", py::arg("password") = "", py::arg("proxy_uri") = "", py::arg("zmq_uri") = "", py::arg("priority") = 0, py::arg("timeout") = 0)
.def(py::init<PyMoneroRpcConnection&>(), py::arg("rpc"))
.def(py::init<const PyMoneroRpcConnection&>(), py::arg("rpc"))
.def_static("compare", [](const std::shared_ptr<PyMoneroRpcConnection> c1, const std::shared_ptr<PyMoneroRpcConnection> c2, std::shared_ptr<PyMoneroRpcConnection> current_connection) {
MONERO_CATCH_AND_RETHROW(PyMoneroRpcConnection::compare(c1, c2, current_connection));
}, py::arg("c1"), py::arg("c2"), py::arg("current_connection"))
.def_readwrite("uri", &PyMoneroRpcConnection::m_uri)
.def_readwrite("username", &PyMoneroRpcConnection::m_username)
.def_readwrite("password", &PyMoneroRpcConnection::m_password)
.def_readwrite("proxy_uri", &PyMoneroRpcConnection::m_proxy_uri)
.def_property("uri",
[](const PyMoneroRpcConnection& self) { return self.m_uri; },
[](PyMoneroRpcConnection& self, const boost::optional<std::string>& val) {
// normalize uri
if (val != boost::none && !val->empty()) {
self.m_uri = val;
} else self.m_uri = boost::none;
})
.def_readonly("username", &PyMoneroRpcConnection::m_username)
.def_readonly("password", &PyMoneroRpcConnection::m_password)
.def_property_readonly("response_time",
[](const PyMoneroRpcConnection& self) { return self.m_response_time; })
.def_property("proxy_uri",
[](const PyMoneroRpcConnection& self) { return self.m_proxy_uri; },
[](PyMoneroRpcConnection& self, const boost::optional<std::string>& val) {
// normalize proxy uri
if (val != boost::none && !val->empty()) {
self.m_proxy_uri = val;
} else self.m_proxy_uri = boost::none;
})
.def_property("zmq_uri",
[](const PyMoneroRpcConnection& self) { return self.m_zmq_uri; },
[](PyMoneroRpcConnection& self, boost::optional<std::string> val) { self.m_zmq_uri = val; })
[](PyMoneroRpcConnection& self, const boost::optional<std::string>& val) {
// normalize zmq uri
if (val != boost::none && !val->empty()) {
self.m_zmq_uri = val;
} else self.m_zmq_uri = boost::none;
})
.def_property("priority",
[](const PyMoneroRpcConnection& self) { return self.m_priority; },
[](PyMoneroRpcConnection& self, int val) { self.m_priority = val; })
.def_property("timeout",
[](const PyMoneroRpcConnection& self) { return self.m_timeout; },
[](PyMoneroRpcConnection& self, uint64_t val) { self.m_timeout = val; })
.def_property("response_time",
[](const PyMoneroRpcConnection& self) { return self.m_response_time; },
[](PyMoneroRpcConnection& self, boost::optional<long> val) { self.m_response_time = val; })
.def("set_attribute", [](PyMoneroRpcConnection& self, const std::string& key, const std::string& value) {
MONERO_CATCH_AND_RETHROW(self.set_attribute(key, value));
}, py::arg("key"), py::arg("value"))
Expand Down Expand Up @@ -1960,7 +1978,6 @@ PYBIND11_MODULE(monero, m) {
MONERO_CATCH_AND_RETHROW(self.delete_address_book_entry(index));
}, py::arg("index"))
.def("tag_accounts", [](PyMoneroWallet& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
std::cout << "Indirizzo dell'oggetto A: " << &self << std::endl;
MONERO_CATCH_AND_RETHROW(self.tag_accounts(tag, account_indices));
}, py::arg("tag"), py::arg("account_indices"))
.def("untag_accounts", [](PyMoneroWallet& self, const std::vector<uint32_t>& account_indices) {
Expand Down Expand Up @@ -2243,9 +2260,15 @@ PYBIND11_MODULE(monero, m) {
std::string b{bin};
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_json(b));
}, py::arg("bin"))
.def_static("binary_to_json", [](const std::string &bin) {
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_json(bin));
}, py::arg("bin"))
.def_static("dict_to_binary", [](const py::dict &dictionary) {
MONERO_CATCH_AND_RETHROW(py::bytes(PyMoneroUtils::dict_to_binary(dictionary)));
}, py::arg("dictionary"))
.def_static("binary_to_dict", [](const std::string &bin) {
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_dict(bin));
}, py::arg("bin"))
.def_static("binary_to_dict", [](const py::bytes &bin) {
std::string b{bin};
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_dict(b));
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/wallet/py_monero_wallet_rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ void PyMoneroWalletRpc::set_daemon_connection(const std::string& uri, const std:
set_daemon_connection(boost::none);
return;
}
boost::optional<monero_rpc_connection> rpc = monero_rpc_connection(uri, username, password, proxy_uri);
boost::optional<monero_rpc_connection> rpc = PyMoneroRpcConnection(uri, username, password, proxy_uri);
set_daemon_connection(rpc);
}

Expand Down
Loading
Loading