wallet: start foreign api server on opening
This commit is contained in:
parent
4ea93407a7
commit
c0db456838
1 changed files with 82 additions and 1 deletions
|
@ -13,12 +13,15 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::{fs, thread};
|
use std::{fs, thread};
|
||||||
|
use std::net::{SocketAddr, TcpListener};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, mpsc, RwLock};
|
use std::sync::{Arc, mpsc, RwLock};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||||
use std::thread::Thread;
|
use std::thread::Thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use futures::channel::oneshot;
|
||||||
|
use grin_api::{ApiServer, Router};
|
||||||
use grin_chain::SyncStatus;
|
use grin_chain::SyncStatus;
|
||||||
use grin_core::global;
|
use grin_core::global;
|
||||||
use grin_keychain::{ExtKeychain, Keychain};
|
use grin_keychain::{ExtKeychain, Keychain};
|
||||||
|
@ -26,6 +29,7 @@ use grin_util::Mutex;
|
||||||
use grin_util::secp::SecretKey;
|
use grin_util::secp::SecretKey;
|
||||||
use grin_util::types::ZeroingString;
|
use grin_util::types::ZeroingString;
|
||||||
use grin_wallet_api::Owner;
|
use grin_wallet_api::Owner;
|
||||||
|
use grin_wallet_controller::controller::ForeignAPIHandlerV2;
|
||||||
use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
|
use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
|
||||||
use grin_wallet_libwallet::{Error, NodeClient, StatusMessage, WalletInst, WalletLCProvider};
|
use grin_wallet_libwallet::{Error, NodeClient, StatusMessage, WalletInst, WalletLCProvider};
|
||||||
use grin_wallet_libwallet::api_impl::owner::{retrieve_summary_info, retrieve_txs};
|
use grin_wallet_libwallet::api_impl::owner::{retrieve_summary_info, retrieve_txs};
|
||||||
|
@ -47,6 +51,9 @@ pub struct Wallet {
|
||||||
/// Wallet sync thread.
|
/// Wallet sync thread.
|
||||||
sync_thread: Arc<RwLock<Option<Thread>>>,
|
sync_thread: Arc<RwLock<Option<Thread>>>,
|
||||||
|
|
||||||
|
/// Foreign API server.
|
||||||
|
foreign_api_server: Arc<RwLock<Option<ApiServer>>>,
|
||||||
|
|
||||||
/// Flag to check if wallet reopening is needed.
|
/// Flag to check if wallet reopening is needed.
|
||||||
reopen: Arc<AtomicBool>,
|
reopen: Arc<AtomicBool>,
|
||||||
/// Flag to check if wallet is open.
|
/// Flag to check if wallet is open.
|
||||||
|
@ -74,6 +81,11 @@ pub struct Wallet {
|
||||||
repair_progress: Arc<AtomicU8>
|
repair_progress: Arc<AtomicU8>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default Foreign API server host.
|
||||||
|
const DEFAULT_FOREIGN_API_HOST: &str = "127.0.0.1";
|
||||||
|
/// Default Foreign API server port.
|
||||||
|
const DEFAULT_FOREIGN_API_PORT: u16 = 3421;
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
/// Create new [`Wallet`] instance with provided [`WalletConfig`].
|
/// Create new [`Wallet`] instance with provided [`WalletConfig`].
|
||||||
fn new(config: WalletConfig) -> Self {
|
fn new(config: WalletConfig) -> Self {
|
||||||
|
@ -82,6 +94,7 @@ impl Wallet {
|
||||||
instance: None,
|
instance: None,
|
||||||
instance_ext_conn_id: None,
|
instance_ext_conn_id: None,
|
||||||
sync_thread: Arc::from(RwLock::new(None)),
|
sync_thread: Arc::from(RwLock::new(None)),
|
||||||
|
foreign_api_server: Arc::new(RwLock::new(None)),
|
||||||
reopen: Arc::new(AtomicBool::new(false)),
|
reopen: Arc::new(AtomicBool::new(false)),
|
||||||
is_open: Arc::from(AtomicBool::new(false)),
|
is_open: Arc::from(AtomicBool::new(false)),
|
||||||
closing: Arc::new(AtomicBool::new(false)),
|
closing: Arc::new(AtomicBool::new(false)),
|
||||||
|
@ -254,6 +267,18 @@ impl Wallet {
|
||||||
let wallet_close = self.clone();
|
let wallet_close = self.clone();
|
||||||
let instance = wallet_close.instance.clone().unwrap();
|
let instance = wallet_close.instance.clone().unwrap();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
// Stop created API server.
|
||||||
|
let api_server_exists = {
|
||||||
|
wallet_close.foreign_api_server.read().unwrap().is_some()
|
||||||
|
};
|
||||||
|
if api_server_exists {
|
||||||
|
let _ = thread::spawn(move || {
|
||||||
|
let mut api_server_w = wallet_close.foreign_api_server.write().unwrap();
|
||||||
|
api_server_w.as_mut().unwrap().stop();
|
||||||
|
*api_server_w = None;
|
||||||
|
}).join();
|
||||||
|
}
|
||||||
|
|
||||||
// Close the wallet.
|
// Close the wallet.
|
||||||
Self::close_wallet(&instance);
|
Self::close_wallet(&instance);
|
||||||
|
|
||||||
|
@ -416,7 +441,7 @@ const SYNC_DELAY: Duration = Duration::from_millis(60 * 1000);
|
||||||
const SYNC_ATTEMPTS: u8 = 10;
|
const SYNC_ATTEMPTS: u8 = 10;
|
||||||
|
|
||||||
/// Launch thread to sync wallet data from node.
|
/// Launch thread to sync wallet data from node.
|
||||||
fn start_sync(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
fn start_sync(mut wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
// Reset progress values.
|
// Reset progress values.
|
||||||
wallet.info_sync_progress.store(0, Ordering::Relaxed);
|
wallet.info_sync_progress.store(0, Ordering::Relaxed);
|
||||||
wallet.txs_sync_progress.store(0, Ordering::Relaxed);
|
wallet.txs_sync_progress.store(0, Ordering::Relaxed);
|
||||||
|
@ -450,6 +475,20 @@ fn start_sync(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start Foreign API listener if API server was not created.
|
||||||
|
let api_server_exists = {
|
||||||
|
wallet.foreign_api_server.read().unwrap().is_some()
|
||||||
|
};
|
||||||
|
if !api_server_exists {
|
||||||
|
match start_api_server(&mut wallet, keychain.clone()) {
|
||||||
|
Ok(api_server) => {
|
||||||
|
let mut api_server_w = wallet.foreign_api_server.write().unwrap();
|
||||||
|
*api_server_w = Some(api_server);
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scan outputs if repair is needed or sync data if there is no error.
|
// Scan outputs if repair is needed or sync data if there is no error.
|
||||||
if !wallet.sync_error() {
|
if !wallet.sync_error() {
|
||||||
if wallet.is_repairing() {
|
if wallet.is_repairing() {
|
||||||
|
@ -485,6 +524,48 @@ fn start_sync(wallet: Wallet, keychain: Option<SecretKey>) -> Thread {
|
||||||
}).thread().clone()
|
}).thread().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start Foreign API server to accept txs via Tor and receive mining rewards from Stratum server.
|
||||||
|
fn start_api_server(wallet: &mut Wallet,
|
||||||
|
keychain: Option<SecretKey>) -> Result<ApiServer, Error> {
|
||||||
|
// Find free port.
|
||||||
|
let free_port = (DEFAULT_FOREIGN_API_PORT..).find(|port| {
|
||||||
|
return match TcpListener::bind((DEFAULT_FOREIGN_API_HOST, port.to_owned())) {
|
||||||
|
Ok(_) => {
|
||||||
|
let node_p2p_port = NodeConfig::get_p2p_port();
|
||||||
|
let node_api_port = NodeConfig::get_api_ip_port().1;
|
||||||
|
port.to_string() != node_p2p_port && port.to_string() != node_api_port
|
||||||
|
},
|
||||||
|
Err(_) => false
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
// Setup API server address.
|
||||||
|
let api_addr = format!("{}:{}", DEFAULT_FOREIGN_API_HOST, free_port);
|
||||||
|
|
||||||
|
// Start Foreign API server thread.
|
||||||
|
let instance = wallet.instance.clone().unwrap();
|
||||||
|
let api_handler_v2 = ForeignAPIHandlerV2::new(instance,
|
||||||
|
Arc::new(Mutex::new(keychain)),
|
||||||
|
false,
|
||||||
|
Mutex::new(None));
|
||||||
|
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: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
|
||||||
|
Box::leak(Box::new(oneshot::channel::<()>()));
|
||||||
|
|
||||||
|
let mut apis = ApiServer::new();
|
||||||
|
println!("Starting HTTP Foreign listener API server at {}.", api_addr);
|
||||||
|
let socket_addr: SocketAddr = api_addr.parse().unwrap();
|
||||||
|
let _ = apis.start(socket_addr, router, None, api_chan)
|
||||||
|
.map_err(|_| Error::GenericError("API thread failed to start".to_string()))?;
|
||||||
|
|
||||||
|
println!("HTTP Foreign listener started.");
|
||||||
|
Ok(apis)
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve [`WalletData`] from node.
|
/// Retrieve [`WalletData`] from node.
|
||||||
fn sync_wallet_data(wallet: &Wallet, keychain: Option<SecretKey>) {
|
fn sync_wallet_data(wallet: &Wallet, keychain: Option<SecretKey>) {
|
||||||
println!("SYNC start, attempts: {}", wallet.get_sync_attempts());
|
println!("SYNC start, attempts: {}", wallet.get_sync_attempts());
|
||||||
|
|
Loading…
Reference in a new issue