/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2026 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use sled_overlay::sled; use std::{array::TryFromSliceError, string::FromUtf8Error, sync::Arc}; #[cfg(feature = "enable-plugin-darkirc")] pub mod darkirc; #[cfg(feature = "enable-plugin-darkirc")] pub use darkirc::DarkIrcPtr; #[cfg(feature = "enable-plugin-fud")] pub mod fud; #[cfg(feature = "enable-plugin-fud")] pub use fud::FudPluginPtr as FudPtr; #[cfg(feature = "enable-plugin-drk")] pub mod drk; #[cfg(feature = "enable-plugin-drk")] pub use drk::DrkPluginPtr as DrkPtr; #[cfg(feature = "enable-plugin-darkirc")] pub use darkirc::DarkIrc; #[cfg(feature = "enable-plugin-drk")] pub use drk::DrkPlugin; #[cfg(feature = "enable-plugin-fud")] pub use fud::FudPlugin; #[cfg(any(feature = "enable-plugin-darkirc", feature = "enable-plugin-fud"))] use darkfi::net::Settings as NetSettings; #[cfg(any(feature = "enable-plugin-darkirc", feature = "enable-plugin-fud"))] use crate::{ prop::{Property, PropertyAtomicGuard, PropertySubType, PropertyType, PropertyValue, Role}, scene::{SceneNode, SceneNodePtr, SceneNodeType}, }; #[cfg(any(feature = "enable-plugin-darkirc", feature = "enable-plugin-fud"))] pub struct PluginSettings { pub setting_root: SceneNodePtr, pub sled_tree: sled::Tree, } #[cfg(any(feature = "enable-plugin-darkirc", feature = "enable-plugin-fud"))] impl PluginSettings { pub fn add_setting(&self, name: &str, default: PropertyValue) -> Option { let atom = &mut PropertyAtomicGuard::none(); let node = match default { PropertyValue::Bool(b) => { let mut node = SceneNode::new(name, SceneNodeType::Setting); let prop = Property::new("value", PropertyType::Bool, PropertySubType::Null); node.add_property(prop).unwrap(); let prop = Property::new("default", PropertyType::Bool, PropertySubType::Null); node.add_property(prop).unwrap(); node.set_property_bool(atom, Role::User, "value", b.clone()).unwrap(); node.set_property_bool(atom, Role::App, "default", b.clone()).unwrap(); Some(node) } PropertyValue::Uint32(u) => { let mut node = SceneNode::new(name, SceneNodeType::Setting); let prop = Property::new("value", PropertyType::Uint32, PropertySubType::Null); node.add_property(prop).unwrap(); let prop = Property::new("default", PropertyType::Uint32, PropertySubType::Null); node.add_property(prop).unwrap(); node.set_property_u32(atom, Role::User, "value", u.clone()).unwrap(); node.set_property_u32(atom, Role::App, "default", u.clone()).unwrap(); Some(node) } PropertyValue::Float32(f) => { let mut node = SceneNode::new(name, SceneNodeType::Setting); let prop = Property::new("value", PropertyType::Float32, PropertySubType::Null); node.add_property(prop).unwrap(); let prop = Property::new("default", PropertyType::Float32, PropertySubType::Null); node.add_property(prop).unwrap(); node.set_property_f32(atom, Role::User, "value", f.clone()).unwrap(); node.set_property_f32(atom, Role::App, "default", f.clone()).unwrap(); Some(node) } PropertyValue::Str(s) => { let mut node = SceneNode::new(name, SceneNodeType::Setting); let prop = Property::new("value", PropertyType::Str, PropertySubType::Null); node.add_property(prop).unwrap(); let prop = Property::new("default", PropertyType::Str, PropertySubType::Null); node.add_property(prop).unwrap(); node.set_property_str(atom, Role::User, "value", s.clone()).unwrap(); node.set_property_str(atom, Role::App, "default", s.clone()).unwrap(); Some(node) } _ => None, }; match node { Some(n) => { let node_ptr = Arc::new(n); self.setting_root.link(node_ptr.clone().into()); Some(node_ptr) } None => None, } } // For all settings, copy the value from sled into the setting node's value property pub fn load_settings(&self) { let atom = &mut PropertyAtomicGuard::none(); for setting_node in self.setting_root.get_children().iter() { if setting_node.typ != SceneNodeType::Setting { continue } let value = setting_node.get_property("value").clone().unwrap(); match value.typ { PropertyType::Bool => { let sled_result = self.sled_tree.get(setting_node.name.as_str()); if let Ok(Some(sled_value)) = sled_result { setting_node .set_property_bool(atom, Role::User, "value", sled_value[0] != 0) .unwrap(); } } PropertyType::Uint32 => { let sled_result = self.sled_tree.get(setting_node.name.as_str()); if let Ok(Some(sled_value)) = sled_result { if sled_value.len() == 4 { let bytes: Result<[u8; 4], TryFromSliceError> = sled_value.as_ref().try_into(); if let Ok(b) = bytes { setting_node .set_property_u32( atom, Role::User, "value", u32::from_le_bytes(b), ) .unwrap(); } } } } PropertyType::Float32 => { let sled_result = self.sled_tree.get(setting_node.name.as_str()); if let Ok(Some(sled_value)) = sled_result { if sled_value.len() == 4 { let bytes: Result<[u8; 4], TryFromSliceError> = sled_value.as_ref().try_into(); if let Ok(b) = bytes { setting_node .set_property_f32( atom, Role::User, "value", f32::from_le_bytes(b), ) .unwrap(); } } } } PropertyType::Str => { let sled_result = self.sled_tree.get(setting_node.name.as_str()); if let Ok(Some(sled_value)) = sled_result { let string: Result = String::from_utf8(sled_value.to_vec()); if let Ok(s) = string { setting_node.set_property_str(atom, Role::User, "value", s).unwrap(); } } } _ => {} } } } // Save all settings to sled pub fn save_settings(&self) { for setting_node in self.setting_root.get_children().iter() { if setting_node.typ != SceneNodeType::Setting { continue } let value = setting_node.get_property("value").clone().unwrap(); match value.typ { PropertyType::Bool => { let value_bytes = if value.get_bool(0).unwrap() { 1u8 } else { 0u8 }; self.sled_tree .insert(setting_node.name.as_str(), sled::IVec::from(vec![value_bytes])) .unwrap(); } PropertyType::Uint32 => { self.sled_tree .insert( setting_node.name.as_str(), sled::IVec::from(value.get_u32(0).unwrap().to_le_bytes().as_ref()), ) .unwrap(); } PropertyType::Float32 => { self.sled_tree .insert( setting_node.name.as_str(), sled::IVec::from(value.get_f32(0).unwrap().to_le_bytes().as_ref()), ) .unwrap(); } PropertyType::Str => { self.sled_tree .insert( setting_node.name.as_str(), sled::IVec::from(value.get_str(0).unwrap().as_bytes()), ) .unwrap(); } _ => {} } } } pub fn get_setting(&self, name: &str) -> Option { self.setting_root .clone() .get_children() .iter() .find(|node| node.typ == SceneNodeType::Setting && node.name == name) .cloned() } pub fn add_p2p_settings(&self, p2p_settings: &NetSettings) { self.add_setting( "net.outbound_connections", PropertyValue::Uint32(p2p_settings.outbound_connections as u32), ); self.add_setting( "net.inbound_connections", PropertyValue::Uint32(p2p_settings.inbound_connections as u32), ); //TODO: Update this when multiple active_profiles at a time is supported self.add_setting( "net.outbound_connect_timeout", PropertyValue::Uint32( p2p_settings .outbound_connect_timeout(&p2p_settings.active_profiles.first().unwrap()) as u32, ), ); self.add_setting( "net.channel_handshake_timeout", PropertyValue::Uint32( p2p_settings .channel_handshake_timeout(&p2p_settings.active_profiles.first().unwrap()) as u32, ), ); self.add_setting( "net.channel_heartbeat_interval", PropertyValue::Uint32( p2p_settings .channel_heartbeat_interval(&p2p_settings.active_profiles.first().unwrap()) as u32, ), ); self.add_setting( "net.outbound_peer_discovery_cooloff_time", PropertyValue::Uint32(p2p_settings.outbound_peer_discovery_cooloff_time as u32), ); self.add_setting("net.localnet", PropertyValue::Bool(p2p_settings.localnet)); self.add_setting( "net.greylist_refinery_interval", PropertyValue::Uint32(p2p_settings.greylist_refinery_interval as u32), ); self.add_setting( "net.time_with_no_connections", PropertyValue::Uint32(p2p_settings.time_with_no_connections as u32), ); } // Update a NetSettings from settings in the node tree pub fn update_p2p_settings(&self, p2p_settings: &mut NetSettings) { p2p_settings.outbound_connections = self .get_setting("net.outbound_connections") .unwrap() .get_property_u32("value") .unwrap() as usize; p2p_settings.inbound_connections = self.get_setting("net.inbound_connections").unwrap().get_property_u32("value").unwrap() as usize; //TODO: Update this when multiple active_profiles at a time is supported if let Some(profile) = p2p_settings.profiles.get_mut(p2p_settings.active_profiles.first().unwrap()) { profile.outbound_connect_timeout = self .get_setting("net.outbound_connect_timeout") .unwrap() .get_property_u32("value") .unwrap() as u64; profile.channel_handshake_timeout = self .get_setting("net.channel_handshake_timeout") .unwrap() .get_property_u32("value") .unwrap() as u64; profile.channel_heartbeat_interval = self .get_setting("net.channel_heartbeat_interval") .unwrap() .get_property_u32("value") .unwrap() as u64; } p2p_settings.outbound_peer_discovery_cooloff_time = self .get_setting("net.outbound_peer_discovery_cooloff_time") .unwrap() .get_property_u32("value") .unwrap() as u64; p2p_settings.localnet = self.get_setting("net.localnet").unwrap().get_property_bool("value").unwrap(); p2p_settings.greylist_refinery_interval = self .get_setting("net.greylist_refinery_interval") .unwrap() .get_property_u32("value") .unwrap() as u64; p2p_settings.time_with_no_connections = self .get_setting("net.time_with_no_connections") .unwrap() .get_property_u32("value") .unwrap() as u64; } }