Browse Source

Use actix for update_listener

master
Alex Mikhalev 4 years ago
parent
commit
4eb03f2e22
  1. 203
      src/update_listener.rs

203
src/update_listener.rs

@ -3,37 +3,38 @@ use crate::{ @@ -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 { @@ -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(());
.await
{
warn!("could not publish program running: {}", err);
}
};
self.mqtt_interface.publish_section_runner(&state).await?;
Ok(())
ctx.spawn(wrap_future(fut));
}
}
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?
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));
}
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
#[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);
}
}
async fn run(self, quit_rx: oneshot::Receiver<()>) {
let span = trace_span!("update_listener task");
impl Listenable<UpdateListenerActor> for ProgramEventRecv {
fn listen(self, ctx: &mut <UpdateListenerActor as Actor>::Context) {
ctx.add_stream(self);
}
}
self.run_or_quit(quit_rx)
.instrument(span)
.await
.expect("error in UpdateListenerTask");
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 { @@ -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…
Cancel
Save