use bus::StateBus;
use lifeline::prelude::*;
use message::MainRecv;
use postage::{sink::Sink, stream::Stream};
use service::{MainService, StateService};
use simple_logger::SimpleLogger;
use state::{LocationState, SkyState, WeatherState};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::main]
pub async fn main() -> anyhow::Result<()> {
SimpleLogger::new().init().expect("log init failed");
let bus = StateBus::default();
let _service = MainService::spawn(&bus)?;
let _state = StateService::spawn(&bus)?;
let mut tx = bus.tx::<MainRecv>()?;
let mut rx = bus.rx::<SkyState>()?;
drop(bus);
tx.send(MainRecv::Travel(LocationState::Boston)).await?;
sleep(Duration::from_millis(20)).await;
let state = rx.recv().await;
let expected = SkyState {
weather: WeatherState::Snowing,
location: LocationState::Boston,
};
assert_eq!(Some(expected), state);
tx.send(MainRecv::Travel(LocationState::SanDiego)).await?;
sleep(Duration::from_millis(20)).await;
let state = rx.recv().await;
let expected = SkyState {
weather: WeatherState::Sunny72Degrees,
location: LocationState::SanDiego,
};
assert_eq!(Some(expected), state);
println!("All done.");
Ok(())
}
mod message {
use crate::state::LocationState;
#[derive(Debug, Clone)]
pub enum MainRecv {
Travel(LocationState),
}
#[derive(Debug, Clone)]
pub struct TravelEvent(pub LocationState);
}
mod state {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SkyState {
pub weather: WeatherState,
pub location: LocationState,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum WeatherState {
None,
Snowing,
Sunny72Degrees,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum LocationState {
None,
Boston,
SanDiego,
}
impl Default for SkyState {
fn default() -> Self {
Self {
weather: WeatherState::None,
location: LocationState::None,
}
}
}
}
mod bus {
use crate::message::{MainRecv, TravelEvent};
use crate::state::SkyState;
use lifeline::prelude::*;
use postage::{broadcast, mpsc, watch};
lifeline_bus!(pub struct StateBus);
impl Message<StateBus> for SkyState {
type Channel = watch::Sender<Self>;
}
impl Message<StateBus> for TravelEvent {
type Channel = broadcast::Sender<Self>;
}
impl Message<StateBus> for MainRecv {
type Channel = mpsc::Sender<Self>;
}
}
mod service {
use super::bus::StateBus;
use crate::{
message::{MainRecv, TravelEvent},
state::{SkyState, WeatherState},
};
use lifeline::prelude::*;
use postage::{sink::Sink, stream::Stream};
pub struct MainService {
_greet: Lifeline,
}
impl Service for MainService {
type Bus = StateBus;
type Lifeline = anyhow::Result<Self>;
fn spawn(bus: &Self::Bus) -> Self::Lifeline {
let mut rx = bus.rx::<MainRecv>()?;
let mut tx = bus.tx::<TravelEvent>()?;
let _greet = Self::try_task("greet", async move {
while let Some(recv) = rx.recv().await {
match recv {
MainRecv::Travel(location) => {
tx.send(TravelEvent(location)).await?;
}
}
}
Ok(())
});
Ok(Self { _greet })
}
}
pub struct StateService {
_travel: Lifeline,
}
impl Service for StateService {
type Bus = StateBus;
type Lifeline = anyhow::Result<Self>;
fn spawn(bus: &Self::Bus) -> Self::Lifeline {
let mut rx = bus.rx::<TravelEvent>()?;
let mut tx = bus.tx::<SkyState>()?;
let _travel = Self::try_task("travel", async move {
let mut state = SkyState::default();
while let Some(update) = rx.recv().await {
state.location = update.0;
match state.location {
crate::state::LocationState::None => state.weather = WeatherState::None,
crate::state::LocationState::Boston => {
state.weather = WeatherState::Snowing
}
crate::state::LocationState::SanDiego => {
state.weather = WeatherState::Sunny72Degrees
}
}
tx.send(state.clone()).await?;
}
Ok(())
});
Ok(Self { _travel })
}
}
}