this repo has no description

RUNTIME WORKS FUCK YEA

phaz.uk 9a7bb29c f9016d75

verified
+1
src-tauri/Cargo.lock
··· 7 7 version = "0.1.0" 8 8 dependencies = [ 9 9 "anyhow", 10 + "crossbeam-channel", 10 11 "dirs", 11 12 "flate2", 12 13 "serde",
+1
src-tauri/Cargo.toml
··· 27 27 anyhow = "1.0.99" 28 28 flate2 = "1.1.2" 29 29 tauri-plugin-dialog = "2" 30 + crossbeam-channel = "0.5.15" 30 31
+3 -3
src-tauri/src/frontend_calls/sync_tab.rs
··· 1 - use std::sync::mpsc::Sender; 1 + use crossbeam_channel::Sender; 2 2 3 3 use tauri::State; 4 4 5 5 use crate::{ runtime::commands::RuntimeCommand, structs::nodes::Node }; 6 6 7 7 #[tauri::command] 8 - pub fn sync_tab( graph: Vec<Node>, id: String, cmd: State<Sender<RuntimeCommand>> ) { 8 + pub fn sync_tab( graph: Vec<Node>, id: String, cmd: State<Sender<RuntimeCommand>> ){ 9 9 cmd.send(RuntimeCommand::AddTab(graph, id)).unwrap(); 10 10 } 11 11 12 12 #[tauri::command] 13 - pub fn discard_tab( id: String, cmd: State<Sender<RuntimeCommand>> ) { 13 + pub fn discard_tab( id: String, cmd: State<Sender<RuntimeCommand>> ){ 14 14 cmd.send(RuntimeCommand::RemoveTab(id)).unwrap(); 15 15 }
+5 -3
src-tauri/src/lib.rs
··· 1 - use std::{collections::HashMap, fs, sync::{self, Arc, Mutex}}; 1 + use std::{ fs, sync::Mutex }; 2 + use crossbeam_channel::bounded; 3 + use tokio::sync; 2 4 3 5 use frontend_calls::*; 4 6 5 - use crate::{ osc::OSCMessage, runtime::nodes::RuntimeNodeTree, setup::setup, utils::config::Config }; 7 + use crate::{ osc::OSCMessage, setup::setup, utils::config::Config }; 6 8 7 9 mod frontend_calls; 8 10 mod osc; ··· 34 36 35 37 static ADDRESSES: Mutex<Vec<OSCMessage>> = Mutex::new(Vec::new()); 36 38 37 - let ( runtime_sender, runtime_receiver ) = sync::mpsc::channel(); 39 + let ( runtime_sender, runtime_receiver ) = bounded(1024); 38 40 39 41 tauri::Builder::default() 40 42 .plugin(tauri_plugin_dialog::init())
+2 -2
src-tauri/src/osc.rs
··· 1 1 // https://gist.github.com/phaze-the-dumb/634daacb5141eae2f846e20987dba7a8 2 - 3 - use std::{net::UdpSocket, sync::mpsc::Sender}; 2 + use std::net::UdpSocket; 4 3 4 + use crossbeam_channel::Sender; 5 5 use serde::Serialize; 6 6 7 7 use crate::structs::parameter_types::ParameterType;
+21 -24
src-tauri/src/runtime.rs
··· 7 7 8 8 // This is horrible. I know, I'm sorry. 9 9 10 - pub fn runtime_dry( entry: String, parameters: &Vec<ParameterType>, tab: &RuntimeNodeTree ) -> Result<()>{ 11 - let node = tab.nodes.get(&entry); 10 + pub fn runtime_dry( entry: String, parameters: &Vec<ParameterType>, tab: &mut RuntimeNodeTree ) -> Result<()>{ 11 + let node = tab.nodes.get_mut(&entry); 12 12 if node.is_none(){ bail!("Cannot find node"); } 13 13 14 - let mut node = node.unwrap().lock().unwrap(); 14 + let node = node.unwrap(); 15 15 16 16 let output_map = node.outputs(); 17 17 let args = node.execute_dry(parameters); 18 18 19 - drop(node); 20 - 21 19 if args.is_some(){ 22 20 let args = args.unwrap(); 23 21 ··· 27 25 for output in &output_map[i]{ 28 26 if output.2 == 5{ break; } // Ignore flow outputs 29 27 30 - let next_node = tab.nodes.get(&output.0); 28 + let next_node = tab.nodes.get_mut(&output.0); 31 29 if next_node.is_none(){ bail!("Cannot find node {}", output.0) } 32 30 33 - let mut next_node = next_node.unwrap().lock().unwrap(); 31 + let next_node = next_node.unwrap(); 34 32 let can_update = next_node.update_arg(output.1 as usize, arg.clone()); 35 33 36 34 if can_update{ 37 - drop(next_node); 38 - // ^^ Drop this MutexGuard before we enter the runtime, 39 - // as it blocks the runtime for gaining a lock on the node 40 - // TODO: Please find a better way of making it mutable 41 - 42 - runtime_dry(output.0.clone(), &vec![], &tab)?; 35 + runtime_dry(output.0.clone(), &vec![], tab)?; 43 36 } 44 37 } 45 38 } ··· 48 41 Ok(()) 49 42 } 50 43 51 - 52 - pub fn runtime( entry: String, tab: &RuntimeNodeTree ) -> Result<()>{ 53 - let node = tab.nodes.get(&entry); 44 + pub fn runtime( entry: String, tab: &mut RuntimeNodeTree ) -> Result<()>{ 45 + let node = tab.nodes.get_mut(&entry); 54 46 if node.is_none(){ bail!("Cannot find node"); } 55 47 56 - let mut node = node.unwrap().lock().unwrap(); 48 + let node = node.unwrap(); 57 49 58 50 let next = node.execute(); 59 - if next{ 51 + if next.is_some(){ 52 + let next = next.unwrap(); 53 + 60 54 let outputs = node.outputs(); 61 55 62 - drop(node); 56 + for i in 0..next.len(){ 57 + let arg = &next[i]; 58 + if i >= outputs.len() { break; } 63 59 64 - for outputs in outputs{ 65 - for output in outputs{ 66 - if output.2 == 5{ 67 - // This is a flow output, continue 68 - runtime(output.0, &tab)?; 60 + for output in &outputs[i]{ 61 + if let ParameterType::Flow(next) = arg{ 62 + if *next{ 63 + // This is a flow output, continue 64 + runtime(output.0.clone(), tab)?; 65 + } 69 66 } 70 67 } 71 68 }
+1
src-tauri/src/runtime/commands.rs
··· 1 1 use crate::{ osc::OSCMessage, structs::nodes::Node }; 2 2 3 + #[derive(Debug)] 3 4 pub enum RuntimeCommand{ 4 5 OSCMessage(OSCMessage), 5 6
+20 -7
src-tauri/src/runtime/nodes.rs
··· 1 - use std::{collections::HashMap, sync::Mutex}; 1 + use std::collections::HashMap; 2 2 3 - use crate::{ runtime::nodes::{ debug::Debug, osctrigger::OSCTrigger }, structs::{ nodes::Node, parameter_types::ParameterType } }; 3 + use crate::{ runtime::nodes::{ conditional::{ ifequal::ConditionalIfEqual, iffalse::ConditionalIfFalse, iftrue::ConditionalIfTrue }, debug::Debug, osctrigger::OSCTrigger, statics::{ float::StaticFloat, int::StaticInt, string::StaticString } }, structs::{ nodes::Node, parameter_types::ParameterType } }; 4 4 5 5 mod osctrigger; 6 6 mod debug; 7 + mod statics; 8 + mod conditional; 7 9 8 10 pub struct RuntimeNodeTree{ 9 - pub nodes: HashMap<String, Mutex<Box<dyn RuntimeNode>>> 11 + pub nodes: HashMap<String, Box<dyn RuntimeNode>> 10 12 } 11 13 14 + unsafe impl Send for RuntimeNodeTree{} 15 + 12 16 impl RuntimeNodeTree{ 13 17 pub fn from( tree: Vec<Node> ) -> Self{ 14 - let mut runtime_nodes: HashMap<String, Mutex<Box<dyn RuntimeNode>>> = HashMap::new(); 18 + let mut runtime_nodes: HashMap<String, Box<dyn RuntimeNode>> = HashMap::new(); 15 19 for node in tree{ 16 20 match node.type_id.as_str(){ 17 - "osctrigger" => { runtime_nodes.insert(node.id.clone(), Mutex::new(OSCTrigger::new(node))); } 18 - "debug" => { runtime_nodes.insert(node.id.clone(), Mutex::new(Debug::new(node))); } 21 + "osctrigger" => { runtime_nodes.insert(node.id.clone(), OSCTrigger::new(node)); } 22 + 23 + "staticstring" => { runtime_nodes.insert(node.id.clone(), StaticString::new(node)); } 24 + "staticint" => { runtime_nodes.insert(node.id.clone(), StaticInt::new(node)); } 25 + "staticfloat" => { runtime_nodes.insert(node.id.clone(), StaticFloat::new(node)); } 26 + 27 + "iftrue" => { runtime_nodes.insert(node.id.clone(), ConditionalIfTrue::new(node)); } 28 + "iffalse" => { runtime_nodes.insert(node.id.clone(), ConditionalIfFalse::new(node)); } 29 + "ifequal" => { runtime_nodes.insert(node.id.clone(), ConditionalIfEqual::new(node)); } 30 + 31 + "debug" => { runtime_nodes.insert(node.id.clone(), Debug::new(node)); } 19 32 _ => {} 20 33 } 21 34 } ··· 27 40 pub trait RuntimeNode{ 28 41 fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>>; // Node ID, input index, output value type 29 42 fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>>; // Only update values on the first loop through 30 - fn execute( &mut self ) -> bool; // Then call functions on the second loop 43 + fn execute( &mut self ) -> Option<Vec<ParameterType>>; // Then call functions on the second loop 31 44 fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool; 32 45 fn is_entrypoint( &self ) -> bool; 33 46 }
+52
src-tauri/src/runtime/nodes/conditional/ifequal.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct ConditionalIfEqual{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + value1: ParameterType, 6 + value2: ParameterType 7 + } 8 + 9 + impl ConditionalIfEqual{ 10 + pub fn new( node: Node ) -> Box<Self>{ 11 + dbg!(&node); 12 + 13 + Box::new(Self { 14 + outputs: node.outputs.iter() 15 + .map(| x | { 16 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 17 + }).collect(), 18 + value1: ParameterType::None, 19 + value2: ParameterType::None, 20 + }) 21 + } 22 + } 23 + 24 + impl RuntimeNode for ConditionalIfEqual{ 25 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 26 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 27 + 28 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { 29 + if self.value1 == ParameterType::None && self.value2 == ParameterType::None{ 30 + None 31 + } else{ 32 + let equal = self.value1 == self.value2; 33 + Some(vec![ ParameterType::Flow(equal), ParameterType::Flow(!equal) ]) 34 + } 35 + } 36 + 37 + fn update_arg( &mut self, index: usize, arg: ParameterType ) -> bool { 38 + match index{ 39 + 1 => { 40 + self.value1 = arg; 41 + } 42 + 2 => { 43 + self.value2 = arg; 44 + } 45 + _ => {} 46 + } 47 + 48 + false 49 + } 50 + 51 + fn is_entrypoint( &self ) -> bool { false } 52 + }
+46
src-tauri/src/runtime/nodes/conditional/iffalse.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct ConditionalIfFalse{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + runtime_active: bool 6 + } 7 + 8 + impl ConditionalIfFalse{ 9 + pub fn new( node: Node ) -> Box<Self>{ 10 + dbg!(&node); 11 + 12 + Box::new(Self { 13 + outputs: node.outputs.iter() 14 + .map(| x | { 15 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 16 + }).collect(), 17 + runtime_active: false 18 + }) 19 + } 20 + } 21 + 22 + impl RuntimeNode for ConditionalIfFalse{ 23 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 24 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 25 + 26 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { 27 + Some(vec![ ParameterType::Flow(!self.runtime_active), ParameterType::Flow(self.runtime_active) ]) 28 + } 29 + 30 + fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool { 31 + if let ParameterType::Boolean(boolean) = arg{ 32 + if boolean{ 33 + self.runtime_active = true; 34 + true 35 + } else{ 36 + self.runtime_active = false; 37 + false 38 + } 39 + } else{ 40 + self.runtime_active = false; 41 + false 42 + } 43 + } 44 + 45 + fn is_entrypoint( &self ) -> bool { false } 46 + }
+46
src-tauri/src/runtime/nodes/conditional/iftrue.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct ConditionalIfTrue{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + runtime_active: bool 6 + } 7 + 8 + impl ConditionalIfTrue{ 9 + pub fn new( node: Node ) -> Box<Self>{ 10 + dbg!(&node); 11 + 12 + Box::new(Self { 13 + outputs: node.outputs.iter() 14 + .map(| x | { 15 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 16 + }).collect(), 17 + runtime_active: false 18 + }) 19 + } 20 + } 21 + 22 + impl RuntimeNode for ConditionalIfTrue{ 23 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { self.outputs.clone() } 24 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 25 + 26 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { 27 + Some(vec![ ParameterType::Flow(self.runtime_active), ParameterType::Flow(!self.runtime_active) ]) 28 + } 29 + 30 + fn update_arg( &mut self, _: usize, arg: ParameterType ) -> bool { 31 + if let ParameterType::Boolean(boolean) = arg{ 32 + if boolean{ 33 + self.runtime_active = true; 34 + true 35 + } else{ 36 + self.runtime_active = false; 37 + false 38 + } 39 + } else{ 40 + self.runtime_active = false; 41 + false 42 + } 43 + } 44 + 45 + fn is_entrypoint( &self ) -> bool { false } 46 + }
+3
src-tauri/src/runtime/nodes/conditional/mod.rs
··· 1 + pub mod iftrue; 2 + pub mod iffalse; 3 + pub mod ifequal;
+3 -3
src-tauri/src/runtime/nodes/debug.rs
··· 5 5 } 6 6 7 7 impl Debug{ 8 - pub fn new( node: Node ) -> Box<Self>{ 8 + pub fn new( _: Node ) -> Box<Self>{ 9 9 Box::new(Self { to_log: None }) 10 10 } 11 11 } ··· 14 14 fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { vec![] } 15 15 fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { Some(vec![]) } 16 16 17 - fn execute( &mut self ) -> bool { 17 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { 18 18 dbg!(&self.to_log); 19 19 self.to_log = None; 20 20 21 - false 21 + None 22 22 } 23 23 24 24 fn update_arg( &mut self, index: usize, value: ParameterType ) -> bool {
+12 -5
src-tauri/src/runtime/nodes/osctrigger.rs
··· 2 2 3 3 pub struct OSCTrigger{ 4 4 outputs: Vec<Vec<( String, isize, isize )>>, 5 - address: String, 5 + address: Option<String>, 6 6 runtime_active: bool 7 7 } 8 8 ··· 10 10 pub fn new( node: Node ) -> Box<Self>{ 11 11 dbg!(&node); 12 12 13 + let value = &node.statics[0].value; 14 + 13 15 Box::new(Self { 14 - address: node.statics[0].value.as_str().unwrap().to_owned(), 16 + address: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) }, 15 17 outputs: node.outputs.iter() 16 18 .map(| x | { 17 19 x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() ··· 27 29 } 28 30 29 31 fn execute_dry( &mut self, msg: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 32 + if self.address.is_none(){ 33 + self.runtime_active = false; 34 + return None 35 + } 36 + 30 37 if let ParameterType::String(address) = &msg[0]{ 31 - if *address == self.address{ 38 + if *address == *self.address.as_ref().unwrap(){ 32 39 self.runtime_active = true; 33 40 Some(msg.clone()) 34 41 // The first value is technically the address value, ··· 45 52 } 46 53 } 47 54 48 - fn execute( &mut self ) -> bool { 55 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { 49 56 let execute = self.runtime_active; 50 57 self.runtime_active = false; 51 58 52 - execute 59 + Some(vec![ ParameterType::Flow(execute) ]) 53 60 } 54 61 55 62 fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false }
+41
src-tauri/src/runtime/nodes/statics/float.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct StaticFloat{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + value: Option<f32> 6 + } 7 + 8 + impl StaticFloat{ 9 + pub fn new( node: Node ) -> Box<Self>{ 10 + dbg!(&node); 11 + 12 + let value = &node.statics[0].value; 13 + 14 + Box::new(Self { 15 + value: if value.is_null(){ None } else { Some(value.as_f64().unwrap() as f32) }, 16 + outputs: node.outputs.iter() 17 + .map(| x | { 18 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 19 + }).collect(), 20 + }) 21 + } 22 + } 23 + 24 + impl RuntimeNode for StaticFloat{ 25 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 26 + self.outputs.clone() 27 + } 28 + 29 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 30 + if self.value.is_some(){ 31 + Some(vec![ ParameterType::Float(self.value.clone().unwrap()) ]) 32 + } else{ 33 + None 34 + } 35 + } 36 + 37 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 38 + 39 + fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 40 + fn is_entrypoint( &self ) -> bool { true } 41 + }
+41
src-tauri/src/runtime/nodes/statics/int.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct StaticInt{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + value: Option<i32> 6 + } 7 + 8 + impl StaticInt{ 9 + pub fn new( node: Node ) -> Box<Self>{ 10 + dbg!(&node); 11 + 12 + let value = &node.statics[0].value; 13 + 14 + Box::new(Self { 15 + value: if value.is_null(){ None } else { Some(value.as_i64().unwrap() as i32) }, 16 + outputs: node.outputs.iter() 17 + .map(| x | { 18 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 19 + }).collect(), 20 + }) 21 + } 22 + } 23 + 24 + impl RuntimeNode for StaticInt{ 25 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 26 + self.outputs.clone() 27 + } 28 + 29 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 30 + if self.value.is_some(){ 31 + Some(vec![ ParameterType::Int(self.value.clone().unwrap()) ]) 32 + } else{ 33 + None 34 + } 35 + } 36 + 37 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 38 + 39 + fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 40 + fn is_entrypoint( &self ) -> bool { true } 41 + }
+3
src-tauri/src/runtime/nodes/statics/mod.rs
··· 1 + pub mod string; 2 + pub mod int; 3 + pub mod float;
+41
src-tauri/src/runtime/nodes/statics/string.rs
··· 1 + use crate::{ runtime::nodes::RuntimeNode, structs::{ nodes::Node, parameter_types::ParameterType } }; 2 + 3 + pub struct StaticString{ 4 + outputs: Vec<Vec<( String, isize, isize )>>, 5 + value: Option<String> 6 + } 7 + 8 + impl StaticString{ 9 + pub fn new( node: Node ) -> Box<Self>{ 10 + dbg!(&node); 11 + 12 + let value = &node.statics[0].value; 13 + 14 + Box::new(Self { 15 + value: if value.is_null(){ None } else { Some(value.as_str().unwrap().to_owned()) }, 16 + outputs: node.outputs.iter() 17 + .map(| x | { 18 + x.connections.iter().map(| x | { ( x.node.clone(), x.index, x.value_type ) }).collect() 19 + }).collect(), 20 + }) 21 + } 22 + } 23 + 24 + impl RuntimeNode for StaticString{ 25 + fn outputs( &self ) -> Vec<Vec<( String, isize, isize )>> { 26 + self.outputs.clone() 27 + } 28 + 29 + fn execute_dry( &mut self, _: &Vec<ParameterType> ) -> Option<Vec<ParameterType>> { 30 + if self.value.is_some(){ 31 + Some(vec![ ParameterType::String(self.value.clone().unwrap()) ]) 32 + } else{ 33 + None 34 + } 35 + } 36 + 37 + fn execute( &mut self ) -> Option<Vec<ParameterType>> { None } 38 + 39 + fn update_arg( &mut self, _: usize, _: ParameterType ) -> bool { false } 40 + fn is_entrypoint( &self ) -> bool { true } 41 + }
+19 -26
src-tauri/src/setup.rs
··· 1 - use std::{ collections::HashMap, fs::File, io::Read, sync::{ self, mpsc::Receiver, Mutex } }; 1 + use std::{ collections::HashMap, fs::File, io::Read, sync::Mutex }; 2 + use crossbeam_channel::{ Receiver, bounded }; 2 3 3 4 use flate2::read::GzDecoder; 4 5 use serde_json::{ Map, Value }; ··· 9 10 pub fn setup( 10 11 app: &mut App, 11 12 addresses: &'static Mutex<Vec<OSCMessage>>, 12 - runtime_command_receiver: Receiver<RuntimeCommand> 13 + mut runtime_command_receiver: Receiver<RuntimeCommand> 13 14 ) { 14 15 let window = app.get_webview_window("main").unwrap(); 15 16 ··· 32 33 handle.emit("load_new_tab", Value::Object(map)).unwrap(); 33 34 }); 34 35 35 - let ( sender, receiver ) = sync::mpsc::channel(); 36 + let ( sender, receiver ) = bounded(1024); 36 37 37 38 tokio::spawn(async move { 38 39 osc::start_server(sender, "127.0.0.1:9001"); 39 40 }); 40 41 41 - let ( runtime_sender, runtime_receiver ) = sync::mpsc::channel(); 42 + let ( runtime_sender, runtime_receiver ) = bounded(1024); 42 43 43 44 let runtime_sender_1 = runtime_sender.clone(); 44 45 tokio::spawn(async move { ··· 55 56 window.emit("osc-message", &message).unwrap(); 56 57 57 58 let msg = message.clone(); 58 - let mut addresses = addresses.lock().unwrap(); 59 - if !addresses.contains(&msg) { addresses.push(msg); } 59 + let mut addrs = addresses.lock().unwrap(); 60 + if !addrs.contains(&msg) { addrs.push(msg); } 60 61 61 62 runtime_sender.send(RuntimeCommand::OSCMessage(message)).unwrap(); 62 63 } ··· 70 71 71 72 match cmd{ 72 73 RuntimeCommand::OSCMessage( msg ) => { 73 - for ( _, tab ) in &mut tabs{ 74 - for ( id, node ) in &tab.nodes{ 75 - let node = node.lock().unwrap(); 74 + for ( _, mut tab ) in &mut tabs{ 75 + let keys: Vec<String> = tab.nodes.keys().map(| x | { x.clone() }).collect(); 76 76 77 - if node.is_entrypoint(){ 77 + for id in keys.clone(){ 78 + let entry = tab.nodes[&id].is_entrypoint(); 79 + 80 + if entry{ 78 81 let args = vec![ 79 82 vec![ ParameterType::String(msg.address.clone()) ], msg.values.clone() 80 83 ].concat(); 81 84 82 - drop(node); 83 - // ^^ Drop this MutexGuard before we enter the runtime, 84 - // as it blocks the runtime for gaining a lock on the node 85 - // TODO: Please find a better way of making it mutable 86 - 87 - runtime_dry(id.clone(), &args, tab).unwrap(); 85 + runtime_dry(id.clone(), &args, &mut tab).unwrap(); 88 86 } 89 87 } 90 88 91 - for ( id, node ) in &tab.nodes{ 92 - let node = node.lock().unwrap(); 93 - 94 - if node.is_entrypoint(){ 95 - drop(node); 96 - // ^^ Drop this MutexGuard before we enter the runtime, 97 - // as it blocks the runtime for gaining a lock on the node 98 - // TODO: Please find a better way of making it mutable 89 + for id in keys{ 90 + let entry = tab.nodes[&id].is_entrypoint(); 99 91 100 - runtime(id.clone(), tab).unwrap(); 92 + if entry{ 93 + let _ = runtime(id.clone(), &mut tab); 101 94 } 102 95 } 103 96 } ··· 112 105 } 113 106 } 114 107 }); 115 - } 108 + }
+3 -1
src-tauri/src/structs/parameter_types.rs
··· 1 1 use serde::Serialize; 2 2 3 - #[derive(Serialize, Clone, Debug)] 3 + #[derive(Serialize, Clone, Debug, PartialEq)] 4 4 #[serde(tag = "key", content = "value")] 5 5 pub enum ParameterType { 6 6 AnyType(String), ··· 11 11 Boolean(bool), 12 12 String(String), 13 13 Flow(bool), 14 + 15 + None 14 16 }
+5
src/App.css
··· 1 + @font-face{ 2 + font-family: Rubik; 3 + src: url("/assets/fonts/Rubik-VariableFont_wght.ttf"); 4 + } 5 + 1 6 body{ 2 7 background: #1f2129; 3 8 background-attachment: fixed;
+3 -1
src/Nodes/Statics.tsx
··· 1 1 import { NodeDefinition } from "./Nodes"; 2 + import { NodeStaticsFloat } from "./Statics/Float"; 2 3 3 4 import { NodeStaticsInt } from "./Statics/Int"; 4 5 import { NodeStaticsString } from "./Statics/String"; ··· 8 9 name: 'Statics', 9 10 items: [ 10 11 NodeStaticsInt, 11 - NodeStaticsString 12 + NodeStaticsString, 13 + NodeStaticsFloat 12 14 ] 13 15 }
+21
src/Nodes/Statics/Float.tsx
··· 1 + import { Node, NodeType } from "../../structs/node"; 2 + import { NodeDefinition } from "../Nodes"; 3 + 4 + export let NodeStaticsFloat: NodeDefinition = { 5 + isSingle: true, 6 + name: 'Float', 7 + typeId: 'staticfloat', 8 + 9 + w: 200, 10 + h: 85, 11 + 12 + statics: [{ 13 + type: NodeType.Float, 14 + name: 'Value', 15 + value: null 16 + }], 17 + 18 + outputs: [{ name: "Float", type: NodeType.Float }], 19 + 20 + onStaticsUpdate: async ( _node: Node ) => {} 21 + }
+1 -1
src/Nodes/Statics/Int.tsx
··· 4 4 export let NodeStaticsInt: NodeDefinition = { 5 5 isSingle: true, 6 6 name: 'Int', 7 - typeId: 'ifelse', 7 + typeId: 'staticint', 8 8 9 9 w: 200, 10 10 h: 85,
+41 -1
src/components/ControlBar.tsx
··· 1 1 import './ControlBar.css'; 2 2 3 - import { Accessor, createSignal, For, Match, Show, Switch } from 'solid-js'; 3 + import { Accessor, createEffect, createSignal, For, Match, Show, Switch } from 'solid-js'; 4 4 import { Node, NodeType } from '../structs/node'; 5 5 import { TextInput } from './TextInput'; 6 6 import { invoke } from '@tauri-apps/api/core'; ··· 14 14 } 15 15 16 16 export let ControlBar = ( props: ControlBarProps ) => { 17 + createEffect(() => { 18 + console.log(props.node()); 19 + }) 20 + 17 21 return ( 18 22 <div class="control-bar"> 19 23 <For each={props.node()?.statics}> ··· 26 30 <Match when={item.type == NodeType.String}> 27 31 { item.name } 28 32 <div style={{ display: 'inline-block', 'margin-left': '10px' }}> 33 + <input 34 + type="text" 35 + placeholder='Enter Value...' 36 + value={item.value || ''} 37 + onChange={( el ) => { 38 + let value = el.target.value; 39 + let node = props.node()!; 40 + 41 + item.value = value; 42 + node.onStaticsUpdate(node); 29 43 44 + NodeManager.Instance.UpdateConfig(); 45 + }} /> 30 46 </div> 31 47 </Match> 32 48 <Match when={item.type == NodeType.Int}> 33 49 { item.name } 34 50 <div style={{ display: 'inline-block', 'margin-left': '10px' }}> 51 + <input 52 + type="number" 53 + placeholder='Enter Value...' 54 + value={item.value !== undefined ? item.value : ''} 55 + onChange={( el ) => { 56 + let value = el.target.value; 57 + let node = props.node()!; 35 58 59 + item.value = parseInt(value); 60 + node.onStaticsUpdate(node); 61 + 62 + NodeManager.Instance.UpdateConfig(); 63 + }} /> 36 64 </div> 37 65 </Match> 38 66 <Match when={item.type == NodeType.Float}> 39 67 { item.name } 40 68 <div style={{ display: 'inline-block', 'margin-left': '10px' }}> 69 + <input 70 + type="number" 71 + placeholder='Enter Value...' 72 + value={item.value !== undefined ? item.value : ''} 73 + onChange={( el ) => { 74 + let value = el.target.value; 75 + let node = props.node()!; 41 76 77 + item.value = parseFloat(value); 78 + node.onStaticsUpdate(node); 79 + 80 + NodeManager.Instance.UpdateConfig(); 81 + }} /> 42 82 </div> 43 83 </Match> 44 84 <Match when={item.type == NodeType.OSCAddress}>
+2
src/components/TabMenu.css
··· 53 53 .tab-meta{ 54 54 width: calc(100% - 40px); 55 55 transform: translateY(1px); 56 + display: flex; 57 + align-items: center; 56 58 } 57 59 58 60 .tab-meta-input{
+11
src/components/TextInput.css
··· 9 9 width: 400px; 10 10 } 11 11 12 + input[type="number"]{ 13 + outline: none; 14 + background: none; 15 + border: none; 16 + border-bottom: 2px solid #525252; 17 + font-size: 15px; 18 + font-family: Rubik, 'Courier New'; 19 + color: #fff; 20 + width: 400px; 21 + } 22 + 12 23 div[input-dropdown]{ 13 24 position: absolute; 14 25 width: fit-content;