use log::warn;
use koibumi_common_sync::constant::{LOCAL_SERVER, ONION_SEED, TOR_SOCKS};
use koibumi_core::{
message::{StreamNumbers, UserAgent},
net::SocketAddrExt,
Config as CoreConfig,
};
use koibumi_node_sync::{Config, SocketAddrNode, SocksAuth};
use crate::{config::Config as GuiConfig, gui::State, ids::Ids};
#[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 set_widgets(
&mut self,
ui: &mut conrod_core::UiCell,
ids: &mut Ids,
config: &GuiConfig,
state: State,
) {
let text_size = config.text_size();
let font_id = ui.fonts.ids().next().unwrap();
use conrod_core::{
color, text, widget, Colorable, Labelable, Positionable, Sizeable, Widget,
};
widget::Canvas::new()
.top_left_of(ids.tabs_body)
.wh_of(ids.tabs_body)
.scroll_kids_vertically()
.set(ids.settings, ui);
widget::Scrollbar::y_axis(ids.settings)
.auto_hide(true)
.set(ids.settings_scrollbar, ui);
let label = "Server";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.server_enabled)
.top_left_with_margins_on(ids.settings, 2.0, 2.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_server_enabled, ui)
.last()
{
if state == State::Idle {
self.server_enabled = value;
}
}
for event in widget::TextBox::new(&self.server_value)
.right_from(ids.settings_server_enabled, 2.0)
.font_size(text_size as u32)
.w_h(320.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_server, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => self.server_value = string,
}
}
}
let label = "SOCKS";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.socks_enabled)
.down_from(ids.settings_server_enabled, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_socks_enabled, ui)
.last()
{
if state == State::Idle {
self.socks_enabled = value;
}
}
for event in widget::TextBox::new(&self.socks_value)
.right_from(ids.settings_socks_enabled, 2.0)
.font_size(text_size as u32)
.w_h(320.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_socks, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => self.socks_value = string,
}
}
}
let label = "SOCKS auth";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.socks_auth_enabled)
.down_from(ids.settings_socks_enabled, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_socks_auth_enabled, ui)
.last()
{
if state == State::Idle {
self.socks_auth_enabled = value;
}
}
for event in widget::TextBox::new(&self.socks_username_value)
.right_from(ids.settings_socks_auth_enabled, 2.0)
.font_size(text_size as u32)
.w_h(160.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_socks_username, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => self.socks_username_value = string,
}
}
}
for event in widget::TextBox::new(&self.socks_password_value)
.right_from(ids.settings_socks_username, 2.0)
.font_size(text_size as u32)
.w_h(160.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_socks_password, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => self.socks_password_value = string,
}
}
}
let label = "Connect to Onion address nodes";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.connect_to_onion)
.down_from(ids.settings_socks_auth_enabled, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_connect_to_onion, ui)
.last()
{
if state == State::Idle {
self.connect_to_onion = value;
}
}
let label = "Connect to IP address nodes";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.connect_to_ip)
.down_from(ids.settings_connect_to_onion, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_connect_to_ip, ui)
.last()
{
if state == State::Idle {
self.connect_to_ip = value;
}
}
let label = "Connect to Myself";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
if let Some(value) = widget::Toggle::new(self.connect_to_myself)
.down_from(ids.settings_connect_to_ip, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.set(ids.settings_connect_to_myself, ui)
.last()
{
if state == State::Idle {
self.connect_to_myself = value;
}
}
let label = "User agent";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_connect_to_myself, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_user_agent_label, ui);
widget::Canvas::new()
.right_from(ids.settings_user_agent_label, 2.0)
.w_h(320.0, text_size as f64 + 8.0)
.scroll_kids_vertically()
.color(color::LIGHT_GRAY)
.set(ids.settings_user_agent_canvas, ui);
if let Some(edit) = widget::TextEdit::new(&self.user_agent_value)
.top_left_with_margins_on(ids.settings_user_agent_canvas, 2.0, 2.0)
.padded_w_of(ids.settings_user_agent_canvas, 2.0)
.parent(ids.settings_user_agent_canvas)
.restrict_to_height(false)
.font_size(text_size as u32)
.wrap_by_character()
.color(color::BLACK)
.line_spacing((text_size / 2) as f64)
.set(ids.settings_user_agent, ui)
{
if state == State::Idle {
self.user_agent_value = edit;
}
}
widget::Scrollbar::y_axis(ids.settings_user_agent_canvas)
.auto_hide(true)
.set(ids.settings_user_agent_scrollbar, ui);
let label = "Seeds";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_user_agent_label, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_seeds_label, ui);
widget::Canvas::new()
.right_from(ids.settings_seeds_label, 2.0)
.w_h(320.0, text_size as f64 + 8.0)
.scroll_kids_vertically()
.color(color::LIGHT_GRAY)
.set(ids.settings_seeds_canvas, ui);
if let Some(edit) = widget::TextEdit::new(&self.seeds_value)
.top_left_with_margins_on(ids.settings_seeds_canvas, 2.0, 2.0)
.padded_w_of(ids.settings_seeds_canvas, 2.0)
.parent(ids.settings_seeds_canvas)
.restrict_to_height(false)
.font_size(text_size as u32)
.wrap_by_character()
.color(color::BLACK)
.line_spacing((text_size / 2) as f64)
.set(ids.settings_seeds, ui)
{
if state == State::Idle {
self.seeds_value = edit;
}
}
widget::Scrollbar::y_axis(ids.settings_seeds_canvas)
.auto_hide(true)
.set(ids.settings_seeds_scrollbar, ui);
let label = "Onion";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
for _click in widget::Button::new()
.down_from(ids.settings_seeds_label, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.color(color::DARK_GRAY)
.label_color(color::WHITE)
.set(ids.settings_onion_button, ui)
{
if state == State::Idle {
self.seeds_value = ONION_SEED.to_string();
}
}
let label = "Myself";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
for _click in widget::Button::new()
.right_from(ids.settings_onion_button, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.label_font_size(text_size as u32)
.label(label)
.color(color::DARK_GRAY)
.label_color(color::WHITE)
.set(ids.settings_myself_button, ui)
{
if state == State::Idle {
self.seeds_value = self.server_value.clone();
}
}
let label = "Bootstraps";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_onion_button, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_bootstraps_label, ui);
widget::Canvas::new()
.right_from(ids.settings_bootstraps_label, 2.0)
.w_h(320.0, text_size as f64 + 8.0)
.scroll_kids_vertically()
.color(color::LIGHT_GRAY)
.set(ids.settings_bootstraps_canvas, ui);
if let Some(edit) = widget::TextEdit::new(&self.bootstraps_value)
.top_left_with_margins_on(ids.settings_bootstraps_canvas, 2.0, 2.0)
.padded_w_of(ids.settings_bootstraps_canvas, 2.0)
.parent(ids.settings_bootstraps_canvas)
.restrict_to_height(false)
.font_size(text_size as u32)
.wrap_by_character()
.color(color::BLACK)
.line_spacing((text_size / 2) as f64)
.set(ids.settings_bootstraps, ui)
{
if state == State::Idle {
self.bootstraps_value = edit;
}
}
widget::Scrollbar::y_axis(ids.settings_seeds_canvas)
.auto_hide(true)
.set(ids.settings_seeds_scrollbar, ui);
let label = "Max incoming:";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_bootstraps_label, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_incoming_label, ui);
for event in widget::TextBox::new(&self.max_incoming_connected_value)
.right_from(ids.settings_max_incoming_label, 2.0)
.font_size(text_size as u32)
.w_h(80.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_max_incoming_connected, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => {
self.max_incoming_connected_value = string
}
}
}
}
let label = "connected, ";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.right_from(ids.settings_max_incoming_connected, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_incoming_connected_label, ui);
for event in widget::TextBox::new(&self.max_incoming_established_value)
.right_from(ids.settings_max_incoming_connected_label, 2.0)
.font_size(text_size as u32)
.w_h(80.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_max_incoming_established, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => {
self.max_incoming_established_value = string
}
}
}
}
let label = "established";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.right_from(ids.settings_max_incoming_established, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_incoming_established_label, ui);
let label = "Max outgoing:";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_max_incoming_label, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_outgoing_label, ui);
for event in widget::TextBox::new(&self.max_outgoing_initiated_value)
.right_from(ids.settings_max_outgoing_label, 2.0)
.font_size(text_size as u32)
.w_h(80.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_max_outgoing_initiated, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => {
self.max_outgoing_initiated_value = string
}
}
}
}
let label = "initiated, ";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.right_from(ids.settings_max_outgoing_initiated, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_outgoing_initiated_label, ui);
for event in widget::TextBox::new(&self.max_outgoing_established_value)
.right_from(ids.settings_max_outgoing_initiated_label, 2.0)
.font_size(text_size as u32)
.w_h(80.0, text_size as f64 + 8.0)
.color(color::LIGHT_GRAY)
.set(ids.settings_max_outgoing_established, ui)
{
if state == State::Idle {
match event {
widget::text_box::Event::Enter => {}
widget::text_box::Event::Update(string) => {
self.max_outgoing_established_value = string
}
}
}
}
let label = "established";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.right_from(ids.settings_max_outgoing_established, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_max_outgoing_established_label, ui);
let label = "Own nodes";
let width = text::line::width(label, ui.fonts.get(font_id).unwrap(), text_size as u32);
widget::Text::new(label)
.down_from(ids.settings_max_outgoing_label, 4.0)
.w_h(width + 8.0, text_size as f64 + 8.0)
.font_size(text_size as u32)
.color(color::WHITE)
.set(ids.settings_own_nodes_label, ui);
widget::Canvas::new()
.right_from(ids.settings_own_nodes_label, 2.0)
.w_h(320.0, text_size as f64 + 8.0)
.scroll_kids_vertically()
.color(color::LIGHT_GRAY)
.set(ids.settings_own_nodes_canvas, ui);
if let Some(edit) = widget::TextEdit::new(&self.own_nodes_value)
.top_left_with_margins_on(ids.settings_own_nodes_canvas, 2.0, 2.0)
.padded_w_of(ids.settings_own_nodes_canvas, 2.0)
.parent(ids.settings_own_nodes_canvas)
.restrict_to_height(false)
.font_size(text_size as u32)
.wrap_by_character()
.color(color::BLACK)
.set(ids.settings_own_nodes, ui)
{
if state == State::Idle {
self.own_nodes_value = edit;
}
}
widget::Scrollbar::y_axis(ids.settings_own_nodes_canvas)
.auto_hide(true)
.set(ids.settings_own_nodes_scrollbar, ui);
}
}