gui(installer): add electrum node option
This commit is contained in:
parent
341e4467db
commit
c93aa88d74
@ -11,7 +11,7 @@ use crate::{
|
||||
lianalite::client::{auth::AuthClient, backend::api},
|
||||
node::{
|
||||
bitcoind::{Bitcoind, ConfigField, RpcAuthType},
|
||||
NodeType,
|
||||
electrum, NodeType,
|
||||
},
|
||||
};
|
||||
use async_hwi::{DeviceKind, Version};
|
||||
@ -77,10 +77,16 @@ pub enum DefineBitcoind {
|
||||
RpcAuthTypeSelected(RpcAuthType),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DefineElectrum {
|
||||
ConfigFieldEdited(electrum::ConfigField, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DefineNode {
|
||||
NodeTypeSelected(NodeType),
|
||||
DefineBitcoind(DefineBitcoind),
|
||||
DefineElectrum(DefineElectrum),
|
||||
PingResult((NodeType, Result<(), Error>)),
|
||||
Ping,
|
||||
}
|
||||
|
||||
@ -701,6 +701,7 @@ pub enum Error {
|
||||
Backend(Arc<DaemonError>),
|
||||
Settings(SettingsError),
|
||||
Bitcoind(String),
|
||||
Electrum(String),
|
||||
CannotCreateDatadir(String),
|
||||
CannotCreateFile(String),
|
||||
CannotWriteToFile(String),
|
||||
@ -752,6 +753,7 @@ impl std::fmt::Display for Error {
|
||||
Self::Backend(e) => write!(f, "Remote backend error: {}", e),
|
||||
Self::Settings(e) => write!(f, "Settings file error: {}", e),
|
||||
Self::Bitcoind(e) => write!(f, "Failed to ping bitcoind: {}", e),
|
||||
Self::Electrum(e) => write!(f, "Failed to ping Electrum: {}", e),
|
||||
Self::CannotCreateDatadir(e) => write!(f, "Failed to create datadir: {}", e),
|
||||
Self::CannotGetAvailablePort(e) => write!(f, "Failed to get available port: {}", e),
|
||||
Self::CannotWriteToFile(e) => write!(f, "Failed to write to file: {}", e),
|
||||
|
||||
86
gui/src/installer/step/node/electrum.rs
Normal file
86
gui/src/installer/step/node/electrum.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use iced::Command;
|
||||
use liana::{
|
||||
config::ElectrumConfig,
|
||||
electrum_client::{self, ElectrumApi},
|
||||
};
|
||||
use liana_ui::{component::form, widget::*};
|
||||
|
||||
use crate::{
|
||||
installer::{
|
||||
context::Context,
|
||||
message::{self, Message},
|
||||
view, Error,
|
||||
},
|
||||
node::electrum::ConfigField,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DefineElectrum {
|
||||
address: form::Value<String>,
|
||||
}
|
||||
|
||||
impl DefineElectrum {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
address: form::Value::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_try_ping(&self) -> bool {
|
||||
!self.address.value.is_empty() && self.address.valid
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: message::DefineNode) -> Command<Message> {
|
||||
if let message::DefineNode::DefineElectrum(msg) = message {
|
||||
match msg {
|
||||
message::DefineElectrum::ConfigFieldEdited(field, value) => match field {
|
||||
ConfigField::Address => {
|
||||
let value_noprefix = if value.starts_with("ssl://") {
|
||||
value.replacen("ssl://", "", 1)
|
||||
} else {
|
||||
value.replacen("tcp://", "", 1)
|
||||
};
|
||||
let noprefix_parts: Vec<_> = value_noprefix.split(':').collect();
|
||||
self.address.value.clone_from(&value); // save the value including any prefix
|
||||
self.address.valid = noprefix_parts.len() == 2
|
||||
&& !noprefix_parts
|
||||
.first()
|
||||
.expect("there are two parts")
|
||||
.is_empty()
|
||||
&& noprefix_parts
|
||||
.last()
|
||||
.expect("there are two parts")
|
||||
.parse::<u16>() // check it is a port
|
||||
.is_ok();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
Command::none()
|
||||
}
|
||||
|
||||
pub fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
if self.can_try_ping() {
|
||||
ctx.bitcoin_backend = Some(liana::config::BitcoinBackend::Electrum(ElectrumConfig {
|
||||
addr: self.address.value.clone(),
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<Message> {
|
||||
view::define_electrum(&self.address)
|
||||
}
|
||||
|
||||
pub fn ping(&self) -> Result<(), Error> {
|
||||
let builder = electrum_client::Config::builder();
|
||||
let config = builder.timeout(Some(3)).build();
|
||||
let client = electrum_client::Client::from_config(&self.address.value, config)
|
||||
.map_err(|e| Error::Electrum(e.to_string()))?;
|
||||
client
|
||||
.raw_call("server.ping", [])
|
||||
.map_err(|e| Error::Electrum(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
pub mod bitcoind;
|
||||
pub mod electrum;
|
||||
|
||||
use crate::{
|
||||
hw::HardwareWallets,
|
||||
installer::{
|
||||
context::Context,
|
||||
message::{self, Message},
|
||||
step::{node::bitcoind::DefineBitcoind, Step},
|
||||
step::{
|
||||
node::{bitcoind::DefineBitcoind, electrum::DefineElectrum},
|
||||
Step,
|
||||
},
|
||||
view, Error,
|
||||
},
|
||||
node::NodeType,
|
||||
@ -17,54 +21,65 @@ use liana_ui::widget::Element;
|
||||
#[derive(Clone)]
|
||||
pub enum NodeDefinition {
|
||||
Bitcoind(DefineBitcoind),
|
||||
Electrum(DefineElectrum),
|
||||
}
|
||||
|
||||
impl NodeDefinition {
|
||||
fn new(node_type: NodeType) -> Self {
|
||||
match node_type {
|
||||
NodeType::Bitcoind => NodeDefinition::Bitcoind(DefineBitcoind::new()),
|
||||
NodeType::Electrum => NodeDefinition::Electrum(DefineElectrum::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn node_type(&self) -> NodeType {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(_) => NodeType::Bitcoind,
|
||||
NodeDefinition::Electrum(_) => NodeType::Electrum,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.apply(ctx),
|
||||
NodeDefinition::Electrum(def) => def.apply(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
fn can_try_ping(&self) -> bool {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.can_try_ping(),
|
||||
NodeDefinition::Electrum(def) => def.can_try_ping(),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_context(&mut self, ctx: &Context) {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.load_context(ctx),
|
||||
NodeDefinition::Electrum(_) => {
|
||||
// noop for now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: message::DefineNode) -> Command<Message> {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.update(message),
|
||||
NodeDefinition::Electrum(def) => def.update(message),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.view(),
|
||||
NodeDefinition::Electrum(def) => def.view(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ping(&self) -> Result<(), Error> {
|
||||
match self {
|
||||
NodeDefinition::Bitcoind(def) => def.ping(),
|
||||
NodeDefinition::Electrum(def) => def.ping(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -99,6 +114,7 @@ impl DefineNode {
|
||||
let available_node_types = [
|
||||
// This is the order in which the available node types will be shown to the user.
|
||||
NodeType::Bitcoind,
|
||||
NodeType::Electrum,
|
||||
];
|
||||
assert!(available_node_types.contains(&selected_node_type));
|
||||
|
||||
@ -187,6 +203,9 @@ impl Step for DefineNode {
|
||||
msg @ message::DefineNode::DefineBitcoind(_) => {
|
||||
return self.update_node(NodeType::Bitcoind, msg);
|
||||
}
|
||||
msg @ message::DefineNode::DefineElectrum(_) => {
|
||||
return self.update_node(NodeType::Electrum, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
|
||||
@ -41,7 +41,7 @@ use crate::{
|
||||
},
|
||||
node::{
|
||||
bitcoind::{ConfigField, RpcAuthType, RpcAuthValues, StartInternalBitcoindError},
|
||||
NodeType,
|
||||
electrum, NodeType,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1180,6 +1180,7 @@ pub fn define_bitcoin_node<'a>(
|
||||
row.push(radio(
|
||||
match node_type {
|
||||
NodeType::Bitcoind => "Bitcoin Core",
|
||||
NodeType::Electrum => "Electrum",
|
||||
},
|
||||
node_type,
|
||||
Some(selected_node_type),
|
||||
@ -1360,6 +1361,27 @@ pub fn define_bitcoind<'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn define_electrum<'a>(address: &form::Value<String>) -> Element<'a, Message> {
|
||||
let col_address = Column::new()
|
||||
.push(text("Address:").bold())
|
||||
.push(
|
||||
form::Form::new_trimmed("127.0.0.1:50001", address, |msg| {
|
||||
Message::DefineNode(DefineNode::DefineElectrum(
|
||||
message::DefineElectrum::ConfigFieldEdited(electrum::ConfigField::Address, msg),
|
||||
))
|
||||
})
|
||||
.warning(
|
||||
"Please enter correct address (including port), \
|
||||
optionally prefixed with tcp:// or ssl://",
|
||||
)
|
||||
.size(text::P1_SIZE)
|
||||
.padding(10),
|
||||
)
|
||||
.spacing(10);
|
||||
|
||||
Column::new().push(col_address).spacing(50).into()
|
||||
}
|
||||
|
||||
pub fn select_bitcoind_type<'a>(progress: (usize, usize)) -> Element<'a, Message> {
|
||||
layout(
|
||||
progress,
|
||||
|
||||
14
gui/src/node/electrum.rs
Normal file
14
gui/src/node/electrum.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum ConfigField {
|
||||
Address,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfigField {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ConfigField::Address => write!(f, "RPC address"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
pub mod bitcoind;
|
||||
pub mod electrum;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||
pub enum NodeType {
|
||||
Bitcoind,
|
||||
Electrum,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user