mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-21 09:08:32 +02:00
Global config instance (#769)
* config: global instance * fix: cli tests * fix: owner api tests * config: save tor config * fix: owner rpc tests * fix: set config file path on init and owner api call * tor: store launched services, get global config at command loop, remove unused listen args, check for empty global config to set default, do not save empty tor config at owner * api: update config in memory after successful file write * arti: restart proxy in loop * fix: comment for tor config save * config: set or init, update without error * config: scoped tor config * build: update lock file * config: ability to store multiple configurations at memory from config path * tor: restart service on config change * fix: owner api test * foreign: pass tor config from args, stop service, error handling * arti: move runtime wrapper to single file * config: read existing config from file at create_config * config: handle error on read * arti: single dir for cache * foreign: register config listener before launch * config: save temp * config: remove unused error type * config: make path and members not optional, return an error on config creation if it exists, pass default tor config to send if not set * arti: non public runtime wrapper * config: migrate comments * fix: rpc tests * config: return from cache if exists * config: save disabled tor config when null provided at owner and tor section was not set * config: update tor with args at listener * config: pass pathbuf directly on creation * config: unique tmp file name, setting permissions and providing config version * fix global config handling * fix config persistence * fix tor service restart * fix config synchronization * require wallet close before changing data directory * unify global config updates --------- Co-authored-by: wiesche <wiesche89@googlemail.com>
This commit is contained in:
+457
-563
File diff suppressed because it is too large
Load Diff
+227
-132
@@ -12,10 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Controller for wallet.. instantiates and handles listeners (or single-run
|
||||
//! Controller for wallet, instantiates and handles listeners (or single-run
|
||||
//! invocations) as needed.
|
||||
use crate::api::{self, ApiServer, BasicAuthMiddleware, ResponseFuture, Router, TLSConfig};
|
||||
use crate::config::TorConfig;
|
||||
use crate::impls::tor::config as tor_config;
|
||||
use crate::impls::tor::process as tor_process;
|
||||
use crate::impls::tor::{bridge as tor_bridge, proxy as tor_proxy};
|
||||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::{
|
||||
address, Error, NodeClient, NodeVersionInfo, Slate, SlatepackAddress, WalletInst,
|
||||
@@ -25,6 +28,7 @@ use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{from_hex, static_secp_instance, to_base64, Mutex};
|
||||
use grin_wallet_api::JsonId;
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
|
||||
use hyper::header::HeaderValue;
|
||||
use hyper::{Request, Response, StatusCode};
|
||||
use qr_code::QrCode;
|
||||
@@ -34,21 +38,23 @@ use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Cursor;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::impls::tor::config as tor_config;
|
||||
use crate::impls::tor::process as tor_process;
|
||||
use crate::impls::tor::{bridge as tor_bridge, proxy as tor_proxy};
|
||||
use std::thread;
|
||||
|
||||
use crate::apiwallet::{
|
||||
EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, Foreign,
|
||||
ConfigPath, EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, Foreign,
|
||||
ForeignCheckMiddlewareFn, ForeignRpc, Owner, OwnerRpc,
|
||||
};
|
||||
use easy_jsonrpc_mw;
|
||||
use easy_jsonrpc_mw::{Handler, MaybeReply};
|
||||
use grin_api::ApiBody;
|
||||
use grin_wallet_impls::tor::arti::start_tor_service;
|
||||
use grin_wallet_impls::tor::Tor;
|
||||
use grin_wallet_config::config::{
|
||||
add_global_config_listener, get_global_config, remove_global_config_listener,
|
||||
};
|
||||
use grin_wallet_impls::tor::arti::{start_tor_service, stop_tor_service};
|
||||
use grin_wallet_impls::tor::process::TorProcess;
|
||||
use http_body_util::{BodyExt, Full};
|
||||
use hyper::body::Incoming;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -91,7 +97,7 @@ fn init_tor_listener(
|
||||
tor_dir: String,
|
||||
addr: &str,
|
||||
tor_config: TorConfig,
|
||||
) -> Result<Tor, Error> {
|
||||
) -> Result<tor_process::TorProcess, Error> {
|
||||
info!("Starting external Tor Process listener.");
|
||||
|
||||
let mut process = tor_process::TorProcess::new();
|
||||
@@ -131,19 +137,15 @@ fn init_tor_listener(
|
||||
.completion_percent(100)
|
||||
.launch()
|
||||
.map_err(|e| Error::TorProcess(format!("{:?}", e)))?;
|
||||
Ok(Tor {
|
||||
process: Some(process),
|
||||
service: None,
|
||||
client: None,
|
||||
})
|
||||
Ok(process)
|
||||
}
|
||||
|
||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn owner_single_use<L, F, C, K>(
|
||||
wallet: Option<Arc<Mutex<Box<dyn WalletInst<'static, L, C, K>>>>>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
api_context: Option<&mut Owner<L, C, K>>,
|
||||
config_path: PathBuf,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
@@ -152,27 +154,14 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
match api_context {
|
||||
Some(c) => f(c, keychain_mask)?,
|
||||
None => {
|
||||
let wallet = match wallet {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
return Err(Error::GenericError(
|
||||
"Instantiated wallet or Owner API context must be provided".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
f(&mut Owner::new(wallet, None), keychain_mask)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
f(&mut Owner::new(wallet, None, config_path), keychain_mask)
|
||||
}
|
||||
|
||||
/// Instantiate wallet Foreign API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn foreign_single_use<'a, L, F, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
config_path: PathBuf,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
@@ -184,6 +173,7 @@ where
|
||||
{
|
||||
f(&mut Foreign::new(
|
||||
wallet,
|
||||
config_path,
|
||||
keychain_mask,
|
||||
Some(check_middleware),
|
||||
false,
|
||||
@@ -196,13 +186,12 @@ where
|
||||
/// Note keychain mask is only provided here in case the foreign listener is also being used
|
||||
/// in the same wallet instance
|
||||
pub fn owner_listener<L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
owner_api: &mut Owner<L, C, K>,
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
addr: &str,
|
||||
api_secret: Option<String>,
|
||||
tls_config: Option<TLSConfig>,
|
||||
owner_api_include_foreign: Option<bool>,
|
||||
tor_config: Option<TorConfig>,
|
||||
test_mode: bool,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
@@ -226,12 +215,8 @@ where
|
||||
running_foreign = true;
|
||||
}
|
||||
|
||||
let api_handler_v3 = OwnerAPIHandlerV3::new(
|
||||
wallet.clone(),
|
||||
keychain_mask.clone(),
|
||||
tor_config.clone(),
|
||||
running_foreign,
|
||||
);
|
||||
let wallet = owner_api.wallet_inst.clone();
|
||||
let api_handler_v3 = OwnerAPIHandlerV3::new(owner_api, keychain_mask.clone(), running_foreign);
|
||||
|
||||
router
|
||||
.add_route("/v3/owner", Arc::new(api_handler_v3))
|
||||
@@ -240,8 +225,12 @@ where
|
||||
// If so configured, add the foreign API to the same port
|
||||
if running_foreign {
|
||||
warn!("Starting HTTP Foreign API on Owner server at {}.", addr);
|
||||
let foreign_api_handler_v2 =
|
||||
ForeignAPIHandlerV2::new(wallet, keychain_mask, test_mode, Mutex::new(tor_config));
|
||||
let foreign_api_handler_v2 = ForeignAPIHandlerV2::new(
|
||||
wallet,
|
||||
owner_api.shared_config_path(),
|
||||
keychain_mask,
|
||||
test_mode,
|
||||
);
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(foreign_api_handler_v2))
|
||||
.map_err(|_| Error::GenericError("Router failed to add route".to_string()))?;
|
||||
@@ -265,99 +254,162 @@ where
|
||||
/// port and wrapping the calls
|
||||
pub fn foreign_listener<L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
config_path: PathBuf,
|
||||
bridge: Option<String>,
|
||||
use_tor: Option<bool>,
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
addr: &str,
|
||||
tls_config: Option<TLSConfig>,
|
||||
use_tor: bool,
|
||||
test_mode: bool,
|
||||
tor_config: TorConfig,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
// Check if wallet has been opened first
|
||||
let (sec_key, tor_dir, onion_address) = {
|
||||
let mask = keychain_mask.lock();
|
||||
let mut w_lock = wallet.lock();
|
||||
let lc = w_lock.lc_provider()?;
|
||||
let w_inst = lc.wallet_inst()?;
|
||||
let k = w_inst.keychain((&mask).as_ref())?;
|
||||
let parent_key_id = w_inst.parent_key_id();
|
||||
let sec_key = address::address_from_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let tor_dir = format!("{}/tor/listener", lc.get_top_level_directory()?);
|
||||
let onion_address = OnionV3Address::from_private(&sec_key.0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
(sec_key, tor_dir, onion_address)
|
||||
};
|
||||
loop {
|
||||
let (restart_tx, restart_rx) = std::sync::mpsc::channel::<()>();
|
||||
register_config_listener(&config_path, "foreign_listener", restart_tx)?;
|
||||
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
test_mode,
|
||||
Mutex::new(Some(tor_config.clone())),
|
||||
);
|
||||
let mut router = Router::new();
|
||||
let tor_config = listener_tor_config(&config_path, bridge.clone(), use_tor)?;
|
||||
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(api_handler_v2))
|
||||
.map_err(|_| Error::GenericError("Router failed to add route".to_string()))?;
|
||||
|
||||
let api_chan: (mpsc::Sender<()>, mpsc::Receiver<()>) = mpsc::channel::<()>(1);
|
||||
|
||||
let mut apis = ApiServer::new();
|
||||
warn!("Starting HTTP Foreign listener API server at {}.", addr);
|
||||
let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address");
|
||||
let api_thread = apis
|
||||
.start(socket_addr, router, tls_config, api_chan)
|
||||
.map_err(|_| Error::GenericError("API thread failed to start".to_string()))?;
|
||||
warn!("HTTP Foreign listener started.");
|
||||
|
||||
// Need to keep external process in scope while the listener is running.
|
||||
let tor_service = if use_tor {
|
||||
let use_integrated = tor_config.use_integrated.unwrap_or(false);
|
||||
let res = if use_integrated {
|
||||
start_tor_service(sec_key, &tor_dir, addr, tor_config.clone())
|
||||
} else {
|
||||
init_tor_listener(sec_key, tor_dir, addr, tor_config)
|
||||
// Check if wallet has been opened first
|
||||
let (sec_key, tor_dir, onion_address) = {
|
||||
let mask = keychain_mask.lock();
|
||||
let mut w_lock = wallet.lock();
|
||||
let lc = w_lock.lc_provider()?;
|
||||
let w_inst = lc.wallet_inst()?;
|
||||
let k = w_inst.keychain((&mask).as_ref())?;
|
||||
let parent_key_id = w_inst.parent_key_id();
|
||||
let sec_key = address::address_from_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let tor_dir = format!("{}/tor/listener", lc.get_top_level_directory()?);
|
||||
let onion_address = OnionV3Address::from_private(&sec_key.0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
(sec_key, tor_dir, onion_address)
|
||||
};
|
||||
match res {
|
||||
Ok(service) => {
|
||||
warn!(
|
||||
"Starting Tor Hidden Service for API listener at address {}, binding to {}",
|
||||
onion_address, addr
|
||||
);
|
||||
Ok(Some(service))
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Unable to start TOR listener");
|
||||
error!("Tor Error: {}", e);
|
||||
warn!("Listener is available on {}", addr);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
if tor_service.is_ok() {
|
||||
if let Some(_) = tor_service.as_ref().unwrap() {
|
||||
let sp_address = SlatepackAddress::try_from(onion_address.clone())?;
|
||||
let qr_string = match QrCode::new(sp_address.to_string()) {
|
||||
Ok(qr) => qr.to_string(false, 3),
|
||||
Err(_) => "Failed to generate QR code!".to_string(),
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(
|
||||
wallet.clone(),
|
||||
config_path.clone().into(),
|
||||
keychain_mask.clone(),
|
||||
test_mode,
|
||||
);
|
||||
let mut router = Router::new();
|
||||
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(api_handler_v2))
|
||||
.map_err(|_| Error::GenericError("Router failed to add route".to_string()))?;
|
||||
|
||||
let api_chan: (mpsc::Sender<()>, mpsc::Receiver<()>) = mpsc::channel::<()>(1);
|
||||
let stop_tx = api_chan.0.clone();
|
||||
|
||||
let mut apis = ApiServer::new();
|
||||
warn!("Starting HTTP Foreign listener API server at {}.", addr);
|
||||
let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address");
|
||||
let api_thread = apis
|
||||
.start(socket_addr, router, tls_config.clone(), api_chan)
|
||||
.map_err(|_| Error::GenericError("API thread failed to start".to_string()))?;
|
||||
warn!("HTTP Foreign listener started.");
|
||||
|
||||
// Need to keep external process in scope while the listener is running.
|
||||
let _tor_service = if tor_config.use_tor_listener {
|
||||
let use_integrated = tor_config.use_integrated.unwrap_or(false);
|
||||
|
||||
let res: Result<Option<TorProcess>, Error> = if use_integrated {
|
||||
match start_tor_service(sec_key, addr, &tor_config.clone()) {
|
||||
Ok(_) => Ok(None),
|
||||
Err(e) => {
|
||||
error!("Error starting integrated Tor service: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match init_tor_listener(sec_key, tor_dir, addr, tor_config.clone()) {
|
||||
Ok(p) => Ok(Some(p)),
|
||||
Err(e) => {
|
||||
error!("Error starting external Tor listener: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
};
|
||||
warn!("Slatepack Address is: {}\n{}", sp_address, qr_string);
|
||||
match res {
|
||||
Ok(service) => {
|
||||
warn!(
|
||||
"Starting Tor Hidden Service for API listener at address {}, binding to {}",
|
||||
onion_address, addr
|
||||
);
|
||||
let sp_address = SlatepackAddress::try_from(onion_address.clone())?;
|
||||
let qr_string = match QrCode::new(sp_address.to_string()) {
|
||||
Ok(qr) => qr.to_string(false, 3),
|
||||
Err(_) => "Failed to generate QR code!".to_string(),
|
||||
};
|
||||
warn!("Slatepack Address is: {}\n{}", sp_address, qr_string);
|
||||
Ok(service)
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Unable to start TOR listener");
|
||||
error!("Tor Error: {}", e);
|
||||
warn!("Listener is available on {}", addr);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("Listener is available on {}", addr);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
api_thread
|
||||
.join()
|
||||
.map_err(|e| Error::GenericError(format!("API thread panicked :{:?}", e)))
|
||||
// Start thread to check if restart is needed.
|
||||
let restart_needed = Arc::new(AtomicBool::new(false));
|
||||
let t_restart_needed = restart_needed.clone();
|
||||
thread::spawn(move || {
|
||||
if restart_rx.recv().is_ok() {
|
||||
t_restart_needed.store(true, Ordering::SeqCst);
|
||||
let _ = stop_tx.try_send(());
|
||||
}
|
||||
});
|
||||
|
||||
let res = api_thread
|
||||
.join()
|
||||
.map_err(|e| Error::GenericError(format!("API thread panicked :{:?}", e)));
|
||||
|
||||
if tor_config.use_tor_listener && tor_config.use_integrated.unwrap_or(false) {
|
||||
stop_tor_service(onion_address.to_string())?;
|
||||
}
|
||||
|
||||
if restart_needed.load(Ordering::Relaxed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
remove_global_config_listener(&config_path, "foreign_listener");
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
fn register_config_listener(
|
||||
config_path: &PathBuf,
|
||||
listener_id: &str,
|
||||
tx: std::sync::mpsc::Sender<()>,
|
||||
) -> Result<(), Error> {
|
||||
get_global_config(config_path)?;
|
||||
add_global_config_listener(config_path, listener_id, tx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn listener_tor_config(
|
||||
config_path: &Path,
|
||||
bridge: Option<String>,
|
||||
use_tor: Option<bool>,
|
||||
) -> Result<TorConfig, Error> {
|
||||
let mut tor_config = get_global_config(config_path)?.tor_config();
|
||||
if let Some(bridge) = bridge {
|
||||
tor_config.bridge.bridge_line = Some(bridge);
|
||||
}
|
||||
if let Some(use_tor) = use_tor {
|
||||
tor_config.use_tor_listener = use_tor;
|
||||
}
|
||||
Ok(tor_config)
|
||||
}
|
||||
|
||||
/// V3 API Handler/Wrapper for owner functions, which include a secure
|
||||
@@ -577,17 +629,16 @@ where
|
||||
{
|
||||
/// Create a new owner API handler for GET methods
|
||||
pub fn new(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
owner_api: &Owner<L, C, K>,
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
tor_config: Option<TorConfig>,
|
||||
running_foreign: bool,
|
||||
) -> OwnerAPIHandlerV3<L, C, K> {
|
||||
let owner_api = Owner::new(wallet.clone(), None);
|
||||
owner_api.set_tor_config(tor_config);
|
||||
let owner_api = Arc::new(owner_api);
|
||||
let wallet = owner_api.wallet_inst.clone();
|
||||
let config_path = owner_api.shared_config_path();
|
||||
let owner_api = Owner::new(wallet.clone(), None, config_path);
|
||||
OwnerAPIHandlerV3 {
|
||||
wallet,
|
||||
owner_api,
|
||||
owner_api: Arc::new(owner_api),
|
||||
shared_key: Arc::new(Mutex::new(None)),
|
||||
keychain_mask,
|
||||
running_foreign,
|
||||
@@ -706,14 +757,14 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
/// Wallet instance
|
||||
/// Wallet instance.
|
||||
pub wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
/// Wallet configuration path.
|
||||
pub config_path: ConfigPath,
|
||||
/// Keychain mask
|
||||
pub keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
/// run in doctest mode
|
||||
pub test_mode: bool,
|
||||
/// tor config
|
||||
pub tor_config: Mutex<Option<TorConfig>>,
|
||||
}
|
||||
|
||||
impl<L, C, K> ForeignAPIHandlerV2<L, C, K>
|
||||
@@ -725,15 +776,15 @@ where
|
||||
/// Create a new foreign API handler for GET methods
|
||||
pub fn new(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
config_path: ConfigPath,
|
||||
keychain_mask: Arc<Mutex<Option<SecretKey>>>,
|
||||
test_mode: bool,
|
||||
tor_config: Mutex<Option<TorConfig>>,
|
||||
) -> ForeignAPIHandlerV2<L, C, K> {
|
||||
ForeignAPIHandlerV2 {
|
||||
wallet,
|
||||
config_path,
|
||||
keychain_mask,
|
||||
test_mode,
|
||||
tor_config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,11 +807,10 @@ where
|
||||
req: Request<Incoming>,
|
||||
mask: Option<SecretKey>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
config_path: ConfigPath,
|
||||
test_mode: bool,
|
||||
tor_config: Option<TorConfig>,
|
||||
) -> Result<Response<ApiBody>, Error> {
|
||||
let api = Foreign::new(wallet, mask, Some(check_middleware), test_mode);
|
||||
api.set_tor_config(tor_config);
|
||||
let api = Foreign::new(wallet, config_path, mask, Some(check_middleware), test_mode);
|
||||
let res = Self::call_api(req, api).await?;
|
||||
Ok(json_response_pretty(&res))
|
||||
}
|
||||
@@ -776,10 +826,10 @@ where
|
||||
let mask = self.keychain_mask.lock().clone();
|
||||
let wallet = self.wallet.clone();
|
||||
let test_mode = self.test_mode;
|
||||
let tor_config = self.tor_config.lock().clone();
|
||||
let config_path = self.config_path.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
match Self::handle_post_request(req, mask, wallet, test_mode, tor_config).await {
|
||||
match Self::handle_post_request(req, mask, wallet, config_path, test_mode).await {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
error!("Request Error: {:?}", e);
|
||||
@@ -866,3 +916,48 @@ where
|
||||
serde_json::from_reader(cursor)
|
||||
.map_err(|e| Error::GenericError(format!("Invalid request body: {}", e)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::global::ChainTypes;
|
||||
use grin_wallet_config::config::update_global_config;
|
||||
use grin_wallet_config::GlobalWalletConfig;
|
||||
use std::fs;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[test]
|
||||
fn listener_reload() {
|
||||
let dir = std::env::temp_dir().join(format!("grin-wallet-listener-{}", Uuid::new_v4()));
|
||||
fs::create_dir(&dir).unwrap();
|
||||
let path = dir.join("grin-wallet.toml");
|
||||
let mut config = GlobalWalletConfig::for_chain(&ChainTypes::AutomatedTesting, &path);
|
||||
config
|
||||
.write_to_file(path.to_str().unwrap(), false, None, None)
|
||||
.unwrap();
|
||||
|
||||
let (restart_tx, restart_rx) = channel();
|
||||
register_config_listener(&path, "test_listener", restart_tx).unwrap();
|
||||
|
||||
update_global_config(&path, |config| {
|
||||
config.members.tor.as_mut().unwrap().socks_proxy_addr = "127.0.0.1:59051".into();
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
restart_rx.recv_timeout(Duration::from_secs(1)).unwrap();
|
||||
|
||||
let tor_config =
|
||||
listener_tor_config(&path, Some("obfs4 test-bridge".into()), Some(false)).unwrap();
|
||||
assert_eq!(tor_config.socks_proxy_addr, "127.0.0.1:59051");
|
||||
assert_eq!(
|
||||
tor_config.bridge.bridge_line.as_deref(),
|
||||
Some("obfs4 test-bridge")
|
||||
);
|
||||
assert!(!tor_config.use_tor_listener);
|
||||
|
||||
remove_global_config_listener(&path, "test_listener");
|
||||
fs::remove_dir_all(dir).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user