http: client, wallet to node communication with proxy

This commit is contained in:
ardocrat
2025-05-31 23:34:51 +03:00
parent 1ef62a806b
commit 92f8386264
7 changed files with 337 additions and 60 deletions
+64
View File
@@ -0,0 +1,64 @@
// Copyright 2025 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use bytes::Bytes;
use http_body_util::Full;
use hyper::body::Incoming;
use hyper::{Request, Response};
use hyper_proxy2::{Intercept, Proxy, ProxyConnector};
use hyper_tls::HttpsConnector;
use hyper_util::client::legacy::{Client, Error};
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::rt::TokioExecutor;
use crate::AppConfig;
/// Handles http requests.
pub struct HttpClient {
}
impl HttpClient {
/// Send request.
pub async fn send(req: Request<Full<Bytes>>) -> Result<Response<Incoming>, Error> {
let res = if AppConfig::use_proxy() {
if let Some(url) = AppConfig::socks_proxy_url() {
let mut connector = HttpConnector::new();
connector.enforce_http(false);
let uri = url.parse().unwrap();
let proxy = hyper_socks2::SocksConnector {
proxy_addr: uri,
auth: None,
connector,
};
let client = Client::builder(TokioExecutor::new())
.build::<_, Full<Bytes>>(proxy);
client.request(req).await
} else {
let url = AppConfig::http_proxy_url().unwrap();
let uri = url.parse().unwrap();
let proxy = Proxy::new(Intercept::All, uri);
let connector = HttpConnector::new();
let proxy_connector = ProxyConnector::from_proxy(connector, proxy).unwrap();
let client = Client::builder(TokioExecutor::new())
.build::<_, Full<Bytes>>(proxy_connector);
client.request(req).await
}
} else {
let client = Client::builder(TokioExecutor::new())
.build::<_, Full<Bytes>>(HttpsConnector::new());
client.request(req).await
};
res
}
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2025 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod client;
pub use client::*;
+1
View File
@@ -38,6 +38,7 @@ mod node;
mod wallet;
mod tor;
mod settings;
mod http;
pub mod gui;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
+10 -10
View File
@@ -16,6 +16,7 @@ use grin_core::global::ChainTypes;
use grin_util::to_base64;
use serde_derive::{Deserialize, Serialize};
use crate::http::HttpClient;
use crate::wallet::ConnectionsConfig;
/// External connection for the wallet.
@@ -34,13 +35,15 @@ pub struct ExternalConnection {
}
/// Default external node URL for main network.
const DEFAULT_MAIN_URLS: [&'static str; 2] = [
const DEFAULT_MAIN_URLS: [&'static str; 3] = [
"https://main.gri.mw",
"https://grincoin.org",
"https://grinnode.live:3413"
];
/// Default external node URL for main network.
const DEFAULT_TEST_URLS: [&'static str; 1] = [
const DEFAULT_TEST_URLS: [&'static str; 2] = [
"https://test.gri.mw",
"https://testnet.grincoin.org"
];
@@ -101,11 +104,8 @@ fn check_ext_conn(conn: &ExternalConnection, ui_ctx: &egui::Context) {
let url = url::Url::parse(conn.url.as_str()).unwrap();
if let Ok(_) = url.socket_addrs(|| None) {
let addr = format!("{}v2/foreign", url.to_string());
// Setup http client.
let client = hyper_tor::Client::builder()
.build::<_, hyper_tor::Body>(hyper_tls::HttpsConnector::new());
let mut req_setup = hyper_tor::Request::builder()
.method(hyper_tor::Method::POST)
let mut req_setup = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(addr.clone());
// Setup secret key auth.
if let Some(key) = conn.secret {
@@ -114,13 +114,13 @@ fn check_ext_conn(conn: &ExternalConnection, ui_ctx: &egui::Context) {
to_base64(&format!("grin:{}", key))
);
req_setup = req_setup
.header(hyper_tor::header::AUTHORIZATION, basic_auth.clone());
.header(hyper::header::AUTHORIZATION, basic_auth.clone());
}
let req = req_setup.body(hyper_tor::Body::from(
let req = req_setup.body(http_body_util::Full::from(
r#"{"id":1,"jsonrpc":"2.0","method":"get_version","params":{} }"#)
).unwrap();
// Send request.
match client.request(req).await {
match HttpClient::send(req).await {
Ok(res) => {
let status = res.status().as_u16();
// Available on 200 HTTP status code.
+22 -1
View File
@@ -187,7 +187,28 @@ impl Wallet {
} else {
integrated()
};
Ok(HTTPNodeClient::new(&node_api_url, node_secret)?)
let client = if AppConfig::use_proxy() {
let socks = AppConfig::use_socks_proxy();
let url = if socks {
AppConfig::socks_proxy_url()
} else {
AppConfig::http_proxy_url()
}.unwrap_or("".to_string());
let res = url.replace("http://", "").replace("socks5://", "").parse();
if let Ok(addr) = res {
let scheme = if socks {
"socks5://"
} else {
"http://"
};
HTTPNodeClient::new_proxy(&node_api_url, node_secret, Some((addr, scheme)))?
} else {
HTTPNodeClient::new_proxy(&node_api_url, node_secret, None)?
}
} else {
HTTPNodeClient::new_proxy(&node_api_url, node_secret, None)?
};
Ok(client)
}
/// Create [`WalletInstance`] from provided [`WalletConfig`].