use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use crate::grin_keychain::Keychain;
use crate::grin_util::secp::key::SecretKey;
use crate::grin_util::Mutex;
use crate::api_impl::owner;
use crate::types::NodeClient;
use crate::Error;
use crate::{WalletInst, WalletLCProvider};
const MESSAGE_QUEUE_MAX_LEN: usize = 10_000;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum StatusMessage {
UpdatingOutputs(String),
UpdatingTransactions(String),
FullScanWarn(String),
Scanning(String, u8),
ScanningComplete(String),
UpdateWarning(String),
}
pub fn start_updater_log_thread(
rx: Receiver<StatusMessage>,
queue: Arc<Mutex<Vec<StatusMessage>>>,
) -> Result<(), Error> {
let _ = thread::Builder::new()
.name("wallet-updater-status".to_string())
.spawn(move || {
while let Ok(m) = rx.recv() {
{
let mut q = queue.lock();
q.insert(0, m.clone());
while q.len() > MESSAGE_QUEUE_MAX_LEN {
q.pop();
}
}
match m {
StatusMessage::UpdatingOutputs(s) => debug!("{}", s),
StatusMessage::UpdatingTransactions(s) => debug!("{}", s),
StatusMessage::FullScanWarn(s) => warn!("{}", s),
StatusMessage::Scanning(s, m) => {
debug!("{}", s);
warn!("Scanning - {}% complete", m);
}
StatusMessage::ScanningComplete(s) => warn!("{}", s),
StatusMessage::UpdateWarning(s) => warn!("{}", s),
}
}
})?;
Ok(())
}
pub struct Updater<'a, L, C, K>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
is_running: Arc<AtomicBool>,
}
impl<'a, L, C, K> Updater<'a, L, C, K>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
pub fn new(
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
is_running: Arc<AtomicBool>,
) -> Self {
is_running.store(false, Ordering::Relaxed);
Updater {
wallet_inst,
is_running,
}
}
pub fn run(
&self,
frequency: Duration,
keychain_mask: Option<SecretKey>,
status_send_channel: &Option<Sender<StatusMessage>>,
) -> Result<(), Error> {
self.is_running.store(true, Ordering::Relaxed);
loop {
let wallet_opened = {
let mut w_lock = self.wallet_inst.lock();
let w_provider = w_lock.lc_provider()?;
w_provider.wallet_inst().is_ok()
};
if wallet_opened {
owner::update_wallet_state(
self.wallet_inst.clone(),
(&keychain_mask).as_ref(),
status_send_channel,
false,
)?;
}
if !self.is_running.load(Ordering::Relaxed) {
break;
}
thread::sleep(frequency);
}
Ok(())
}
}