use crate::{Credentials, Error};
use bip39::Mnemonic;
use std::str::FromStr;
use tracing;
#[derive(uniffi::Object, Clone)]
pub struct Signer {
seed: Vec<u8>,
pub(crate) inner: gl_client::signer::Signer,
credentials: Option<Credentials>,
}
#[uniffi::export]
impl Signer {
#[uniffi::constructor()]
pub fn new(phrase: String) -> Result<Signer, Error> {
let phrase = Mnemonic::from_str(phrase.as_str()).map_err(|_e| Error::PhraseCorrupted())?;
let seed = phrase.to_seed_normalized(&"").to_vec();
Self::new_from_seed(seed)
}
#[uniffi::constructor()]
pub fn new_from_seed(seed: Vec<u8>) -> Result<Signer, Error> {
let credentials = gl_client::credentials::Nobody::new();
let inner = gl_client::signer::Signer::new(
seed.clone(),
gl_client::bitcoin::Network::Bitcoin,
credentials,
)
.map_err(|e| Error::Other(e.to_string()))?;
let credentials = None;
Ok(Signer {
seed,
inner,
credentials,
})
}
pub fn authenticate(&self, creds: &Credentials) -> Result<Signer, Error> {
let credentials = Some(creds.clone());
let inner = gl_client::signer::Signer::new(
self.seed.clone(),
gl_client::bitcoin::Network::Bitcoin,
creds.inner.clone(),
)
.map_err(|e| Error::Other(e.to_string()))?;
Ok(Signer {
inner,
credentials,
..self.clone()
})
}
pub fn start(&self) -> Result<Handle, Error> {
Ok(Handle::spawn(self.inner.clone()))
}
pub fn node_id(&self) -> Vec<u8> {
self.inner.node_id()
}
}
impl Signer {
async fn run(&self, signal: tokio::sync::mpsc::Receiver<()>) {
self.inner
.run_forever(signal)
.await
.expect("Error running signer loop");
}
}
#[derive(uniffi::Object, Clone)]
pub struct Handle {
chan: tokio::sync::mpsc::Sender<()>,
}
#[uniffi::export]
impl Handle {
pub fn stop(&self) {
self.chan.try_send(()).expect("sending shutdown signal");
}
}
impl Handle {
pub(crate) fn spawn(signer: gl_client::signer::Signer) -> Self {
let (tx, rx) = tokio::sync::mpsc::channel(1);
crate::util::get_signer_runtime().spawn(async move {
if let Err(e) = signer.run_forever(rx).await {
tracing::error!("Error running signer: {e}");
}
});
Self { chan: tx }
}
pub(crate) fn try_stop(&self) -> bool {
self.chan.try_send(()).is_ok()
}
}