use crate::args::RunArgs;
use crate::events::EventsDrainer;
use crate::launcher::{CommandEvent, CommandWatcher};
use crate::state::AppState;
use anyhow::Result;
use async_trait::async_trait;
use crb::agent::{Agent, Context, DoAsync, Next, OnEvent};
use crb::core::Slot;
use crb::superagent::{Interval, StreamSession, Supervisor, SupervisorSession, Tick};
use crossterm::event::{Event, KeyCode};
use ratatui::DefaultTerminal;
pub struct HubApp {
args: RunArgs,
terminal: Slot<DefaultTerminal>,
state: AppState,
interval: Interval,
}
impl HubApp {
pub fn new(args: RunArgs) -> Self {
Self {
args,
terminal: Slot::empty(),
state: AppState::new(),
interval: Interval::new(),
}
}
}
impl Supervisor for HubApp {
type BasedOn = StreamSession<Self>;
type GroupBy = ();
}
impl Agent for HubApp {
type Context = SupervisorSession<Self>;
fn begin(&mut self) -> Next<Self> {
Next::do_async(Configure)
}
}
struct Configure;
#[async_trait]
impl DoAsync<Configure> for HubApp {
async fn handle(&mut self, _: Configure, ctx: &mut Context<Self>) -> Result<Next<Self>> {
self.interval.set_interval_ms(100)?;
ctx.consume(self.interval.events()?);
let terminal = ratatui::try_init()?;
self.terminal.fill(terminal)?;
let drainer = EventsDrainer::new(&ctx);
ctx.spawn_agent(drainer, ());
let (watcher, _tx) = CommandWatcher::new(self.args.clone(), &ctx);
ctx.spawn_agent(watcher, ());
Ok(Next::events())
}
}
#[async_trait]
impl OnEvent<Event> for HubApp {
async fn handle(&mut self, event: Event, ctx: &mut Context<Self>) -> Result<()> {
match event {
Event::Key(event) => match event.code {
KeyCode::Char('q') => {
ctx.do_next(Next::do_async(Terminate));
}
_ => {}
},
_ => {}
};
Ok(())
}
}
#[async_trait]
impl OnEvent<CommandEvent> for HubApp {
async fn handle(&mut self, event: CommandEvent, _ctx: &mut Context<Self>) -> Result<()> {
match event {
CommandEvent::Stdout { key, value } => {
self.state.set(key, value);
}
CommandEvent::Terminated(_) => {
}
}
Ok(())
}
}
#[derive(Clone)]
struct Render;
#[async_trait]
impl OnEvent<Render> for HubApp {
async fn handle(&mut self, _: Render, _ctx: &mut Context<Self>) -> Result<()> {
let terminal = self.terminal.get_mut()?;
terminal.draw(|frame| {
self.state.render(frame);
})?;
Ok(())
}
}
struct Terminate;
#[async_trait]
impl DoAsync<Terminate> for HubApp {
async fn once(&mut self, _: &mut Terminate) -> Result<Next<Self>> {
ratatui::try_restore()?;
Ok(Next::done())
}
}
#[async_trait]
impl OnEvent<Tick> for HubApp {
async fn handle(&mut self, _: Tick, _ctx: &mut Context<Self>) -> Result<()> {
Ok(())
}
}