Implement mqtt section states
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
46fab5b50f
commit
63fd0be100
@ -63,6 +63,11 @@ async fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
let mut mqtt_interface = mqtt_interface::MqttInterfaceTask::start(mqtt_options).await?;
|
let mut mqtt_interface = mqtt_interface::MqttInterfaceTask::start(mqtt_options).await?;
|
||||||
|
|
||||||
|
update_listener::UpdateListener::start(
|
||||||
|
section_runner.subscribe().await?,
|
||||||
|
mqtt_interface.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
program_runner.update_sections(sections.clone()).await?;
|
program_runner.update_sections(sections.clone()).await?;
|
||||||
mqtt_interface.publish_sections(§ions).await?;
|
mqtt_interface.publish_sections(§ions).await?;
|
||||||
for section_id in sections.keys() {
|
for section_id in sections.keys() {
|
||||||
|
@ -274,7 +274,7 @@ impl RunnerTask {
|
|||||||
let sec_event = sec_event.wrap_err("failed to receive section event")?;
|
let sec_event = sec_event.wrap_err("failed to receive section event")?;
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match sec_event {
|
match sec_event {
|
||||||
SectionEvent::RunFinish(finished_run) => {
|
SectionEvent::RunFinish(finished_run, _) => {
|
||||||
self.handle_finished_run(finished_run, run_queue);
|
self.handle_finished_run(finished_run, run_queue);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -525,15 +525,15 @@ mod test {
|
|||||||
ProgramEvent::RunStart(prog)
|
ProgramEvent::RunStart(prog)
|
||||||
if prog.id == 1
|
if prog.id == 1
|
||||||
);
|
);
|
||||||
assert_matches!(sec_events.try_recv().unwrap(), SectionEvent::RunStart(_));
|
assert_matches!(sec_events.try_recv().unwrap(), SectionEvent::RunStart(_, _));
|
||||||
assert_eq!(interface.get_section_state(0), true);
|
assert_eq!(interface.get_section_state(0), true);
|
||||||
|
|
||||||
tokio::time::pause();
|
tokio::time::pause();
|
||||||
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunFinish(_));
|
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunFinish(_, _));
|
||||||
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunStart(_));
|
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunStart(_, _));
|
||||||
assert_eq!(interface.get_section_state(0), false);
|
assert_eq!(interface.get_section_state(0), false);
|
||||||
assert_eq!(interface.get_section_state(1), true);
|
assert_eq!(interface.get_section_state(1), true);
|
||||||
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunFinish(_));
|
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunFinish(_, _));
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
prog_events.recv().await.unwrap(),
|
prog_events.recv().await.unwrap(),
|
||||||
ProgramEvent::RunFinish(_)
|
ProgramEvent::RunFinish(_)
|
||||||
@ -715,7 +715,7 @@ mod test {
|
|||||||
ProgramEvent::RunStart(prog)
|
ProgramEvent::RunStart(prog)
|
||||||
if prog.id == 1
|
if prog.id == 1
|
||||||
);
|
);
|
||||||
assert_matches!(sec_events.try_recv().unwrap(), SectionEvent::RunStart(_));
|
assert_matches!(sec_events.try_recv().unwrap(), SectionEvent::RunStart(_, _));
|
||||||
|
|
||||||
runner.cancel_program(program.id).await.unwrap();
|
runner.cancel_program(program.id).await.unwrap();
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
@ -724,7 +724,7 @@ mod test {
|
|||||||
ProgramEvent::RunCancel(prog)
|
ProgramEvent::RunCancel(prog)
|
||||||
if prog.id == 1
|
if prog.id == 1
|
||||||
);
|
);
|
||||||
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunCancel(_));
|
assert_matches!(sec_events.recv().await.unwrap(), SectionEvent::RunCancel(_, _));
|
||||||
|
|
||||||
runner.quit().await.unwrap();
|
runner.quit().await.unwrap();
|
||||||
sec_runner.quit().await.unwrap();
|
sec_runner.quit().await.unwrap();
|
||||||
|
@ -17,7 +17,7 @@ use tokio::{
|
|||||||
};
|
};
|
||||||
use tracing::{debug, trace, trace_span, warn};
|
use tracing::{debug, trace, trace_span, warn};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SectionRunHandle(i32);
|
pub struct SectionRunHandle(i32);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -44,13 +44,13 @@ enum RunnerMsg {
|
|||||||
Subscribe(oneshot::Sender<SectionEventRecv>),
|
Subscribe(oneshot::Sender<SectionEventRecv>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum SectionEvent {
|
pub enum SectionEvent {
|
||||||
RunStart(SectionRunHandle),
|
RunStart(SectionRunHandle, SectionRef),
|
||||||
RunFinish(SectionRunHandle),
|
RunFinish(SectionRunHandle, SectionRef),
|
||||||
RunPause(SectionRunHandle),
|
RunPause(SectionRunHandle, SectionRef),
|
||||||
RunUnpause(SectionRunHandle),
|
RunUnpause(SectionRunHandle, SectionRef),
|
||||||
RunCancel(SectionRunHandle),
|
RunCancel(SectionRunHandle, SectionRef),
|
||||||
RunnerPause,
|
RunnerPause,
|
||||||
RunnerUnpause,
|
RunnerUnpause,
|
||||||
}
|
}
|
||||||
@ -176,7 +176,10 @@ impl RunnerTask {
|
|||||||
run.state = Running {
|
run.state = Running {
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
};
|
};
|
||||||
self.send_event(SectionEvent::RunStart(run.handle.clone()));
|
self.send_event(SectionEvent::RunStart(
|
||||||
|
run.handle.clone(),
|
||||||
|
run.section.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_run(&mut self, run: &mut Arc<SecRun>) {
|
fn finish_run(&mut self, run: &mut Arc<SecRun>) {
|
||||||
@ -186,7 +189,10 @@ impl RunnerTask {
|
|||||||
self.interface
|
self.interface
|
||||||
.set_section_state(run.section.interface_id, false);
|
.set_section_state(run.section.interface_id, false);
|
||||||
run.state = SecRunState::Finished;
|
run.state = SecRunState::Finished;
|
||||||
self.send_event(SectionEvent::RunFinish(run.handle.clone()));
|
self.send_event(SectionEvent::RunFinish(
|
||||||
|
run.handle.clone(),
|
||||||
|
run.section.clone(),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
section_id = run.section.id,
|
section_id = run.section.id,
|
||||||
@ -204,7 +210,10 @@ impl RunnerTask {
|
|||||||
.set_section_state(run.section.interface_id, false);
|
.set_section_state(run.section.interface_id, false);
|
||||||
}
|
}
|
||||||
run.state = SecRunState::Cancelled;
|
run.state = SecRunState::Cancelled;
|
||||||
self.send_event(SectionEvent::RunCancel(run.handle.clone()));
|
self.send_event(SectionEvent::RunCancel(
|
||||||
|
run.handle.clone(),
|
||||||
|
run.section.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pause_run(&mut self, run: &mut Arc<SecRun>) {
|
fn pause_run(&mut self, run: &mut Arc<SecRun>) {
|
||||||
@ -232,7 +241,10 @@ impl RunnerTask {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
run.state = new_state;
|
run.state = new_state;
|
||||||
self.send_event(SectionEvent::RunPause(run.handle.clone()));
|
self.send_event(SectionEvent::RunPause(
|
||||||
|
run.handle.clone(),
|
||||||
|
run.section.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unpause_run(&mut self, run: &mut Arc<SecRun>) {
|
fn unpause_run(&mut self, run: &mut Arc<SecRun>) {
|
||||||
@ -251,7 +263,10 @@ impl RunnerTask {
|
|||||||
};
|
};
|
||||||
let ran_for = pause_time - start_time;
|
let ran_for = pause_time - start_time;
|
||||||
run.duration -= ran_for;
|
run.duration -= ran_for;
|
||||||
self.send_event(SectionEvent::RunUnpause(run.handle.clone()));
|
self.send_event(SectionEvent::RunUnpause(
|
||||||
|
run.handle.clone(),
|
||||||
|
run.section.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Waiting | Finished | Cancelled | Running { .. } => {
|
Waiting | Finished | Cancelled | Running { .. } => {
|
||||||
warn!(
|
warn!(
|
||||||
@ -467,6 +482,7 @@ mod test {
|
|||||||
model::{Section, Sections},
|
model::{Section, Sections},
|
||||||
trace_listeners::{EventListener, Filters, SpanFilters, SpanListener},
|
trace_listeners::{EventListener, Filters, SpanFilters, SpanListener},
|
||||||
};
|
};
|
||||||
|
use assert_matches::assert_matches;
|
||||||
use im::ordmap;
|
use im::ordmap;
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
|
|
||||||
@ -732,59 +748,39 @@ mod test {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_matches!(
|
||||||
event_recv.recv().await,
|
event_recv.recv().await,
|
||||||
Ok(SectionEvent::RunStart(run1.clone()))
|
Ok(SectionEvent::RunStart(handle, _))
|
||||||
|
if handle == run1
|
||||||
);
|
);
|
||||||
|
|
||||||
runner.pause().await.unwrap();
|
runner.pause().await.unwrap();
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunnerPause));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunnerPause));
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunPause(handle, _)) if handle == run1);
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunPause(run1.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
runner.unpause().await.unwrap();
|
runner.unpause().await.unwrap();
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunnerUnpause));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunnerUnpause));
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunUnpause(handle, _)) if handle == run1);
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunUnpause(run1.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
advance(Duration::from_secs(11)).await;
|
advance(Duration::from_secs(11)).await;
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunFinish(run1)));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunFinish(handle, _)) if handle == run1);
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunStart(handle, _)) if handle == run2);
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunStart(run2.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
runner.pause().await.unwrap();
|
runner.pause().await.unwrap();
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunnerPause));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunnerPause));
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunPause(handle, _)) if handle == run2);
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunPause(run2.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
// cancel paused run
|
// cancel paused run
|
||||||
runner.cancel_run(run2.clone()).await.unwrap();
|
runner.cancel_run(run2.clone()).await.unwrap();
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunCancel(handle, _)) if handle == run2);
|
||||||
event_recv.recv().await,
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunPause(handle, _)) if handle == run3);
|
||||||
Ok(SectionEvent::RunCancel(run2.clone()))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunPause(run3.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
runner.unpause().await.unwrap();
|
runner.unpause().await.unwrap();
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunnerUnpause));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunnerUnpause));
|
||||||
assert_eq!(
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunUnpause(handle, _)) if handle == run3);
|
||||||
event_recv.recv().await,
|
|
||||||
Ok(SectionEvent::RunUnpause(run3.clone()))
|
|
||||||
);
|
|
||||||
|
|
||||||
advance(Duration::from_secs(11)).await;
|
advance(Duration::from_secs(11)).await;
|
||||||
assert_eq!(event_recv.recv().await, Ok(SectionEvent::RunFinish(run3)));
|
assert_matches!(event_recv.recv().await, Ok(SectionEvent::RunFinish(handle, _)) if handle == run3);
|
||||||
|
|
||||||
runner.quit().await.unwrap();
|
runner.quit().await.unwrap();
|
||||||
}
|
}
|
||||||
|
63
src/update_listener.rs
Normal file
63
src/update_listener.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use crate::{
|
||||||
|
mqtt_interface::MqttInterface,
|
||||||
|
section_runner::{SectionEvent, SectionEventRecv},
|
||||||
|
};
|
||||||
|
use tokio::{select, sync::broadcast, task::JoinHandle};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
|
pub struct UpdateListener {
|
||||||
|
mqtt_interface: MqttInterface,
|
||||||
|
running: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UpdateListener {
|
||||||
|
pub fn start(
|
||||||
|
section_events: SectionEventRecv,
|
||||||
|
mqtt_interface: MqttInterface,
|
||||||
|
) -> JoinHandle<()> {
|
||||||
|
let update_listener = UpdateListener {
|
||||||
|
mqtt_interface,
|
||||||
|
running: true,
|
||||||
|
};
|
||||||
|
tokio::spawn(update_listener.run(section_events))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_section_event(
|
||||||
|
&mut self,
|
||||||
|
event: Result<SectionEvent, broadcast::RecvError>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let event = match event {
|
||||||
|
Err(broadcast::RecvError::Closed) => {
|
||||||
|
trace!("section events channel closed");
|
||||||
|
self.running = false;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
e => e,
|
||||||
|
}?;
|
||||||
|
if let Some((sec_id, state)) = match event {
|
||||||
|
SectionEvent::RunStart(_, sec) | SectionEvent::RunUnpause(_, sec) => {
|
||||||
|
Some((sec.id, true))
|
||||||
|
}
|
||||||
|
SectionEvent::RunFinish(_, sec)
|
||||||
|
| SectionEvent::RunPause(_, sec)
|
||||||
|
| SectionEvent::RunCancel(_, sec) => Some((sec.id, false)),
|
||||||
|
SectionEvent::RunnerPause | SectionEvent::RunnerUnpause => None,
|
||||||
|
} {
|
||||||
|
self.mqtt_interface
|
||||||
|
.publish_section_state(sec_id, state)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(mut self, mut section_events: SectionEventRecv) {
|
||||||
|
while self.running {
|
||||||
|
let result = select! {
|
||||||
|
section_event = section_events.recv() => {
|
||||||
|
self.handle_section_event(section_event).await
|
||||||
|
}
|
||||||
|
};
|
||||||
|
result.expect("error in update_listener task");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user