feat: moved state managers under 'actor' dir

Since we're building (sort of) around the actor model, might
as well sort stuff that way.
This commit is contained in:
əlemi 2022-07-31 13:46:21 +02:00
parent 83ae6e3cd1
commit 8316439a3e
5 changed files with 139 additions and 140 deletions

View file

@ -0,0 +1,64 @@
use operational_transform::OperationSeq;
use tokio::sync::{broadcast, mpsc, watch};
use tracing::error;
#[derive(Debug, Clone)]
pub struct BufferView {
pub name: String,
pub content: watch::Receiver<String>,
op_tx: mpsc::Sender<OperationSeq>,
}
impl BufferView {
pub async fn op(&self, op: OperationSeq) -> Result<(), mpsc::error::SendError<OperationSeq>> {
self.op_tx.send(op).await
}
}
#[derive(Debug)]
pub struct Buffer {
view: BufferView,
run: watch::Sender<bool>,
}
impl Drop for Buffer {
fn drop(&mut self) {
self.run.send(false).unwrap_or_else(|e| {
error!("Could not stop Buffer worker task: {:?}", e);
});
}
}
impl Buffer {
pub fn new(name: String, bus: broadcast::Sender<(String, OperationSeq)>) -> Self {
let (op_tx, mut op_rx) = mpsc::channel(32);
let (stop_tx, stop_rx) = watch::channel(true);
let (content_tx, content_rx) = watch::channel(String::new());
let b = Buffer {
run: stop_tx,
view: BufferView {
name: name.clone(),
op_tx,
content: content_rx,
},
};
tokio::spawn(async move {
let mut content = String::new();
while stop_rx.borrow().to_owned() {
// TODO handle these errors!!
let op = op_rx.recv().await.unwrap();
content = op.apply(content.as_str()).unwrap();
bus.send((name.clone(), op)).unwrap(); // TODO fails when there are no receivers subscribed
content_tx.send(content.clone()).unwrap();
}
});
return b;
}
pub fn view(&self) -> BufferView {
return self.view.clone();
}
}

3
src/server/actor/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod buffer;
pub mod workspace;
pub mod state;

View file

@ -3,7 +3,7 @@ use std::{collections::HashMap, sync::Arc};
use tokio::sync::{mpsc, watch};
use tracing::error;
use crate::workspace::Workspace;
use crate::actor::workspace::Workspace;
#[derive(Debug)]
pub enum AlterState {

View file

@ -0,0 +1,71 @@
use std::collections::HashMap;
use operational_transform::OperationSeq;
use tokio::sync::{broadcast, mpsc, watch};
use super::buffer::{BufferView, Buffer};
pub struct WorkspaceView {
pub rx: broadcast::Receiver<OperationSeq>,
pub tx: mpsc::Sender<OperationSeq>,
}
// Must be clonable, containing references to the actual state maybe? Or maybe give everyone an Arc, idk
#[derive(Debug)]
pub struct Workspace {
pub name: String,
pub buffers: watch::Receiver<HashMap<String, BufferView>>,
pub bus: broadcast::Sender<(String, OperationSeq)>,
op_tx: mpsc::Sender<BufferAction>,
run: watch::Sender<bool>,
}
impl Workspace {
pub fn new(name: String) -> Self {
let (op_tx, mut op_rx) = mpsc::channel(32);
let (stop_tx, stop_rx) = watch::channel(true);
let (buf_tx, buf_rx) = watch::channel(HashMap::new());
let (broadcast_tx, broadcast_rx) = broadcast::channel(32);
let w = Workspace {
name,
run: stop_tx,
op_tx,
buffers: buf_rx,
bus: broadcast_tx,
};
tokio::spawn(async move {
let mut buffers = HashMap::new();
while stop_rx.borrow().to_owned() {
// TODO handle these errors!!
let action = op_rx.recv().await.unwrap();
match action {
BufferAction::ADD { buffer } => {
buffers.insert(buffer.view().name.clone(), buffer);
}
BufferAction::REMOVE { name } => {
buffers.remove(&name);
}
}
buf_tx.send(
buffers.iter()
.map(|(k, v)| (k.clone(), v.view()))
.collect()
).unwrap();
}
});
return w;
}
}
pub enum BufferAction {
ADD {
buffer: Buffer,
},
REMOVE {
name: String, // TODO remove by id?
},
}

View file

@ -1,139 +0,0 @@
use std::collections::HashMap;
use operational_transform::OperationSeq;
use tokio::sync::{broadcast, mpsc, watch};
use tracing::error;
#[derive(Debug, Clone)]
pub struct BufferView {
pub name: String,
pub content: watch::Receiver<String>,
op_tx: mpsc::Sender<OperationSeq>,
}
impl BufferView {
pub async fn op(&self, op: OperationSeq) -> Result<(), mpsc::error::SendError<OperationSeq>> {
self.op_tx.send(op).await
}
}
#[derive(Debug)]
pub struct Buffer {
view: BufferView,
run: watch::Sender<bool>,
}
impl Drop for Buffer {
fn drop(&mut self) {
self.run.send(false).unwrap_or_else(|e| {
error!("Could not stop Buffer worker task: {:?}", e);
});
}
}
impl Buffer {
pub fn new(name: String, bus: broadcast::Sender<(String, OperationSeq)>) -> Self {
let (op_tx, mut op_rx) = mpsc::channel(32);
let (stop_tx, stop_rx) = watch::channel(true);
let (content_tx, content_rx) = watch::channel(String::new());
let b = Buffer {
run: stop_tx,
view: BufferView {
name: name.clone(),
op_tx,
content: content_rx,
},
};
tokio::spawn(async move {
let mut content = String::new();
while stop_rx.borrow().to_owned() {
// TODO handle these errors!!
let op = op_rx.recv().await.unwrap();
content = op.apply(content.as_str()).unwrap();
bus.send((name.clone(), op)).unwrap(); // TODO fails when there are no receivers subscribed
content_tx.send(content.clone()).unwrap();
}
});
return b;
}
pub fn view(&self) -> BufferView {
return self.view.clone();
}
}
pub struct WorkspaceView {
pub rx: broadcast::Receiver<OperationSeq>,
pub tx: mpsc::Sender<OperationSeq>,
}
// Must be clonable, containing references to the actual state maybe? Or maybe give everyone an Arc, idk
#[derive(Debug)]
pub struct Workspace {
pub name: String,
pub buffers: watch::Receiver<HashMap<String, BufferView>>,
pub bus: broadcast::Sender<(String, OperationSeq)>,
op_tx: mpsc::Sender<BufferAction>,
run: watch::Sender<bool>,
}
impl Workspace {
pub fn new(name: String) -> Self {
let (op_tx, mut op_rx) = mpsc::channel(32);
let (stop_tx, stop_rx) = watch::channel(true);
let (buf_tx, buf_rx) = watch::channel(HashMap::new());
let (broadcast_tx, broadcast_rx) = broadcast::channel(32);
let w = Workspace {
name,
run: stop_tx,
op_tx,
buffers: buf_rx,
bus: broadcast_tx,
};
tokio::spawn(async move {
let mut buffers = HashMap::new();
while stop_rx.borrow().to_owned() {
// TODO handle these errors!!
let action = op_rx.recv().await.unwrap();
match action {
BufferAction::ADD { buffer } => {
buffers.insert(buffer.view.name.clone(), buffer);
}
BufferAction::REMOVE { name } => {
buffers.remove(&name);
}
}
buf_tx.send(
buffers.iter()
.map(|(k, v)| (k.clone(), v.view()))
.collect()
).unwrap();
}
});
return w;
}
}
pub enum BufferAction {
ADD {
buffer: Buffer,
},
REMOVE {
name: String, // TODO remove by id?
},
}
// impl Default for Workspace {
// fn default() -> Self {
// Workspace {
// name: "fuck you".to_string(),
// content: "too".to_string(),
// }
// }
// }