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 }