use std::collections::HashMap;
use ahp_types::actions::ActionEnvelope;
use ahp_types::common::ROOT_RESOURCE_URI;
use ahp_types::state::{
AnnotationsState, ChangesetState, ChatState, ResourceWatchState, RootState, SessionState,
SnapshotState, TerminalState,
};
use crate::hosts::{HostId, HostSubscriptionEvent};
use crate::reducers::{
apply_action_to_chat, apply_action_to_root, apply_action_to_session, apply_action_to_terminal,
};
use crate::SubscriptionEvent;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct HostedResourceKey {
pub host_id: HostId,
pub uri: String,
}
impl HostedResourceKey {
pub fn new(host_id: HostId, uri: impl Into<String>) -> Self {
Self {
host_id,
uri: uri.into(),
}
}
}
#[derive(Debug, Default)]
pub struct MultiHostStateMirror {
root_states: HashMap<HostId, RootState>,
sessions: HashMap<HostedResourceKey, SessionState>,
chats: HashMap<HostedResourceKey, ChatState>,
terminals: HashMap<HostedResourceKey, TerminalState>,
changesets: HashMap<HostedResourceKey, ChangesetState>,
annotations: HashMap<HostedResourceKey, AnnotationsState>,
resource_watches: HashMap<HostedResourceKey, ResourceWatchState>,
}
impl MultiHostStateMirror {
pub fn new() -> Self {
Self::default()
}
pub fn root_states(&self) -> &HashMap<HostId, RootState> {
&self.root_states
}
pub fn sessions(&self) -> &HashMap<HostedResourceKey, SessionState> {
&self.sessions
}
pub fn chats(&self) -> &HashMap<HostedResourceKey, ChatState> {
&self.chats
}
pub fn terminals(&self) -> &HashMap<HostedResourceKey, TerminalState> {
&self.terminals
}
pub fn changesets(&self) -> &HashMap<HostedResourceKey, ChangesetState> {
&self.changesets
}
pub fn annotations(&self) -> &HashMap<HostedResourceKey, AnnotationsState> {
&self.annotations
}
pub fn resource_watches(&self) -> &HashMap<HostedResourceKey, ResourceWatchState> {
&self.resource_watches
}
pub fn apply_event(&mut self, event: &HostSubscriptionEvent) {
if let SubscriptionEvent::Action(envelope) = &event.event {
self.apply_envelope(&event.host_id, envelope);
}
}
pub fn apply_envelope(&mut self, host: &HostId, envelope: &ActionEnvelope) {
if envelope.channel == ROOT_RESOURCE_URI {
let root = self
.root_states
.entry(host.clone())
.or_insert_with(|| RootState {
agents: vec![],
active_sessions: None,
terminals: None,
config: None,
meta: None,
});
apply_action_to_root(root, &envelope.action);
return;
}
let key = HostedResourceKey::new(host.clone(), envelope.channel.clone());
if let Some(session) = self.sessions.get_mut(&key) {
apply_action_to_session(session, &envelope.action);
return;
}
if let Some(chat) = self.chats.get_mut(&key) {
apply_action_to_chat(chat, &envelope.action);
return;
}
if let Some(terminal) = self.terminals.get_mut(&key) {
apply_action_to_terminal(terminal, &envelope.action);
}
}
pub fn apply_snapshot(&mut self, host: &HostId, snapshot: &ahp_types::state::Snapshot) {
let key = HostedResourceKey::new(host.clone(), snapshot.resource.clone());
match &snapshot.state {
SnapshotState::Root(state) => {
self.root_states
.insert(host.clone(), state.as_ref().clone());
}
SnapshotState::Session(state) => {
self.sessions.insert(key, state.as_ref().clone());
}
SnapshotState::Chat(state) => {
self.chats.insert(key, state.as_ref().clone());
}
SnapshotState::Terminal(state) => {
self.terminals.insert(key, state.as_ref().clone());
}
SnapshotState::Changeset(state) => {
self.changesets.insert(key, state.as_ref().clone());
}
SnapshotState::ResourceWatch(state) => {
self.resource_watches.insert(key, state.as_ref().clone());
}
SnapshotState::Annotations(state) => {
self.annotations.insert(key, state.as_ref().clone());
}
}
}
pub fn reset_host(&mut self, host: &HostId) {
self.root_states.remove(host);
self.sessions.retain(|key, _| &key.host_id != host);
self.chats.retain(|key, _| &key.host_id != host);
self.terminals.retain(|key, _| &key.host_id != host);
self.changesets.retain(|key, _| &key.host_id != host);
self.annotations.retain(|key, _| &key.host_id != host);
self.resource_watches.retain(|key, _| &key.host_id != host);
}
pub fn reset(&mut self) {
self.root_states.clear();
self.sessions.clear();
self.chats.clear();
self.terminals.clear();
self.changesets.clear();
self.annotations.clear();
self.resource_watches.clear();
}
}