/ bin / app / src / plugin / mod.rs
mod.rs
  1  /* This file is part of DarkFi (https://dark.fi)
  2   *
  3   * Copyright (C) 2020-2025 Dyne.org foundation
  4   *
  5   * This program is free software: you can redistribute it and/or modify
  6   * it under the terms of the GNU Affero General Public License as
  7   * published by the Free Software Foundation, either version 3 of the
  8   * License, or (at your option) any later version.
  9   *
 10   * This program is distributed in the hope that it will be useful,
 11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13   * GNU Affero General Public License for more details.
 14   *
 15   * You should have received a copy of the GNU Affero General Public License
 16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17   */
 18  
 19  use sled_overlay::sled;
 20  use std::{array::TryFromSliceError, string::FromUtf8Error, sync::Arc};
 21  
 22  pub mod darkirc;
 23  #[cfg(feature = "enable-plugins")]
 24  pub use darkirc::DarkIrc;
 25  pub use darkirc::DarkIrcPtr;
 26  
 27  use darkfi::net::Settings as NetSettings;
 28  
 29  use crate::{
 30      prop::{Property, PropertyAtomicGuard, PropertySubType, PropertyType, PropertyValue, Role},
 31      scene::{SceneNode, SceneNodePtr, SceneNodeType},
 32  };
 33  
 34  pub struct PluginSettings {
 35      pub setting_root: SceneNodePtr,
 36      pub sled_tree: sled::Tree,
 37  }
 38  impl PluginSettings {
 39      pub fn add_setting(&self, name: &str, default: PropertyValue) -> Option<SceneNodePtr> {
 40          let atom = &mut PropertyAtomicGuard::none();
 41          let node = match default {
 42              PropertyValue::Bool(b) => {
 43                  let mut node = SceneNode::new(name, SceneNodeType::Setting);
 44                  let prop = Property::new("value", PropertyType::Bool, PropertySubType::Null);
 45                  node.add_property(prop).unwrap();
 46                  let prop = Property::new("default", PropertyType::Bool, PropertySubType::Null);
 47                  node.add_property(prop).unwrap();
 48                  node.set_property_bool(atom, Role::User, "value", b.clone()).unwrap();
 49                  node.set_property_bool(atom, Role::App, "default", b.clone()).unwrap();
 50                  Some(node)
 51              }
 52              PropertyValue::Uint32(u) => {
 53                  let mut node = SceneNode::new(name, SceneNodeType::Setting);
 54                  let prop = Property::new("value", PropertyType::Uint32, PropertySubType::Null);
 55                  node.add_property(prop).unwrap();
 56                  let prop = Property::new("default", PropertyType::Uint32, PropertySubType::Null);
 57                  node.add_property(prop).unwrap();
 58                  node.set_property_u32(atom, Role::User, "value", u.clone()).unwrap();
 59                  node.set_property_u32(atom, Role::App, "default", u.clone()).unwrap();
 60                  Some(node)
 61              }
 62              PropertyValue::Float32(f) => {
 63                  let mut node = SceneNode::new(name, SceneNodeType::Setting);
 64                  let prop = Property::new("value", PropertyType::Float32, PropertySubType::Null);
 65                  node.add_property(prop).unwrap();
 66                  let prop = Property::new("default", PropertyType::Float32, PropertySubType::Null);
 67                  node.add_property(prop).unwrap();
 68                  node.set_property_f32(atom, Role::User, "value", f.clone()).unwrap();
 69                  node.set_property_f32(atom, Role::App, "default", f.clone()).unwrap();
 70                  Some(node)
 71              }
 72              PropertyValue::Str(s) => {
 73                  let mut node = SceneNode::new(name, SceneNodeType::Setting);
 74                  let prop = Property::new("value", PropertyType::Str, PropertySubType::Null);
 75                  node.add_property(prop).unwrap();
 76                  let prop = Property::new("default", PropertyType::Str, PropertySubType::Null);
 77                  node.add_property(prop).unwrap();
 78                  node.set_property_str(atom, Role::User, "value", s.clone()).unwrap();
 79                  node.set_property_str(atom, Role::App, "default", s.clone()).unwrap();
 80                  Some(node)
 81              }
 82              _ => None,
 83          };
 84  
 85          match node {
 86              Some(n) => {
 87                  let node_ptr = Arc::new(n);
 88                  self.setting_root.link(node_ptr.clone().into());
 89                  Some(node_ptr)
 90              }
 91              None => None,
 92          }
 93      }
 94  
 95      // For all settings, copy the value from sled into the setting node's value property
 96      pub fn load_settings(&self) {
 97          let atom = &mut PropertyAtomicGuard::none();
 98          for setting_node in self.setting_root.get_children().iter() {
 99              if setting_node.typ != SceneNodeType::Setting {
100                  continue
101              }
102  
103              let value = setting_node.get_property("value").clone().unwrap();
104              match value.typ {
105                  PropertyType::Bool => {
106                      let sled_result = self.sled_tree.get(setting_node.name.as_str());
107                      if let Ok(Some(sled_value)) = sled_result {
108                          setting_node
109                              .set_property_bool(atom, Role::User, "value", sled_value[0] != 0)
110                              .unwrap();
111                      }
112                  }
113                  PropertyType::Uint32 => {
114                      let sled_result = self.sled_tree.get(setting_node.name.as_str());
115                      if let Ok(Some(sled_value)) = sled_result {
116                          if sled_value.len() == 4 {
117                              let bytes: Result<[u8; 4], TryFromSliceError> =
118                                  sled_value.as_ref().try_into();
119                              if let Ok(b) = bytes {
120                                  setting_node
121                                      .set_property_u32(
122                                          atom,
123                                          Role::User,
124                                          "value",
125                                          u32::from_le_bytes(b),
126                                      )
127                                      .unwrap();
128                              }
129                          }
130                      }
131                  }
132                  PropertyType::Float32 => {
133                      let sled_result = self.sled_tree.get(setting_node.name.as_str());
134                      if let Ok(Some(sled_value)) = sled_result {
135                          if sled_value.len() == 4 {
136                              let bytes: Result<[u8; 4], TryFromSliceError> =
137                                  sled_value.as_ref().try_into();
138                              if let Ok(b) = bytes {
139                                  setting_node
140                                      .set_property_f32(
141                                          atom,
142                                          Role::User,
143                                          "value",
144                                          f32::from_le_bytes(b),
145                                      )
146                                      .unwrap();
147                              }
148                          }
149                      }
150                  }
151                  PropertyType::Str => {
152                      let sled_result = self.sled_tree.get(setting_node.name.as_str());
153                      if let Ok(Some(sled_value)) = sled_result {
154                          let string: Result<String, FromUtf8Error> =
155                              String::from_utf8(sled_value.to_vec());
156                          if let Ok(s) = string {
157                              setting_node.set_property_str(atom, Role::User, "value", s).unwrap();
158                          }
159                      }
160                  }
161                  _ => {}
162              }
163          }
164      }
165  
166      // Save all settings to sled
167      pub fn save_settings(&self) {
168          for setting_node in self.setting_root.get_children().iter() {
169              if setting_node.typ != SceneNodeType::Setting {
170                  continue
171              }
172  
173              let value = setting_node.get_property("value").clone().unwrap();
174              match value.typ {
175                  PropertyType::Bool => {
176                      let value_bytes = if value.get_bool(0).unwrap() { 1u8 } else { 0u8 };
177                      self.sled_tree
178                          .insert(setting_node.name.as_str(), sled::IVec::from(vec![value_bytes]))
179                          .unwrap();
180                  }
181                  PropertyType::Uint32 => {
182                      self.sled_tree
183                          .insert(
184                              setting_node.name.as_str(),
185                              sled::IVec::from(value.get_u32(0).unwrap().to_le_bytes().as_ref()),
186                          )
187                          .unwrap();
188                  }
189                  PropertyType::Float32 => {
190                      self.sled_tree
191                          .insert(
192                              setting_node.name.as_str(),
193                              sled::IVec::from(value.get_f32(0).unwrap().to_le_bytes().as_ref()),
194                          )
195                          .unwrap();
196                  }
197                  PropertyType::Str => {
198                      self.sled_tree
199                          .insert(
200                              setting_node.name.as_str(),
201                              sled::IVec::from(value.get_str(0).unwrap().as_bytes()),
202                          )
203                          .unwrap();
204                  }
205                  _ => {}
206              }
207          }
208      }
209  
210      pub fn get_setting(&self, name: &str) -> Option<SceneNodePtr> {
211          self.setting_root
212              .clone()
213              .get_children()
214              .iter()
215              .find(|node| node.typ == SceneNodeType::Setting && node.name == name)
216              .cloned()
217      }
218  
219      pub fn add_p2p_settings(&self, p2p_settings: &NetSettings) {
220          self.add_setting(
221              "net.outbound_connections",
222              PropertyValue::Uint32(p2p_settings.outbound_connections as u32),
223          );
224          self.add_setting(
225              "net.inbound_connections",
226              PropertyValue::Uint32(p2p_settings.inbound_connections as u32),
227          );
228          self.add_setting(
229              "net.outbound_connect_timeout",
230              PropertyValue::Uint32(p2p_settings.outbound_connect_timeout as u32),
231          );
232          self.add_setting(
233              "net.channel_handshake_timeout",
234              PropertyValue::Uint32(p2p_settings.channel_handshake_timeout as u32),
235          );
236          self.add_setting(
237              "net.channel_heartbeat_interval",
238              PropertyValue::Uint32(p2p_settings.channel_heartbeat_interval as u32),
239          );
240          self.add_setting(
241              "net.outbound_peer_discovery_cooloff_time",
242              PropertyValue::Uint32(p2p_settings.outbound_peer_discovery_cooloff_time as u32),
243          );
244          self.add_setting("net.localnet", PropertyValue::Bool(p2p_settings.localnet));
245          self.add_setting(
246              "net.greylist_refinery_interval",
247              PropertyValue::Uint32(p2p_settings.greylist_refinery_interval as u32),
248          );
249          self.add_setting(
250              "net.white_connect_percent",
251              PropertyValue::Uint32(p2p_settings.white_connect_percent as u32),
252          );
253          self.add_setting(
254              "net.gold_connect_count",
255              PropertyValue::Uint32(p2p_settings.gold_connect_count as u32),
256          );
257          self.add_setting(
258              "net.slot_preference_strict",
259              PropertyValue::Bool(p2p_settings.slot_preference_strict),
260          );
261          self.add_setting(
262              "net.time_with_no_connections",
263              PropertyValue::Uint32(p2p_settings.time_with_no_connections as u32),
264          );
265      }
266  
267      // Update a NetSettings from settings in the node tree
268      pub fn update_p2p_settings(&self, p2p_settings: &mut NetSettings) {
269          p2p_settings.outbound_connections = self
270              .get_setting("net.outbound_connections")
271              .unwrap()
272              .get_property_u32("value")
273              .unwrap() as usize;
274          p2p_settings.inbound_connections =
275              self.get_setting("net.inbound_connections").unwrap().get_property_u32("value").unwrap()
276                  as usize;
277          p2p_settings.outbound_connect_timeout = self
278              .get_setting("net.outbound_connect_timeout")
279              .unwrap()
280              .get_property_u32("value")
281              .unwrap() as u64;
282          p2p_settings.channel_handshake_timeout = self
283              .get_setting("net.channel_handshake_timeout")
284              .unwrap()
285              .get_property_u32("value")
286              .unwrap() as u64;
287          p2p_settings.channel_heartbeat_interval = self
288              .get_setting("net.channel_heartbeat_interval")
289              .unwrap()
290              .get_property_u32("value")
291              .unwrap() as u64;
292          p2p_settings.outbound_peer_discovery_cooloff_time = self
293              .get_setting("net.outbound_peer_discovery_cooloff_time")
294              .unwrap()
295              .get_property_u32("value")
296              .unwrap() as u64;
297          p2p_settings.localnet =
298              self.get_setting("net.localnet").unwrap().get_property_bool("value").unwrap();
299          p2p_settings.greylist_refinery_interval = self
300              .get_setting("net.greylist_refinery_interval")
301              .unwrap()
302              .get_property_u32("value")
303              .unwrap() as u64;
304          p2p_settings.white_connect_percent = self
305              .get_setting("net.white_connect_percent")
306              .unwrap()
307              .get_property_u32("value")
308              .unwrap() as usize;
309          p2p_settings.gold_connect_count =
310              self.get_setting("net.gold_connect_count").unwrap().get_property_u32("value").unwrap()
311                  as usize;
312          p2p_settings.slot_preference_strict = self
313              .get_setting("net.slot_preference_strict")
314              .unwrap()
315              .get_property_bool("value")
316              .unwrap();
317          p2p_settings.time_with_no_connections = self
318              .get_setting("net.time_with_no_connections")
319              .unwrap()
320              .get_property_u32("value")
321              .unwrap() as u64;
322      }
323  }