diff --git a/src/backend.cpp b/src/backend.cpp index 7c8e8e3..f7bcc42 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -925,7 +925,7 @@ namespace lwsf { namespace internal { namespace backend }; lock.unlock(); - const auto response = rpc::invoke(client, login); + const auto response = rpc::invoke(client, client_prefix, login); if (!response) { if (response == rpc_unapproved) @@ -956,7 +956,7 @@ namespace lwsf { namespace internal { namespace backend rpc::login login{primary.address, primary.view.sec}; { lock.unlock(); - const auto response = rpc::invoke(client, login).value(); + const auto response = rpc::invoke(client, client_prefix, login).value(); lock.lock(); if (update_lookaheads(*this, response.all_subaddrs)) return new_account; @@ -967,7 +967,7 @@ namespace lwsf { namespace internal { namespace backend fill_upsert(*this, request.subaddrs_); lock.unlock(); - const auto response = rpc::invoke(client, request).value(); + const auto response = rpc::invoke(client, client_prefix, request).value(); lock.lock(); update_lookaheads(*this, response.all_subaddrs); } @@ -1025,11 +1025,11 @@ namespace lwsf { namespace internal { namespace backend } expect outs_response{common_error::kInvalidArgument}; - const auto txs_response = rpc::invoke(client, login); + const auto txs_response = rpc::invoke(client, client_prefix, login); if (txs_response) { const rpc::get_unspent_outs_request request{login, rpc::uint64_string(0), 0, true}; - outs_response = rpc::invoke(client, request); + outs_response = rpc::invoke(client, client_prefix, request); } lock.lock(); @@ -1061,7 +1061,7 @@ namespace lwsf { namespace internal { namespace backend fill_upsert(*this, request.subaddrs_); lock.unlock(); - const auto response = rpc::invoke(client, request); + const auto response = rpc::invoke(client, client_prefix, request); lock.lock(); if (response && update_lookaheads(*this, response->all_subaddrs)) lookahead_error = {}; @@ -1083,7 +1083,7 @@ namespace lwsf { namespace internal { namespace backend }; lock.unlock(); - const auto upsert_response = rpc::invoke(client, upsert_request); + const auto upsert_response = rpc::invoke(client, client_prefix, upsert_request); lock.lock(); if (upsert_response) @@ -1105,7 +1105,7 @@ namespace lwsf { namespace internal { namespace backend }; lock.unlock(); - const auto provision_response = rpc::invoke(client, provision_request); + const auto provision_response = rpc::invoke(client, client_prefix, provision_request); lock.lock(); if (provision_response) @@ -1184,7 +1184,7 @@ namespace lwsf { namespace internal { namespace backend }; lock.unlock(); - const auto response = rpc::invoke(client, request); + const auto response = rpc::invoke(client, client_prefix, request); lock.lock(); if (response) server_lookahead = std::max(server_lookahead, needed_maj_i); @@ -1224,7 +1224,7 @@ namespace lwsf { namespace internal { namespace backend }; lock.unlock(); - const auto response = rpc::invoke(client, request); + const auto response = rpc::invoke(client, client_prefix, request); lock.lock(); if (response) @@ -1266,7 +1266,7 @@ namespace lwsf { namespace internal { namespace backend fill_upsert(*this, request.subaddrs_); lock.unlock(); - const auto response = rpc::invoke(client, request); + const auto response = rpc::invoke(client, client_prefix, request); lock.lock(); if (!response) return (lookahead_error = handle_lookahead_error(response.error())); @@ -1306,7 +1306,7 @@ namespace lwsf { namespace internal { namespace backend rpc::import_request login{{primary.address, primary.view.sec}, height}; lock.unlock(); - auto import = rpc::invoke(client, login); + auto import = rpc::invoke(client, client_prefix, login); lock.lock(); if (!import) @@ -1364,7 +1364,7 @@ namespace lwsf { namespace internal { namespace backend expect> wallet::get_decoys(const rpc::get_random_outs_request& req) { - auto resp = rpc::invoke(client, req); + auto resp = rpc::invoke(client, client_prefix, req); if (!resp) return resp.error(); return {std::move(resp->amount_outs)}; @@ -1373,6 +1373,6 @@ namespace lwsf { namespace internal { namespace backend std::error_code wallet::send_tx(epee::byte_slice tx_bytes) { const rpc::submit_raw_tx_request request{std::move(tx_bytes)}; - return rpc::invoke(client, request).error(); + return rpc::invoke(client, client_prefix, request).error(); } }}} // lwsf // internal // backend diff --git a/src/backend.h b/src/backend.h index 7965cce..8d94c3c 100644 --- a/src/backend.h +++ b/src/backend.h @@ -235,6 +235,7 @@ namespace lwsf { namespace internal { namespace backend Monero::WalletListener* listener; rpc::http_client client; account primary; + std::string client_prefix; std::vector per_byte_fee; //!< by priority level std::error_code refresh_error; //!< Cached because `refresh(...)` is rate limited std::error_code lookahead_error; //!< warnings/errors of `server_lookahead` value diff --git a/src/rpc.cpp b/src/rpc.cpp index 2a50634..ac4cbb0 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -92,7 +92,7 @@ namespace lwsf { namespace internal { namespace rpc return instance; } - expect invoke_payload(http_client& client, const boost::string_ref endpoint, const epee::byte_slice payload) + expect invoke_payload(http_client& client, const boost::string_ref prefix, boost::string_ref endpoint, const epee::byte_slice payload) { static const epee::net_utils::http::fields_list headers{ {"Content-Type", "application/json; charset=utf-8"} @@ -104,6 +104,13 @@ namespace lwsf { namespace internal { namespace rpc return {error::no_response}; } + std::string real; + if (!prefix.empty()) + { + real = std::string{prefix} + std::string{endpoint}; + endpoint = real; + } + const epee::net_utils::http::http_response_info* response = nullptr; if (!client.invoke(endpoint, "POST", {reinterpret_cast(payload.data()), payload.size()}, config::rpc_timeout, std::addressof(response), headers)) return {error::no_response}; diff --git a/src/rpc.h b/src/rpc.h index 8ab3373..d7ad750 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -70,17 +70,17 @@ namespace lwsf { namespace internal { namespace rpc } //! Send `payload` to `client` at uri `endpoint`, and \return payload response - expect invoke_payload(http_client& client, boost::string_ref endpoint, epee::byte_slice payload); + expect invoke_payload(http_client& client, boost::string_ref prefix, boost::string_ref endpoint, epee::byte_slice payload); template - expect invoke(http_client& client, const G& in) + expect invoke(http_client& client, boost::string_ref prefix, const G& in) { epee::byte_stream sink{}; std::error_code error = wire::json::to_bytes(sink, in); if (error) return error; - expect result = invoke_payload(client, F::endpoint(), epee::byte_slice{std::move(sink)}); + expect result = invoke_payload(client, prefix, F::endpoint(), epee::byte_slice{std::move(sink)}); if (!result) return result.error(); diff --git a/src/wallet.cpp b/src/wallet.cpp index 1d511fe..7e63638 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -788,8 +788,6 @@ namespace lwsf { namespace internal epee::net_utils::http::url_content url{}; if (!epee::net_utils::parse_url(daemon_address, url)) throw std::runtime_error{"Invalid LWS URL: " + daemon_address}; - if (!url.m_uri_content.m_path.empty()) - throw std::runtime_error{"LWS URL contains path (unsupported)"}; if (!proxy_address.empty() && !setProxy(proxy_address)) return false; @@ -835,7 +833,10 @@ namespace lwsf { namespace internal } } + const boost::unique_lock lock{data_->sync}; data_->client.set_server(std::move(url.host), std::to_string(url.port), std::move(login), std::move(options)); + data_->passed_login = false; + data_->client_prefix = std::move(url.uri); } catch (const std::exception& e) { diff --git a/src/wallet_manager.cpp b/src/wallet_manager.cpp index b5c40aa..624e15e 100644 --- a/src/wallet_manager.cpp +++ b/src/wallet_manager.cpp @@ -58,6 +58,7 @@ namespace lwsf class wallet_manager : public Monero::WalletManager { rpc::http_client client_; + std::string client_prefix_; std::string error_; rpc::daemon_status cached_; std::chrono::steady_clock::time_point cached_last_; @@ -66,7 +67,7 @@ namespace lwsf { if (std::chrono::steady_clock::now() - cached_last_ > config::daemon_status_cache) { - const auto resp = rpc::invoke(client_, rpc::empty{}); + const auto resp = rpc::invoke(client_, client_prefix_, rpc::empty{}); if (!resp) { error_ = resp.error().message(); @@ -395,8 +396,6 @@ namespace lwsf epee::net_utils::http::url_content url{}; if (!epee::net_utils::parse_url(address, url)) throw std::runtime_error{"Invalid LWS URL: " + address}; - if (!url.m_uri_content.m_path.empty()) - throw std::runtime_error{"LWS URL contains path (unsupported)"}; const bool use_ssl = (url.schema == "https"); epee::net_utils::ssl_options_t options{ @@ -411,6 +410,7 @@ namespace lwsf url.port = 80; } + client_prefix_ = std::move(url.uri); client_.set_server(std::move(url.host), std::to_string(url.port), boost::none, std::move(options)); }