Use actix for update_listener
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									709f8c2760
								
							
						
					
					
						commit
						4eb03f2e22
					
				| @ -3,37 +3,38 @@ use crate::{ | ||||
|     program_runner::{ProgramEvent, ProgramEventRecv}, | ||||
|     section_runner::{SecRunnerState, SecRunnerStateRecv, SectionEvent, SectionEventRecv}, | ||||
| }; | ||||
| use tokio::{ | ||||
|     select, | ||||
|     sync::{broadcast, oneshot}, | ||||
|     task::JoinHandle, | ||||
| }; | ||||
| use tracing::{trace_span, warn}; | ||||
| use tracing_futures::Instrument; | ||||
| use actix::{fut::wrap_future, Actor, ActorContext, Addr, AsyncContext, Handler, StreamHandler}; | ||||
| use tokio::sync::broadcast; | ||||
| use tracing::{trace, warn}; | ||||
| 
 | ||||
| struct UpdateListenerTask { | ||||
|     section_events: SectionEventRecv, | ||||
|     program_events: ProgramEventRecv, | ||||
|     sec_runner_state: SecRunnerStateRecv, | ||||
| struct UpdateListenerActor { | ||||
|     mqtt_interface: MqttInterface, | ||||
|     running: bool, | ||||
| } | ||||
| 
 | ||||
| impl UpdateListenerTask { | ||||
|     async fn handle_section_event( | ||||
| impl Actor for UpdateListenerActor { | ||||
|     type Context = actix::Context<Self>; | ||||
| 
 | ||||
|     fn started(&mut self, _ctx: &mut Self::Context) { | ||||
|         trace!("starting UpdateListener"); | ||||
|     } | ||||
| 
 | ||||
|     fn stopped(&mut self, _ctx: &mut Self::Context) { | ||||
|         trace!("stopped UpdateListener") | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl StreamHandler<Result<SectionEvent, broadcast::RecvError>> for UpdateListenerActor { | ||||
|     fn handle( | ||||
|         &mut self, | ||||
|         event: Result<SectionEvent, broadcast::RecvError>, | ||||
|     ) -> eyre::Result<()> { | ||||
|         ctx: &mut Self::Context, | ||||
|     ) { | ||||
|         let event = match event { | ||||
|             Ok(ev) => ev, | ||||
|             Err(broadcast::RecvError::Closed) => { | ||||
|                 warn!("section events channel closed"); | ||||
|                 self.running = false; | ||||
|                 return Ok(()); | ||||
|             } | ||||
|             Err(broadcast::RecvError::Closed) => unreachable!(), | ||||
|             Err(broadcast::RecvError::Lagged(n)) => { | ||||
|                 warn!("section events lagged by {}", n); | ||||
|                 return Ok(()); | ||||
|                 return; | ||||
|             } | ||||
|         }; | ||||
|         if let Some((sec_id, state)) = match event { | ||||
| @ -45,94 +46,116 @@ impl UpdateListenerTask { | ||||
|             | SectionEvent::RunCancel(_, sec) => Some((sec.id, false)), | ||||
|             SectionEvent::RunnerPause | SectionEvent::RunnerUnpause => None, | ||||
|         } { | ||||
|             self.mqtt_interface | ||||
|                 .publish_section_state(sec_id, state) | ||||
|                 .await?; | ||||
|             let mut mqtt_interface = self.mqtt_interface.clone(); | ||||
|             let fut = async move { | ||||
|                 if let Err(err) = mqtt_interface.publish_section_state(sec_id, state).await { | ||||
|                     warn!("could not publish section state: {}", err); | ||||
|                 } | ||||
|             }; | ||||
|             ctx.spawn(wrap_future(fut)); | ||||
|         } | ||||
|     } | ||||
|         Ok(()) | ||||
| } | ||||
| 
 | ||||
|     async fn handle_program_event( | ||||
| impl StreamHandler<Result<ProgramEvent, broadcast::RecvError>> for UpdateListenerActor { | ||||
|     fn handle( | ||||
|         &mut self, | ||||
|         event: Result<ProgramEvent, broadcast::RecvError>, | ||||
|     ) -> eyre::Result<()> { | ||||
|         ctx: &mut Self::Context, | ||||
|     ) { | ||||
|         let event = match event { | ||||
|             Ok(ev) => ev, | ||||
|             Err(broadcast::RecvError::Closed) => { | ||||
|                 warn!("program events channel closed"); | ||||
|                 self.running = false; | ||||
|                 return Ok(()); | ||||
|             } | ||||
|             Err(broadcast::RecvError::Closed) => unreachable!(), | ||||
|             Err(broadcast::RecvError::Lagged(n)) => { | ||||
|                 warn!("program events lagged by {}", n); | ||||
|                 return Ok(()); | ||||
|                 return; | ||||
|             } | ||||
|         }; | ||||
|         let (program_id, running) = match event { | ||||
|             ProgramEvent::RunStart(prog) => (prog.id, true), | ||||
|             ProgramEvent::RunFinish(prog) | ProgramEvent::RunCancel(prog) => (prog.id, false), | ||||
|         }; | ||||
|         self.mqtt_interface | ||||
|         let mut mqtt_interface = self.mqtt_interface.clone(); | ||||
|         let fut = async move { | ||||
|             if let Err(err) = mqtt_interface | ||||
|                 .publish_program_running(program_id, running) | ||||
|             .await?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn handle_sec_runner_state(&mut self, state: Option<SecRunnerState>) -> eyre::Result<()> { | ||||
|         let state = match state { | ||||
|             Some(state) => state, | ||||
|             None => { | ||||
|                 warn!("section runner events channel closed"); | ||||
|                 self.running = false; | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         }; | ||||
|         self.mqtt_interface.publish_section_runner(&state).await?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn run_impl(&mut self) -> eyre::Result<()> { | ||||
|         while self.running { | ||||
|             select! { | ||||
|                 section_event = self.section_events.recv() => { | ||||
|                     self.handle_section_event(section_event).await? | ||||
|                 } | ||||
|                 program_event = self.program_events.recv() => { | ||||
|                     self.handle_program_event(program_event).await? | ||||
|                 } | ||||
|                 sec_runner_state = self.sec_runner_state.recv() => { | ||||
|                     self.handle_sec_runner_state(sec_runner_state).await? | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn run_or_quit(mut self, mut quit_rx: oneshot::Receiver<()>) -> eyre::Result<()> { | ||||
|         select! { | ||||
|             _ = &mut quit_rx => { | ||||
|                 self.running = false; | ||||
|                 Ok(()) | ||||
|             } | ||||
|             res = self.run_impl() => { | ||||
|                 res | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async fn run(self, quit_rx: oneshot::Receiver<()>) { | ||||
|         let span = trace_span!("update_listener task"); | ||||
| 
 | ||||
|         self.run_or_quit(quit_rx) | ||||
|             .instrument(span) | ||||
|                 .await | ||||
|             .expect("error in UpdateListenerTask"); | ||||
|             { | ||||
|                 warn!("could not publish program running: {}", err); | ||||
|             } | ||||
|         }; | ||||
|         ctx.spawn(wrap_future(fut)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl StreamHandler<SecRunnerState> for UpdateListenerActor { | ||||
|     fn handle(&mut self, state: SecRunnerState, ctx: &mut Self::Context) { | ||||
|         let mut mqtt_interface = self.mqtt_interface.clone(); | ||||
|         let fut = async move { | ||||
|             if let Err(err) = mqtt_interface.publish_section_runner(&state).await { | ||||
|                 warn!("could not publish section runner: {}", err); | ||||
|             } | ||||
|         }; | ||||
|         ctx.spawn(wrap_future(fut)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(actix::Message)] | ||||
| #[rtype(result = "()")] | ||||
| struct Quit; | ||||
| 
 | ||||
| impl Handler<Quit> for UpdateListenerActor { | ||||
|     type Result = (); | ||||
| 
 | ||||
|     fn handle(&mut self, _msg: Quit, ctx: &mut Self::Context) -> Self::Result { | ||||
|         ctx.stop(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| trait Listenable<A>: Send | ||||
| where | ||||
|     A: Actor, | ||||
| { | ||||
|     fn listen(self, ctx: &mut A::Context); | ||||
| } | ||||
| 
 | ||||
| #[derive(actix::Message)] | ||||
| #[rtype(result = "()")] | ||||
| struct Listen<L>(L) | ||||
| where | ||||
|     L: Listenable<UpdateListenerActor>; | ||||
| 
 | ||||
| impl<L> Handler<Listen<L>> for UpdateListenerActor | ||||
| where | ||||
|     L: Listenable<Self>, | ||||
| { | ||||
|     type Result = (); | ||||
| 
 | ||||
|     fn handle(&mut self, msg: Listen<L>, ctx: &mut Self::Context) -> Self::Result { | ||||
|         msg.0.listen(ctx); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Listenable<UpdateListenerActor> for SectionEventRecv { | ||||
|     fn listen(self, ctx: &mut <UpdateListenerActor as Actor>::Context) { | ||||
|         ctx.add_stream(self); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Listenable<UpdateListenerActor> for ProgramEventRecv { | ||||
|     fn listen(self, ctx: &mut <UpdateListenerActor as Actor>::Context) { | ||||
|         ctx.add_stream(self); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Listenable<UpdateListenerActor> for SecRunnerStateRecv { | ||||
|     fn listen(self, ctx: &mut <UpdateListenerActor as Actor>::Context) { | ||||
|         ctx.add_stream(self); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct UpdateListener { | ||||
|     quit_tx: oneshot::Sender<()>, | ||||
|     join_handle: JoinHandle<()>, | ||||
|     addr: Addr<UpdateListenerActor>, | ||||
| } | ||||
| 
 | ||||
| impl UpdateListener { | ||||
| @ -142,24 +165,22 @@ impl UpdateListener { | ||||
|         sec_runner_state: SecRunnerStateRecv, | ||||
|         mqtt_interface: MqttInterface, | ||||
|     ) -> Self { | ||||
|         let task = UpdateListenerTask { | ||||
|             section_events, | ||||
|             program_events, | ||||
|             sec_runner_state, | ||||
|             mqtt_interface, | ||||
|             running: true, | ||||
|         }; | ||||
|         let (quit_tx, quit_rx) = oneshot::channel(); | ||||
|         let join_handle = tokio::spawn(task.run(quit_rx)); | ||||
|         Self { | ||||
|             quit_tx, | ||||
|             join_handle, | ||||
|         let addr = UpdateListenerActor { mqtt_interface }.start(); | ||||
|         let mut l = Self { addr }; | ||||
|         l.listen(section_events); | ||||
|         l.listen(program_events); | ||||
|         l.listen(sec_runner_state); | ||||
|         l | ||||
|     } | ||||
| 
 | ||||
|     fn listen<L: 'static>(&mut self, listener: L) | ||||
|     where | ||||
|         L: Listenable<UpdateListenerActor>, | ||||
|     { | ||||
|         self.addr.do_send(Listen(listener)); | ||||
|     } | ||||
| 
 | ||||
|     pub async fn quit(self) -> eyre::Result<()> { | ||||
|         let _ = self.quit_tx.send(()); | ||||
|         self.join_handle.await?; | ||||
|         Ok(()) | ||||
|         Ok(self.addr.send(Quit).await?) | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user