2023-08-20 00:46:55 +02:00
|
|
|
//! ### controller
|
2024-08-05 22:44:46 +02:00
|
|
|
//!
|
2023-08-20 00:46:55 +02:00
|
|
|
//! a controller implementation for buffer actions
|
|
|
|
|
2023-11-09 05:21:24 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2024-08-13 00:36:09 +02:00
|
|
|
use diamond_types::LocalVersion;
|
2024-08-13 18:03:20 +02:00
|
|
|
use tokio::sync::{oneshot, Mutex};
|
2024-08-05 22:44:46 +02:00
|
|
|
use tokio::sync::{mpsc, watch};
|
2023-08-16 23:09:47 +02:00
|
|
|
use tonic::async_trait;
|
2023-08-11 15:33:40 +02:00
|
|
|
|
2023-11-17 05:47:57 +01:00
|
|
|
use crate::api::Controller;
|
2023-08-16 23:09:47 +02:00
|
|
|
|
2023-11-17 05:45:31 +01:00
|
|
|
use crate::api::TextChange;
|
2023-08-11 15:33:40 +02:00
|
|
|
|
2024-08-13 00:36:09 +02:00
|
|
|
use crate::api::Op;
|
|
|
|
|
2024-08-10 16:13:16 +02:00
|
|
|
use crate::ext::InternallyMutable;
|
2024-08-08 00:27:24 +02:00
|
|
|
|
2023-08-20 00:46:55 +02:00
|
|
|
/// the buffer controller implementation
|
|
|
|
///
|
|
|
|
/// for each controller a worker exists, managing outgoing and inbound
|
2024-08-05 22:44:46 +02:00
|
|
|
/// queues, transforming outbound delayed ops and applying remote changes
|
2023-08-20 00:46:55 +02:00
|
|
|
/// to the local buffer
|
|
|
|
///
|
|
|
|
/// upon dropping this handle will stop the associated worker
|
2023-11-09 05:21:24 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2024-08-05 22:44:46 +02:00
|
|
|
#[cfg_attr(feature = "python", pyo3::pyclass)]
|
2024-08-07 23:06:33 +02:00
|
|
|
#[cfg_attr(feature = "js", napi_derive::napi)]
|
2024-08-08 00:28:15 +02:00
|
|
|
pub struct BufferController(pub(crate) Arc<BufferControllerInner>);
|
|
|
|
|
|
|
|
impl BufferController {
|
|
|
|
/// unique identifier of buffer
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
&self.0.name
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return buffer whole content, updating internal buffer previous state
|
2024-08-13 18:03:20 +02:00
|
|
|
pub async fn content(&self) -> crate::Result<String> {
|
|
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
self.0.content_request.send(tx).await?;
|
|
|
|
Ok(rx.await?)
|
2024-08-08 00:28:15 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-05 19:13:48 +02:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2024-08-08 00:28:15 +02:00
|
|
|
pub(crate) struct BufferControllerInner {
|
2023-11-30 03:41:53 +01:00
|
|
|
name: String,
|
2024-08-13 00:36:09 +02:00
|
|
|
latest_version: watch::Receiver<diamond_types::LocalVersion>,
|
|
|
|
last_update: InternallyMutable<diamond_types::LocalVersion>,
|
|
|
|
ops_in: mpsc::UnboundedSender<TextChange>,
|
2024-08-13 18:03:20 +02:00
|
|
|
ops_out: Mutex<mpsc::UnboundedReceiver<(LocalVersion, Option<Op>)>>,
|
2023-11-30 03:03:09 +01:00
|
|
|
poller: mpsc::UnboundedSender<oneshot::Sender<()>>,
|
2024-08-08 00:28:15 +02:00
|
|
|
stopper: mpsc::UnboundedSender<()>, // just exist
|
2024-08-13 18:03:20 +02:00
|
|
|
content_request: mpsc::Sender<oneshot::Sender<String>>,
|
2023-07-09 03:44:27 +02:00
|
|
|
}
|
|
|
|
|
2024-08-08 00:28:15 +02:00
|
|
|
impl BufferControllerInner {
|
2023-08-17 00:04:37 +02:00
|
|
|
pub(crate) fn new(
|
2023-11-17 17:38:47 +01:00
|
|
|
name: String,
|
2024-08-13 00:36:09 +02:00
|
|
|
latest_version: watch::Receiver<diamond_types::LocalVersion>,
|
|
|
|
ops_in: mpsc::UnboundedSender<TextChange>,
|
|
|
|
ops_out: mpsc::UnboundedReceiver<(LocalVersion, Option<Op>)>,
|
2023-11-30 03:03:09 +01:00
|
|
|
poller: mpsc::UnboundedSender<oneshot::Sender<()>>,
|
2024-08-13 00:36:09 +02:00
|
|
|
stopper: mpsc::UnboundedSender<()>,
|
2024-08-13 18:03:20 +02:00
|
|
|
content_request: mpsc::Sender<oneshot::Sender<String>>,
|
|
|
|
// TODO we're getting too much stuff via constructor, maybe make everything pub(crate)
|
|
|
|
// instead?? or maybe builder, or maybe defaults
|
2023-08-17 00:04:37 +02:00
|
|
|
) -> Self {
|
2024-08-08 00:28:15 +02:00
|
|
|
Self {
|
2024-08-05 22:44:46 +02:00
|
|
|
name,
|
2024-08-13 00:36:09 +02:00
|
|
|
latest_version,
|
|
|
|
last_update: InternallyMutable::new(diamond_types::LocalVersion::default()),
|
|
|
|
ops_in,
|
2024-08-13 18:03:20 +02:00
|
|
|
ops_out: Mutex::new(ops_out),
|
2024-08-05 22:44:46 +02:00
|
|
|
poller,
|
2024-08-13 00:36:09 +02:00
|
|
|
stopper,
|
2024-08-13 18:03:20 +02:00
|
|
|
content_request,
|
2024-08-08 00:28:15 +02:00
|
|
|
}
|
2023-08-17 00:04:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-16 23:09:47 +02:00
|
|
|
#[async_trait]
|
2023-11-16 06:52:25 +01:00
|
|
|
impl Controller<TextChange> for BufferController {
|
2023-11-30 03:41:53 +01:00
|
|
|
/// block until a text change is available
|
|
|
|
/// this returns immediately if one is already available
|
2023-11-17 05:47:57 +01:00
|
|
|
async fn poll(&self) -> crate::Result<()> {
|
2024-08-13 00:36:09 +02:00
|
|
|
// TODO there might be some extra logic we can play with using `seen` and `not seen` yet
|
|
|
|
// mechanics, not just the comparison. nevermind, the `has_changed` etc stuff needs mut self, yuk.
|
|
|
|
|
|
|
|
if self.0.last_update.get() != *self.0.latest_version.borrow() {
|
|
|
|
return Ok(());
|
2023-11-30 03:03:09 +01:00
|
|
|
}
|
2024-08-13 00:36:09 +02:00
|
|
|
|
2023-11-23 15:52:36 +01:00
|
|
|
let (tx, rx) = oneshot::channel::<()>();
|
2024-08-05 19:13:48 +02:00
|
|
|
self.0.poller.send(tx)?;
|
2024-08-05 22:44:46 +02:00
|
|
|
rx.await
|
|
|
|
.map_err(|_| crate::Error::Channel { send: false })?;
|
2023-11-30 03:03:09 +01:00
|
|
|
Ok(())
|
2023-08-21 02:35:56 +02:00
|
|
|
}
|
|
|
|
|
2023-11-30 03:41:53 +01:00
|
|
|
/// if a text change is available, return it immediately
|
2023-11-17 05:47:57 +01:00
|
|
|
fn try_recv(&self) -> crate::Result<Option<TextChange>> {
|
2024-08-13 00:36:09 +02:00
|
|
|
let last_update = self.0.last_update.get();
|
|
|
|
let latest_version = self.0.latest_version.borrow().clone();
|
|
|
|
|
|
|
|
if last_update == latest_version {
|
2023-11-17 18:38:29 +01:00
|
|
|
return Ok(None);
|
2023-11-16 06:52:25 +01:00
|
|
|
}
|
2024-08-13 00:36:09 +02:00
|
|
|
|
2024-08-13 18:03:20 +02:00
|
|
|
match self.0.ops_out.try_lock() {
|
|
|
|
Err(_) => Ok(None),
|
|
|
|
Ok(mut ops) => match ops.try_recv() {
|
|
|
|
Ok((lv, Some(op))) => {
|
|
|
|
self.0.last_update.set(lv);
|
|
|
|
Ok(Some(TextChange::from(op)))
|
|
|
|
},
|
|
|
|
Ok((_lv, None)) => Ok(None), // TODO what is going on here?
|
|
|
|
Err(mpsc::error::TryRecvError::Empty) => Ok(None),
|
|
|
|
Err(mpsc::error::TryRecvError::Disconnected) =>
|
|
|
|
Err(crate::Error::Channel { send: false }),
|
|
|
|
},
|
2024-08-13 00:36:09 +02:00
|
|
|
}
|
2023-08-21 02:35:56 +02:00
|
|
|
}
|
|
|
|
|
2023-11-30 03:41:53 +01:00
|
|
|
/// block until a new text change is available, and return it
|
2023-11-17 05:47:57 +01:00
|
|
|
async fn recv(&self) -> crate::Result<TextChange> {
|
2024-08-13 18:03:20 +02:00
|
|
|
if let Some((lv, Some(op))) = self.0.ops_out.lock().await.recv().await {
|
2024-08-13 00:36:09 +02:00
|
|
|
self.0.last_update.set(lv);
|
|
|
|
Ok(TextChange::from(op))
|
|
|
|
} else {
|
|
|
|
Err(crate::Error::Channel { send: false })
|
|
|
|
}
|
2023-07-09 03:44:27 +02:00
|
|
|
}
|
|
|
|
|
2023-11-30 03:41:53 +01:00
|
|
|
/// enqueue a text change for processing
|
|
|
|
/// this also updates internal buffer previous state
|
2023-11-17 05:47:57 +01:00
|
|
|
fn send(&self, op: TextChange) -> crate::Result<()> {
|
2024-08-13 00:36:09 +02:00
|
|
|
// we let the worker do the updating to the last version and send it back.
|
|
|
|
Ok(self.0.ops_in.send(op)?)
|
2023-07-09 03:44:27 +02:00
|
|
|
}
|
2023-11-30 03:03:09 +01:00
|
|
|
|
2024-08-08 00:28:15 +02:00
|
|
|
fn stop(&self) -> bool {
|
|
|
|
self.0.stopper.send(()).is_ok()
|
2023-11-30 03:03:09 +01:00
|
|
|
}
|
|
|
|
}
|