codemp/src/server/actor/state.rs

105 lines
2.4 KiB
Rust

use std::{collections::HashMap, sync::Arc, fmt::Display};
use tokio::sync::{mpsc, watch};
use tracing::error;
use crate::actor::workspace::Workspace;
#[derive(Debug)]
enum WorkspaceAction {
ADD {
key: String,
w: Box<Workspace>,
},
REMOVE {
key: String
},
}
#[derive(Debug, Clone)]
pub struct WorkspacesView {
watch: watch::Receiver<HashMap<String, Arc<Workspace>>>,
op: mpsc::Sender<WorkspaceAction>,
}
impl WorkspacesView {
pub fn borrow(&self) -> watch::Ref<HashMap<String, Arc<Workspace>>> {
self.watch.borrow()
}
pub async fn add(&mut self, w: Workspace) {
self.op.send(WorkspaceAction::ADD { key: w.id.to_string(), w: Box::new(w) }).await.unwrap();
}
pub async fn remove(&mut self, key: String) {
self.op.send(WorkspaceAction::REMOVE { key }).await.unwrap();
}
}
#[derive(Debug)]
pub struct StateManager {
pub workspaces: WorkspacesView,
pub run: watch::Receiver<bool>,
run_tx: watch::Sender<bool>,
}
impl Drop for StateManager {
fn drop(&mut self) {
self.run_tx.send(false).unwrap_or_else(|e| {
error!("Could not stop StateManager worker: {:?}", e);
})
}
}
impl StateManager {
pub fn new() -> Self {
let (tx, rx) = mpsc::channel(32); // TODO quantify backpressure
let (workspaces_tx, workspaces_rx) = watch::channel(HashMap::new());
let (run_tx, run_rx) = watch::channel(true);
let s = StateManager {
workspaces: WorkspacesView { watch: workspaces_rx, op: tx },
run_tx, run: run_rx,
};
s.workspaces_worker(rx, workspaces_tx);
return s;
}
fn workspaces_worker(&self, mut rx: mpsc::Receiver<WorkspaceAction>, tx: watch::Sender<HashMap<String, Arc<Workspace>>>) {
let run = self.run.clone();
tokio::spawn(async move {
let mut store = HashMap::new();
while run.borrow().to_owned() {
if let Some(event) = rx.recv().await {
match event {
WorkspaceAction::ADD { key, w } => {
store.insert(key, Arc::new(*w)); // TODO put in hashmap
},
WorkspaceAction::REMOVE { key } => {
store.remove(&key);
},
}
tx.send(store.clone()).unwrap();
} else {
break
}
}
});
}
pub fn view(&self) -> WorkspacesView {
return self.workspaces.clone();
}
/// get a workspace Arc directly, without passing by the WorkspacesView
pub fn get(&self, key: &String) -> Option<Arc<Workspace>> {
if let Some(w) = self.workspaces.borrow().get(key) {
return Some(w.clone());
}
return None;
}
}