use super::*; use std::time::{Duration,Instant}; pub struct TheApplication{ pub(super) plugins:Vec, pub(super) state:ApplicationState, } pub struct ApplicationState{ // This is separate so that I can use the address // of a PluginType to find its index inside of plugins. pub(super) plugin_ids:Vec, pub(super) id_map:HashMap, pub(super) delayed_commands:VecDeque, pub(super) responses:VecDeque, pub(super) sender:RSender, pub(super) receiver:RReceiver, pub(super) last_run_at:Instant, } fn print_response( plugin_id:&PluginId, response:&str, ){ println!( "reponse:\n{}\nfrom:\n {:?}\n\n", response.left_pad(4), plugin_id, ); } impl TheApplication{ /// Runs a command, pub fn run_command(&mut self,which_plugin:WhichPlugin,command:RStr<'_>)->Result<(),AppError>{ let list=self.state.expand_which_plugin(which_plugin)?; for index in list { let state=Application_TO::from_ptr(&mut self.state,TU_Opaque); let plugin=&mut self.plugins[index as usize]; println!("command:\n{}", command.left_pad(4)); let resp=plugin.json_command(command,state).into_result()?; self.state.register_command_run(); print_response(&self.state.plugin_ids[index],&resp); } Ok(()) } pub fn tick(&mut self) -> Result<(), AppError>{ if let Ok(ac)=self.state.receiver.try_recv() { self.state.send_command_to_plugin(&ac.from,ac.which_plugin,ac.command).into_result()?; } if let Some(dc)=self.state.delayed_commands.pop_front() { self.run_command_(&dc.from,dc.plugin_index,&dc.command)?; } let mut responses=mem::replace(&mut self.state.responses, VecDeque::new()); for DelayedResponse{to,from,response} in responses.drain(..) { let response=PluginResponse::owned_response(from,response); let state=Application_TO::from_ptr(&mut self.state,TU_Opaque); if let RSome(res)=self.plugins[to] .handle_response(response, state) .into_result()? { print_response(&res.plugin_id, &res.response); } } self.state.responses=responses; Ok(()) } pub fn is_finished(&self)->bool{ self.state.last_run_at.elapsed()>=Duration::from_secs(5) } fn run_command_(&mut self,from:&PluginId, to:usize, command:&str) -> Result<(), AppError> { let state=Application_TO::from_ptr(&mut self.state,TU_Opaque); let response=self.plugins[to].json_command(command.into(),state).into_result()?; let to=self.state.index_for_plugin_id(from)?; self.state.register_command_run(); let response = DelayedResponse { from:self.state.plugin_ids[to].clone(), to, response, }; self.state.responses.push_back(response); Ok(()) } } impl ApplicationState{ pub(crate) fn new() -> Self { let (sender,receiver)=crossbeam_channel::unbounded(); Self{ plugin_ids:Vec::new(), id_map:HashMap::new(), delayed_commands:VecDeque::new(), responses:VecDeque::new(), sender, receiver, last_run_at:Instant::now(), } } fn register_command_run(&mut self) { self.last_run_at=Instant::now(); } fn index_for_plugin_id(&self, id:&PluginId) -> Result { self.id_map.get(&*id.named) .and_then(|x| x.indices.get(id.instance as usize).cloned()) .ok_or_else(|| AppError::InvalidPlugin(WhichPlugin::Id(id.clone()))) } fn expand_which_plugin(&self, which_plugin:WhichPlugin) -> Result { match which_plugin { WhichPlugin::Id(id)=>{ self.index_for_plugin_id(&id) .map(|i| PluginIndices::from([i]) ) }, WhichPlugin::First{ref named} | WhichPlugin::Last{ref named} | WhichPlugin::Every{ref named} => { self.id_map.get(&**named).and_then(|x| { let list=&x.indices; match which_plugin { WhichPlugin::First{..} => { PluginIndices::from([*list.first()?]) }, WhichPlugin::Last{..} => { PluginIndices::from([*list.last()?]) }, WhichPlugin::Every{..} => { PluginIndices::from(&**list) }, _=>unreachable!(), }.piped(Some) }) .ok_or_else(|| AppError::InvalidPlugin(which_plugin.clone())) }, WhichPlugin::Many(list) => { let mut plugin_indices=PluginIndices::new(); for elem in list { plugin_indices.extend(self.expand_which_plugin(elem)?); } Ok(plugin_indices) } } } } impl Application for ApplicationState { fn send_command_to_plugin( &mut self, from:&PluginId, which_plugin:WhichPlugin, command:RString, ) -> RResult<(),AppError> { self.expand_which_plugin(which_plugin).map(|plugin_indices|{ let command=Arc::new(command); for plugin_index in plugin_indices { let from=from.clone(); self.delayed_commands.push_back(DelayedCommand { from, plugin_index, command:command.clone(), }); } }).into() } fn get_plugin_id(&self, which_plugin:WhichPlugin) -> RResult, AppError> { self.expand_which_plugin(which_plugin) .map(|list|{ list.into_iter() .map(|i| self.plugin_ids[i].clone() ) .collect::>() }) .into() } fn sender(&self) -> RSender { self.sender.clone() } fn loaded_plugins(&self) -> RVec { self.plugin_ids.clone().into() } } ////////////////////////////////////////////////////////////////////////////////