use crate::{message::tab_assignment::AssignTab, prelude::*};
use crate::{
message::{
tab::TabRecv,
tab_manager::{TabManagerRecv, TabManagerSend},
},
state::tab::TabsState,
};
use anyhow::Context;
use std::{
collections::HashMap,
sync::atomic::{AtomicUsize, Ordering},
};
use tab_api::tab::{TabId, TabMetadata};
pub struct TabManagerService {
_recv: Lifeline,
}
static TAB_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
impl Service for TabManagerService {
type Bus = ListenerBus;
type Lifeline = anyhow::Result<Self>;
fn spawn(bus: &Self::Bus) -> Self::Lifeline {
let _recv = {
let mut rx = bus.rx::<TabManagerRecv>()?;
let mut tx = bus.tx::<TabManagerSend>()?;
let mut tx_tabs = bus.tx::<TabRecv>()?;
let mut tx_tabs_state = bus.tx::<TabsState>()?;
let mut tx_assign_tab = bus.tx::<AssignTab>()?;
let mut tabs: HashMap<TabId, TabMetadata> = HashMap::new();
Self::try_task("recv", async move {
'msg: while let Some(msg) = rx.recv().await {
match msg {
TabManagerRecv::CreateTab(create) => {
for tab in tabs.values() {
if tab.name == create.name {
continue 'msg;
}
}
debug!("recieved request to create tab {}", &create.name);
let id = TAB_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16;
let tab_id = TabId(id);
let tab_metadata = TabMetadata::create(tab_id, create);
tx_assign_tab.send(AssignTab(tab_metadata.clone())).await?;
tabs.insert(tab_id, tab_metadata);
tx_tabs_state.send(TabsState::new(&tabs)).await?;
}
TabManagerRecv::CloseTab(close) => {
Self::close_tab(
close,
&mut tabs,
&mut tx,
&mut tx_tabs,
&mut tx_tabs_state,
)
.await?;
}
}
}
Ok(())
})
};
Ok(Self { _recv })
}
}
impl TabManagerService {
async fn close_tab(
id: TabId,
tabs: &mut HashMap<TabId, TabMetadata>,
tx: &mut impl Sender<TabManagerSend>,
tx_close: &mut impl Sender<TabRecv>,
tx_tabs_state: &mut impl Sender<TabsState>,
) -> anyhow::Result<()> {
info!("TabManager terminating tab {}", id);
tabs.remove(&id);
tx.send(TabManagerSend::TabTerminated(id))
.await
.context("tx TabTerminated")
.ok();
tx_close.send(TabRecv::Terminate(id)).await.ok();
tx_tabs_state
.send(TabsState::new(&tabs))
.await
.context("tx_tabs_state TabsState")
.ok();
Ok(())
}
}