use iced::{
widget::{button, Checkbox, Column, Row, Text, TextInput},
Command, Element,
};
use log::warn;
use koibumi_common::constant::{LOCAL_SERVER, ONION_SEED, TOR_SOCKS};
use koibumi_core::{
message::{StreamNumbers, UserAgent},
net::SocketAddrExt,
Config as CoreConfig,
};
use koibumi_node::{Config, SocketAddrNode, SocksAuth};
use crate::{
config::Config as GuiConfig,
gui::{self, State},
};
#[derive(Clone, Debug)]
pub(crate) struct Tab {
pub(crate) config: Config,
server_enabled: bool,
server_value: String,
socks_enabled: bool,
socks_value: String,
socks_auth_enabled: bool,
socks_username_value: String,
socks_password_value: String,
connect_to_onion: bool,
connect_to_ip: bool,
connect_to_myself: bool,
user_agent_value: String,
stream_numbers: StreamNumbers,
pub(crate) seeds_value: String,
bootstraps_value: String,
max_incoming_connected_value: String,
max_incoming_established_value: String,
pub(crate) max_outgoing_initiated_value: String,
pub(crate) max_outgoing_established_value: String,
max_nodes: usize,
core: CoreConfig,
pub(crate) own_nodes_value: String,
}
impl Tab {
pub(crate) fn new(config: &Config) -> Self {
let (socks_username, socks_password) = if let Some(auth) = config.socks_auth() {
(auth.username().to_string(), auth.password().to_string())
} else {
(String::new(), String::new())
};
Self {
config: config.clone(),
server_enabled: config.server().is_some(),
server_value: LOCAL_SERVER.to_string(),
socks_enabled: config.socks().is_some(),
socks_value: TOR_SOCKS.to_string(),
socks_auth_enabled: config.socks_auth().is_some(),
socks_username_value: socks_username,
socks_password_value: socks_password,
connect_to_onion: config.connect_to_onion(),
connect_to_ip: config.connect_to_ip(),
connect_to_myself: config.connect_to_myself(),
user_agent_value: config.user_agent().to_string(),
stream_numbers: config.stream_numbers().clone(),
seeds_value: config
.seeds()
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(" "),
bootstraps_value: config
.bootstraps()
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(" "),
max_incoming_connected_value: config.max_incoming_connected().to_string(),
max_incoming_established_value: config.max_incoming_established().to_string(),
max_outgoing_initiated_value: config.max_outgoing_initiated().to_string(),
max_outgoing_established_value: config.max_outgoing_established().to_string(),
max_nodes: config.max_nodes(),
own_nodes_value: config
.own_nodes()
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(" "),
core: config.core().clone(),
}
}
pub(crate) fn create_config(&self) -> Config {
let server = if self.server_enabled {
self.server_value.parse().ok()
} else {
None
};
let socks = if self.socks_enabled {
self.socks_value.parse().ok()
} else {
None
};
let socks_auth = if self.socks_auth_enabled {
Some(SocksAuth::new(
self.socks_username_value.clone(),
self.socks_password_value.clone(),
))
} else {
None
};
let max_incoming_connected =
if let Ok(value) = self.max_incoming_connected_value.parse::<usize>() {
value
} else {
160
};
let max_incoming_established =
if let Ok(value) = self.max_incoming_established_value.parse::<usize>() {
value
} else {
128
};
let max_outgoing_initiated =
if let Ok(value) = self.max_outgoing_initiated_value.parse::<usize>() {
value
} else {
32
};
let max_outgoing_established =
if let Ok(value) = self.max_outgoing_established_value.parse::<usize>() {
value
} else {
8
};
let seeds = {
let mut list: Vec<SocketAddrExt> = Vec::with_capacity(1);
for s in self.seeds_value.split(' ') {
if let Ok(addr) = s.parse() {
list.push(addr);
}
}
list
};
let bootstraps = {
let mut list: Vec<SocketAddrNode> = Vec::with_capacity(2);
for s in self.bootstraps_value.split(' ') {
let addr = s.parse::<SocketAddrNode>();
if let Err(err) = addr {
warn!("{}", err);
continue;
}
list.push(addr.unwrap());
}
list
};
let own_nodes = {
let mut list: Vec<SocketAddrExt> = Vec::with_capacity(1);
for s in self.own_nodes_value.split(' ') {
if let Ok(addr) = s.parse() {
list.push(addr);
}
}
list
};
Config::builder()
.server(server)
.socks(socks)
.socks_auth(socks_auth)
.connect_to_onion(self.connect_to_onion)
.connect_to_ip(self.connect_to_ip)
.connect_to_myself(self.connect_to_myself)
.user_agent(UserAgent::new(self.user_agent_value.as_bytes().to_vec()))
.stream_numbers(self.stream_numbers.clone())
.seeds(seeds)
.bootstraps(bootstraps)
.max_incoming_connected(max_incoming_connected)
.max_incoming_established(max_incoming_established)
.max_outgoing_initiated(max_outgoing_initiated)
.max_outgoing_established(max_outgoing_established)
.max_nodes(self.max_nodes)
.own_nodes(own_nodes)
.core(self.core.clone())
.build()
}
pub(crate) fn update(&mut self, message: gui::Message, state: State) -> Command<gui::Message> {
match message {
gui::Message::SettingsToggleServerEnabled(value) => {
if state == State::Idle {
self.server_enabled = value;
}
Command::none()
}
gui::Message::SettingsServerChanged(value) => {
if state == State::Idle {
self.server_value = value;
}
Command::none()
}
gui::Message::SettingsToggleSocksEnabled(value) => {
if state == State::Idle {
self.socks_enabled = value;
}
Command::none()
}
gui::Message::SettingsSocksChanged(value) => {
if state == State::Idle {
self.socks_value = value;
}
Command::none()
}
gui::Message::SettingsToggleSocksAuthEnabled(value) => {
if state == State::Idle {
self.socks_auth_enabled = value;
}
Command::none()
}
gui::Message::SettingsSocksUsernameChanged(value) => {
if state == State::Idle {
self.socks_username_value = value;
}
Command::none()
}
gui::Message::SettingsSocksPasswordChanged(value) => {
if state == State::Idle {
self.socks_password_value = value;
}
Command::none()
}
gui::Message::SettingsToggleConnectToOnion(value) => {
if state == State::Idle {
self.connect_to_onion = value;
}
Command::none()
}
gui::Message::SettingsToggleConnectToIp(value) => {
if state == State::Idle {
self.connect_to_ip = value;
}
Command::none()
}
gui::Message::SettingsToggleConnectToMyself(value) => {
if state == State::Idle {
self.connect_to_myself = value;
}
Command::none()
}
gui::Message::SettingsUserAgentChanged(value) => {
if state == State::Idle {
self.user_agent_value = value;
}
Command::none()
}
gui::Message::SettingsSeedsChanged(value) => {
if state == State::Idle {
self.seeds_value = value;
}
Command::none()
}
gui::Message::SettingsOnionPressed => {
if state == State::Idle {
self.seeds_value = ONION_SEED.to_string();
}
Command::none()
}
gui::Message::SettingsMyselfPressed => {
if state == State::Idle {
self.seeds_value = self.server_value.clone();
}
Command::none()
}
gui::Message::SettingsBootstrapsChanged(value) => {
if state == State::Idle {
self.bootstraps_value = value;
}
Command::none()
}
gui::Message::SettingsMaxIncomingConnectedChanged(value) => {
if state == State::Idle {
self.max_incoming_connected_value = value;
}
Command::none()
}
gui::Message::SettingsMaxIncomingEstablishedChanged(value) => {
if state == State::Idle {
self.max_incoming_established_value = value;
}
Command::none()
}
gui::Message::SettingsMaxOutgoingInitiatedChanged(value) => {
if state == State::Idle {
self.max_outgoing_initiated_value = value;
}
Command::none()
}
gui::Message::SettingsMaxOutgoingEstablishedChanged(value) => {
if state == State::Idle {
self.max_outgoing_established_value = value;
}
Command::none()
}
gui::Message::SettingsOwnNodesChanged(value) => {
if state == State::Idle {
self.own_nodes_value = value;
}
Command::none()
}
_ => panic!("Program error"),
}
}
pub(crate) fn view(&self, config: &GuiConfig) -> Element<gui::Message> {
let text_size = config.text_size();
let server_checkbox = Checkbox::new("Server", self.server_enabled, |a| {
gui::Message::SettingsToggleServerEnabled(a)
})
.size(text_size)
.text_size(text_size);
let server_textinput = TextInput::new("Server", &self.server_value)
.on_input(gui::Message::SettingsServerChanged)
.size(text_size)
.padding(text_size / 4);
let server = Row::new()
.spacing(text_size / 4)
.push(server_checkbox)
.push(server_textinput);
let socks_checkbox = Checkbox::new("SOCKS", self.socks_enabled, |a| {
gui::Message::SettingsToggleSocksEnabled(a)
})
.size(text_size)
.text_size(text_size);
let socks_textinput = TextInput::new("SOCKS", &self.socks_value)
.on_input(gui::Message::SettingsSocksChanged)
.size(text_size)
.padding(text_size / 4);
let socks = Row::new()
.spacing(text_size / 4)
.push(socks_checkbox)
.push(socks_textinput);
let socks_auth_checkbox = Checkbox::new("SOCKS auth", self.socks_auth_enabled, |a| {
gui::Message::SettingsToggleSocksAuthEnabled(a)
})
.size(text_size)
.text_size(text_size);
let socks_username = TextInput::new("Username", &self.socks_username_value)
.on_input(gui::Message::SettingsSocksUsernameChanged)
.size(text_size)
.padding(text_size / 4);
let socks_password = TextInput::new("Password", &self.socks_password_value)
.on_input(gui::Message::SettingsSocksPasswordChanged)
.size(text_size)
.padding(text_size / 4);
let socks_auth = Row::new()
.spacing(text_size / 4)
.push(socks_auth_checkbox)
.push(socks_username)
.push(socks_password);
let connect_to_onion = Checkbox::new(
"Connect to Onion address nodes",
self.connect_to_onion,
|a| gui::Message::SettingsToggleConnectToOnion(a),
)
.size(text_size)
.text_size(text_size);
let connect_to_ip = Checkbox::new("Connect to IP address nodes", self.connect_to_ip, |a| {
gui::Message::SettingsToggleConnectToIp(a)
})
.size(text_size)
.text_size(text_size);
let connect_to_myself = Checkbox::new("Connect to Myself", self.connect_to_myself, |a| {
gui::Message::SettingsToggleConnectToMyself(a)
})
.size(text_size)
.text_size(text_size);
let user_agent_textinput = TextInput::new("/User agent/", &self.user_agent_value)
.on_input(gui::Message::SettingsUserAgentChanged)
.size(text_size)
.padding(text_size / 4);
let user_agent = Row::new()
.spacing(text_size / 2)
.push(Text::new("User agent").size(text_size))
.push(user_agent_textinput);
let seeds_textinput = TextInput::new("address:port", &self.seeds_value)
.on_input(gui::Message::SettingsSeedsChanged)
.size(text_size)
.padding(text_size / 4);
let seeds = Row::new()
.spacing(text_size / 2)
.push(Text::new("Seeds").size(text_size))
.push(seeds_textinput);
let onion_button =
button(Text::new("Onion").size(text_size)).on_press(gui::Message::SettingsOnionPressed);
let myself_button = button(Text::new("Myself").size(text_size))
.on_press(gui::Message::SettingsMyselfPressed);
let seed_buttons = Row::new()
.spacing(text_size / 4)
.push(onion_button)
.push(myself_button);
let bootstraps_textinput = TextInput::new("address:port", &self.bootstraps_value)
.on_input(gui::Message::SettingsBootstrapsChanged)
.size(text_size)
.padding(text_size / 4);
let bootstraps = Row::new()
.spacing(text_size / 2)
.push(Text::new("Bootstraps").size(text_size))
.push(bootstraps_textinput);
let max_incoming_connected_textinput =
TextInput::new("", &self.max_incoming_connected_value)
.on_input(gui::Message::SettingsMaxIncomingConnectedChanged)
.size(text_size)
.padding(text_size / 4);
let max_incoming_established_textinput =
TextInput::new("", &self.max_incoming_established_value)
.on_input(gui::Message::SettingsMaxIncomingEstablishedChanged)
.size(text_size)
.padding(text_size / 4);
let max_incoming = Row::new()
.spacing(text_size / 2)
.push(Text::new("Max incoming:").size(text_size))
.push(max_incoming_connected_textinput)
.push(Text::new("connected,").size(text_size))
.push(max_incoming_established_textinput)
.push(Text::new("established").size(text_size));
let max_outgoing_initiated_textinput =
TextInput::new("", &self.max_outgoing_initiated_value)
.on_input(gui::Message::SettingsMaxOutgoingInitiatedChanged)
.size(text_size)
.padding(text_size / 4);
let max_outgoing_established_textinput =
TextInput::new("", &self.max_outgoing_established_value)
.on_input(gui::Message::SettingsMaxOutgoingEstablishedChanged)
.size(text_size)
.padding(text_size / 4);
let max_outgoing = Row::new()
.spacing(text_size / 2)
.push(Text::new("Max outgoing:").size(text_size))
.push(max_outgoing_initiated_textinput)
.push(Text::new("initiated,").size(text_size))
.push(max_outgoing_established_textinput)
.push(Text::new("established").size(text_size));
let own_nodes_textinput = TextInput::new("address:port", &self.own_nodes_value)
.on_input(gui::Message::SettingsOwnNodesChanged)
.size(text_size)
.padding(text_size / 4);
let own_nodes = Row::new()
.spacing(text_size / 4)
.push(Text::new("Own nodes").size(text_size))
.push(own_nodes_textinput);
Column::new()
.spacing(text_size / 4)
.push(server)
.push(socks)
.push(socks_auth)
.push(connect_to_onion)
.push(connect_to_ip)
.push(connect_to_myself)
.push(user_agent)
.push(seeds)
.push(seed_buttons)
.push(bootstraps)
.push(max_incoming)
.push(max_outgoing)
.push(own_nodes)
.into()
}
}