/ bin / app / src / scene.rs
scene.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 async_channel::{Receiver, Sender};
 20  use async_trait::async_trait;
 21  use darkfi_serial::{FutAsyncWriteExt, SerialDecodable, SerialEncodable};
 22  use futures::{stream::FuturesUnordered, StreamExt};
 23  use std::{
 24      collections::{HashMap, VecDeque},
 25      fmt,
 26      future::Future,
 27      str::FromStr,
 28      sync::{Arc, OnceLock, RwLock as SyncRwLock, Weak},
 29  };
 30  
 31  use crate::{
 32      error::{Error, Result},
 33      plugin,
 34      prop::{Property, PropertyAtomicGuard, PropertyPtr, Role},
 35      pubsub::{Publisher, PublisherPtr, Subscription},
 36      ui,
 37  };
 38  
 39  macro_rules! t { ($($arg:tt)*) => { trace!(target: "scene", $($arg)*); } }
 40  
 41  pub struct ScenePath(VecDeque<String>);
 42  
 43  impl<S: Into<String>> From<S> for ScenePath {
 44      fn from(path: S) -> Self {
 45          let path: String = path.into();
 46          (&path).parse().expect("invalid ScenePath &str")
 47      }
 48  }
 49  
 50  impl fmt::Display for ScenePath {
 51      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 52          write!(f, "/")?;
 53          for token in &self.0 {
 54              write!(f, "{}/", token)?;
 55          }
 56          Ok(())
 57      }
 58  }
 59  
 60  impl FromStr for ScenePath {
 61      type Err = Error;
 62  
 63      fn from_str(s: &str) -> Result<Self> {
 64          if s.is_empty() || s.chars().nth(0).unwrap() != '/' {
 65              return Err(Error::InvalidScenePath)
 66          }
 67          if s == "/" {
 68              return Ok(ScenePath(VecDeque::new()))
 69          }
 70  
 71          let mut tokens = s.split('/');
 72          // Should start with a /
 73          let initial = tokens.next().expect("should not be empty");
 74          if !initial.is_empty() {
 75              return Err(Error::InvalidScenePath)
 76          }
 77  
 78          let mut path = VecDeque::new();
 79          for token in tokens {
 80              // There should not be any double slashes //
 81              if token.is_empty() {
 82                  return Err(Error::InvalidScenePath)
 83              }
 84              path.push_back(token.to_string());
 85          }
 86          Ok(ScenePath(path))
 87      }
 88  }
 89  
 90  pub type SceneNodePtr = Arc<SceneNode>;
 91  pub type SceneNodeWeak = Weak<SceneNode>;
 92  
 93  pub type SceneNodeId = u32;
 94  
 95  #[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
 96  #[repr(u8)]
 97  pub enum SceneNodeType {
 98      Null = 0,
 99      Root = 1,
100      Window = 2,
101      WindowInput = 3,
102      Keyboard = 4,
103      Mouse = 5,
104      Layer = 6,
105      Object = 7,
106      VectorArt = 8,
107      Text = 9,
108      Texture = 10,
109      Fonts = 11,
110      Font = 12,
111      ChatView = 13,
112      Edit = 14,
113      Image = 15,
114      Button = 16,
115      Shortcut = 17,
116      Gesture = 18,
117      EmojiPicker = 19,
118      SettingRoot = 20,
119      Setting = 21,
120      PluginRoot = 100,
121      Plugin = 101,
122  }
123  
124  pub struct SceneNode {
125      pub name: String,
126      pub id: SceneNodeId,
127      pub typ: SceneNodeType,
128      parent: SyncRwLock<Option<Weak<Self>>>,
129      children: SyncRwLock<Vec<SceneNodePtr>>,
130      pub props: Vec<PropertyPtr>,
131      pub sigs: SyncRwLock<Vec<SignalPtr>>,
132      pub methods: Vec<Method>,
133      pub pimpl: OnceLock<Pimpl>,
134  }
135  
136  impl SceneNode {
137      pub fn root() -> SceneNodePtr {
138          Arc::new(Self::new("", SceneNodeType::Root))
139      }
140  
141      pub fn new<S: Into<String>>(name: S, typ: SceneNodeType) -> Self {
142          Self {
143              name: name.into(),
144              id: rand::random(),
145              typ,
146              parent: SyncRwLock::new(None),
147              children: SyncRwLock::new(vec![]),
148              props: vec![],
149              sigs: SyncRwLock::new(vec![]),
150              methods: vec![],
151              pimpl: OnceLock::new(),
152          }
153      }
154  
155      pub async fn setup<F, Fut>(self, pimpl_fn: F) -> Arc<Self>
156      where
157          F: FnOnce(SceneNodeWeak) -> Fut,
158          Fut: Future<Output = Pimpl>,
159      {
160          let self_ = Arc::new(self);
161          let weak_self = Arc::downgrade(&self_);
162  
163          // Initial props
164          for prop in &self_.props {
165              prop.set_parent(weak_self.clone());
166          }
167  
168          let pimpl = pimpl_fn(weak_self).await;
169          assert_eq!(Arc::strong_count(&self_), 1);
170          self_.pimpl.set(pimpl).unwrap();
171          self_
172      }
173  
174      pub fn setup_null(self) -> Arc<Self> {
175          let self_ = Arc::new(self);
176          let weak_self = Arc::downgrade(&self_);
177  
178          // Initial props
179          for prop in &self_.props {
180              prop.set_parent(weak_self.clone());
181          }
182  
183          assert_eq!(Arc::strong_count(&self_), 1);
184          self_.pimpl.set(Pimpl::Null).unwrap();
185          self_
186      }
187  
188      pub fn pimpl<'a>(&'a self) -> &'a Pimpl {
189          self.pimpl.get().unwrap()
190      }
191  
192      pub fn link(self: &Arc<Self>, child: SceneNodePtr) {
193          let mut childs_parent = child.parent.write().unwrap();
194          assert!(childs_parent.is_none());
195          *childs_parent = Some(Arc::downgrade(&self));
196          drop(childs_parent);
197  
198          let mut children = self.children.write().unwrap();
199          children.push(child);
200      }
201  
202      pub fn get_children(&self) -> Vec<SceneNodePtr> {
203          self.children.read().unwrap().clone()
204      }
205  
206      pub fn lookup_node<P: Into<ScenePath>>(self: &Arc<Self>, path: P) -> Option<SceneNodePtr> {
207          let path: ScenePath = path.into();
208          let mut path = path.0;
209          if path.is_empty() {
210              return Some(self.clone())
211          }
212          let child_name = path.pop_front().unwrap();
213          for child in self.get_children() {
214              if child.name == child_name {
215                  let path = ScenePath(path);
216                  return child.lookup_node(path)
217              }
218          }
219          None
220      }
221  
222      fn has_property(&self, name: &str) -> bool {
223          self.props.iter().any(|prop| prop.name == name)
224      }
225      pub fn add_property(&mut self, prop: Property) -> Result<()> {
226          if self.has_property(&prop.name) {
227              return Err(Error::PropertyAlreadyExists)
228          }
229          self.props.push(Arc::new(prop));
230          Ok(())
231      }
232  
233      pub fn get_property(&self, name: &str) -> Option<PropertyPtr> {
234          self.props.iter().find(|prop| prop.name == name).map(|prop| prop.clone())
235      }
236  
237      // Convenience methods
238      pub fn get_property_bool(&self, name: &str) -> Result<bool> {
239          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_bool(0)
240      }
241      pub fn get_property_u32(&self, name: &str) -> Result<u32> {
242          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_u32(0)
243      }
244      pub fn get_property_f32(&self, name: &str) -> Result<f32> {
245          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_f32(0)
246      }
247      pub fn get_property_str(&self, name: &str) -> Result<String> {
248          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_str(0)
249      }
250      pub fn get_property_enum(&self, name: &str) -> Result<String> {
251          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_enum(0)
252      }
253      pub fn get_property_node_id(&self, name: &str) -> Result<SceneNodeId> {
254          self.get_property(name).ok_or(Error::PropertyNotFound)?.get_node_id(0)
255      }
256      // Setters
257      pub fn set_property_bool(
258          &self,
259          atom: &mut PropertyAtomicGuard,
260          role: Role,
261          name: &str,
262          val: bool,
263      ) -> Result<()> {
264          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_bool(atom, role, 0, val)
265      }
266      pub fn set_property_u32(
267          &self,
268          atom: &mut PropertyAtomicGuard,
269          role: Role,
270          name: &str,
271          val: u32,
272      ) -> Result<()> {
273          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_u32(atom, role, 0, val)
274      }
275      pub fn set_property_f32(
276          &self,
277          atom: &mut PropertyAtomicGuard,
278          role: Role,
279          name: &str,
280          val: f32,
281      ) -> Result<()> {
282          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_f32(atom, role, 0, val)
283      }
284      pub fn set_property_str<S: Into<String>>(
285          &self,
286          atom: &mut PropertyAtomicGuard,
287          role: Role,
288          name: &str,
289          val: S,
290      ) -> Result<()> {
291          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_str(atom, role, 0, val)
292      }
293      pub fn set_property_node_id(
294          &self,
295          atom: &mut PropertyAtomicGuard,
296          role: Role,
297          name: &str,
298          val: SceneNodeId,
299      ) -> Result<()> {
300          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_node_id(atom, role, 0, val)
301      }
302  
303      pub fn set_property_f32_vec(
304          &self,
305          atom: &mut PropertyAtomicGuard,
306          role: Role,
307          name: &str,
308          val: Vec<f32>,
309      ) -> Result<()> {
310          self.get_property(name).ok_or(Error::PropertyNotFound)?.set_f32_vec(atom, role, val)
311      }
312  
313      pub fn add_signal<S: Into<String>>(
314          &mut self,
315          name: S,
316          desc: S,
317          fmt: Vec<(S, S, CallArgType)>,
318      ) -> Result<()> {
319          let name = name.into();
320          if self.has_signal(&name) {
321              return Err(Error::SignalAlreadyExists)
322          }
323          let fmt = fmt
324              .into_iter()
325              .map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
326              .collect();
327          let mut sigs = self.sigs.write().unwrap();
328          sigs.push(Arc::new(Signal {
329              name: name.into(),
330              desc: desc.into(),
331              fmt,
332              slots: SyncRwLock::new(HashMap::new()),
333          }));
334          Ok(())
335      }
336  
337      fn has_signal(&self, name: &str) -> bool {
338          let sigs = self.sigs.read().unwrap();
339          sigs.iter().any(|sig| sig.name == name)
340      }
341      pub fn get_signal(&self, name: &str) -> Option<SignalPtr> {
342          let sigs = self.sigs.read().unwrap();
343          sigs.iter().find(|sig| sig.name == name).cloned()
344      }
345  
346      pub fn register(&self, sig_name: &str, slot: Slot) -> Result<SlotId> {
347          let slot_id = rand::random();
348          let sig = self.get_signal(sig_name).ok_or(Error::SignalNotFound)?;
349          let mut slots = sig.slots.write().unwrap();
350          slots.insert(slot_id, slot);
351          Ok(slot_id)
352      }
353      pub fn unregister(&self, sig_name: &str, slot_id: SlotId) -> Result<()> {
354          let sig = self.get_signal(sig_name).ok_or(Error::SignalNotFound)?;
355          let mut slots = sig.slots.write().unwrap();
356          slots.remove(&slot_id).ok_or(Error::SlotNotFound)?;
357          Ok(())
358      }
359  
360      pub async fn trigger(&self, sig_name: &str, data: Vec<u8>) -> Result<()> {
361          t!("trigger({sig_name}, {data:?}) [node={self:?}]");
362          let sig = self.get_signal(sig_name).ok_or(Error::SignalNotFound)?;
363          let futures = FuturesUnordered::new();
364          let slots: Vec<_> = sig.slots.read().unwrap().values().cloned().collect();
365          // TODO: autoremove failed slots
366          for slot in slots {
367              t!("  triggering {}", slot.name);
368              // Trigger the slot
369              let data = data.clone();
370              futures.push(async move { slot.notify.send(data).await.is_ok() });
371          }
372          let success: Vec<_> = futures.collect().await;
373          t!("trigger success: {success:?}");
374          Ok(())
375      }
376  
377      pub fn add_method<S: Into<String>>(
378          &mut self,
379          name: S,
380          args: Vec<(S, S, CallArgType)>,
381          result: Option<Vec<(S, S, CallArgType)>>,
382      ) -> Result<()> {
383          let name = name.into();
384          if self.has_method(&name) {
385              return Err(Error::MethodAlreadyExists)
386          }
387          let args = args
388              .into_iter()
389              .map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
390              .collect();
391          let result = match result {
392              Some(result) => Some(
393                  result
394                      .into_iter()
395                      .map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
396                      .collect(),
397              ),
398              None => None,
399          };
400          self.methods.push(Method::new(name.into(), args, result));
401          Ok(())
402      }
403  
404      fn has_method(&self, name: &str) -> bool {
405          self.methods.iter().any(|sig| sig.name == name)
406      }
407  
408      pub fn get_method(&self, name: &str) -> Option<&Method> {
409          self.methods.iter().find(|method| method.name == name)
410      }
411  
412      pub async fn call_method(&self, name: &str, arg_data: CallData) -> Result<Option<CallData>> {
413          let method = self.get_method(name).ok_or(Error::MethodNotFound)?;
414          Ok(method.call(arg_data).await)
415      }
416  
417      pub fn subscribe_method_call(&self, name: &str) -> Result<MethodCallSub> {
418          let method = self.get_method(name).ok_or(Error::MethodNotFound)?;
419          let method_sub = method.pubsub.clone().subscribe();
420          Ok(method_sub)
421      }
422  
423      pub fn get_full_path(&self) -> Option<String> {
424          let subpath = "/".to_string() + &self.name;
425          let Some(parent_weak) = self.parent.read().unwrap().clone() else { return Some(subpath) };
426          let Some(parent) = parent_weak.upgrade() else { return None };
427  
428          // Handle root /
429          if parent.typ == SceneNodeType::Root {
430              return Some(subpath)
431          }
432  
433          Some(parent.get_full_path()? + &subpath)
434      }
435  }
436  
437  impl std::fmt::Debug for SceneNode {
438      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
439          if let Some(path) = self.get_full_path() {
440              write!(f, "{path}")
441          } else {
442              write!(f, "{}:{}", self.name, self.id)
443          }
444      }
445  }
446  
447  #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
448  pub enum CallArgType {
449      Uint32,
450      Uint64,
451      Float32,
452      Bool,
453      Str,
454      Hash,
455  }
456  
457  #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
458  pub struct CallArg {
459      pub name: String,
460      pub desc: String,
461      pub typ: CallArgType,
462  }
463  
464  pub type CallData = Vec<u8>;
465  
466  pub type SlotId = u32;
467  
468  #[derive(Clone)]
469  pub struct Slot {
470      pub name: String,
471      pub notify: Sender<CallData>,
472  }
473  
474  impl Slot {
475      pub fn new<S: Into<String>>(name: S) -> (Self, Receiver<CallData>) {
476          let (notify, recvr) = async_channel::unbounded();
477          let self_ = Self { name: name.into(), notify };
478          (self_, recvr)
479      }
480  }
481  
482  type SignalPtr = Arc<Signal>;
483  
484  pub struct Signal {
485      pub name: String,
486      #[allow(dead_code)]
487      pub desc: String,
488      #[allow(dead_code)]
489      pub fmt: Vec<CallArg>,
490      slots: SyncRwLock<HashMap<SlotId, Slot>>,
491  }
492  
493  #[derive(Clone, Debug)]
494  pub struct MethodCall {
495      pub data: CallData,
496      pub send_res: Option<Sender<CallData>>,
497  }
498  
499  impl MethodCall {
500      fn new(data: CallData, send_res: Option<Sender<CallData>>) -> Self {
501          Self { data, send_res }
502      }
503  }
504  
505  pub type MethodCallSub = Subscription<MethodCall>;
506  
507  pub struct Method {
508      pub name: String,
509      pub args: Vec<CallArg>,
510      pub result: Option<Vec<CallArg>>,
511      pub pubsub: PublisherPtr<MethodCall>,
512  }
513  
514  impl Method {
515      fn new(name: String, args: Vec<CallArg>, result: Option<Vec<CallArg>>) -> Self {
516          Self { name, args, result, pubsub: Publisher::new() }
517      }
518  
519      async fn call(&self, data: CallData) -> Option<CallData> {
520          match &self.result {
521              Some(_) => {
522                  let (send_res, recv_res) = async_channel::bounded(1);
523                  self.pubsub.notify(MethodCall::new(data, Some(send_res)));
524                  Some(recv_res.recv().await.unwrap())
525              }
526              None => {
527                  self.pubsub.notify(MethodCall::new(data, None));
528                  None
529              }
530          }
531      }
532  }
533  
534  pub enum Pimpl {
535      Null,
536      Window(ui::WindowPtr),
537      Layer(ui::LayerPtr),
538      VectorArt(ui::VectorArtPtr),
539      Text(ui::TextPtr),
540      Edit(ui::BaseEditPtr),
541      ChatView(ui::ChatViewPtr),
542      Image(ui::ImagePtr),
543      Video(ui::VideoPtr),
544      Button(ui::ButtonPtr),
545      Shortcut(ui::ShortcutPtr),
546      Gesture(ui::GesturePtr),
547      EmojiPicker(ui::EmojiPickerPtr),
548      DarkIrc(plugin::DarkIrcPtr),
549  }
550  
551  impl std::fmt::Debug for Pimpl {
552      fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
553          write!(f, "Pimpl")
554      }
555  }