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 cursor actions
|
2024-08-05 19:13:48 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2024-08-05 22:44:46 +02:00
|
|
|
use tokio::sync::{
|
|
|
|
broadcast::{
|
|
|
|
self,
|
|
|
|
error::{RecvError, TryRecvError},
|
|
|
|
},
|
|
|
|
mpsc, watch, Mutex,
|
|
|
|
};
|
2023-08-16 23:09:47 +02:00
|
|
|
use tonic::async_trait;
|
|
|
|
|
2024-08-08 00:28:15 +02:00
|
|
|
use crate::api::{Controller, Cursor};
|
2024-03-09 19:59:36 +01:00
|
|
|
use codemp_proto::cursor::{CursorEvent, CursorPosition};
|
2023-08-20 00:46:55 +02:00
|
|
|
/// the cursor controller implementation
|
|
|
|
///
|
|
|
|
/// this contains
|
|
|
|
/// * the unique identifier of current user
|
|
|
|
/// * a sink to send movements into
|
|
|
|
/// * a mutex over a stream of inbound cursor events
|
|
|
|
/// * a channel to stop the associated worker
|
|
|
|
///
|
2024-08-05 22:44:46 +02:00
|
|
|
/// for each controller a worker exists , managing outgoing and inbound event queues
|
2023-08-20 00:46:55 +02:00
|
|
|
///
|
|
|
|
/// upon dropping this handle will stop the associated worker
|
2024-08-05 19:13:48 +02: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-05 19:13:48 +02:00
|
|
|
pub struct CursorController(Arc<CursorControllerInner>);
|
|
|
|
|
2023-08-21 02:47:52 +02:00
|
|
|
#[derive(Debug)]
|
2024-08-05 19:13:48 +02:00
|
|
|
struct CursorControllerInner {
|
2024-02-07 01:09:28 +01:00
|
|
|
op: mpsc::UnboundedSender<CursorPosition>,
|
2023-08-21 02:35:56 +02:00
|
|
|
last_op: Mutex<watch::Receiver<CursorEvent>>,
|
2023-08-16 23:09:47 +02:00
|
|
|
stream: Mutex<broadcast::Receiver<CursorEvent>>,
|
2023-08-19 04:02:21 +02:00
|
|
|
stop: mpsc::UnboundedSender<()>,
|
|
|
|
}
|
|
|
|
|
2023-08-17 00:04:37 +02:00
|
|
|
impl CursorController {
|
|
|
|
pub(crate) fn new(
|
2024-02-07 01:09:28 +01:00
|
|
|
op: mpsc::UnboundedSender<CursorPosition>,
|
2023-08-21 02:35:56 +02:00
|
|
|
last_op: Mutex<watch::Receiver<CursorEvent>>,
|
2023-08-19 04:02:21 +02:00
|
|
|
stream: Mutex<broadcast::Receiver<CursorEvent>>,
|
|
|
|
stop: mpsc::UnboundedSender<()>,
|
2023-08-17 00:04:37 +02:00
|
|
|
) -> Self {
|
2024-08-05 22:44:46 +02:00
|
|
|
Self(Arc::new(CursorControllerInner {
|
|
|
|
op,
|
|
|
|
last_op,
|
|
|
|
stream,
|
|
|
|
stop,
|
|
|
|
}))
|
2023-08-17 00:04:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-16 23:09:47 +02:00
|
|
|
#[async_trait]
|
2024-08-05 19:13:48 +02:00
|
|
|
impl Controller<Cursor> for CursorController {
|
2023-08-20 00:46:55 +02:00
|
|
|
/// enqueue a cursor event to be broadcast to current workspace
|
2023-09-10 23:20:07 +02:00
|
|
|
/// will automatically invert cursor start/end if they are inverted
|
2024-08-05 19:13:48 +02:00
|
|
|
fn send(&self, mut cursor: Cursor) -> crate::Result<()> {
|
2024-01-25 03:25:45 +01:00
|
|
|
if cursor.start > cursor.end {
|
2023-09-10 23:20:07 +02:00
|
|
|
std::mem::swap(&mut cursor.start, &mut cursor.end);
|
|
|
|
}
|
2024-08-05 19:13:48 +02:00
|
|
|
Ok(self.0.op.send(cursor.into())?)
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
|
2023-08-21 02:35:56 +02:00
|
|
|
/// try to receive without blocking, but will still block on stream mutex
|
2024-08-05 19:13:48 +02:00
|
|
|
fn try_recv(&self) -> crate::Result<Option<Cursor>> {
|
|
|
|
let mut stream = self.0.stream.blocking_lock();
|
2023-08-21 02:35:56 +02:00
|
|
|
match stream.try_recv() {
|
2024-08-05 19:13:48 +02:00
|
|
|
Ok(x) => Ok(Some(x.into())),
|
2023-08-21 02:35:56 +02:00
|
|
|
Err(TryRecvError::Empty) => Ok(None),
|
2024-01-25 02:13:45 +01:00
|
|
|
Err(TryRecvError::Closed) => Err(crate::Error::Channel { send: false }),
|
2023-08-21 02:35:56 +02:00
|
|
|
Err(TryRecvError::Lagged(n)) => {
|
|
|
|
tracing::warn!("cursor channel lagged, skipping {} events", n);
|
2024-08-05 19:13:48 +02:00
|
|
|
Ok(stream.try_recv().map(|x| x.into()).ok())
|
2024-08-05 22:44:46 +02:00
|
|
|
}
|
2023-08-21 02:35:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-16 23:09:47 +02:00
|
|
|
// TODO is this cancelable? so it can be used in tokio::select!
|
|
|
|
// TODO is the result type overkill? should be an option?
|
2023-08-20 00:46:55 +02:00
|
|
|
/// get next cursor event from current workspace, or block until one is available
|
2024-08-05 19:13:48 +02:00
|
|
|
async fn recv(&self) -> crate::Result<Cursor> {
|
|
|
|
let mut stream = self.0.stream.lock().await;
|
2023-08-16 23:09:47 +02:00
|
|
|
match stream.recv().await {
|
2024-08-05 19:13:48 +02:00
|
|
|
Ok(x) => Ok(x.into()),
|
2024-01-25 02:13:45 +01:00
|
|
|
Err(RecvError::Closed) => Err(crate::Error::Channel { send: false }),
|
2023-08-16 23:09:47 +02:00
|
|
|
Err(RecvError::Lagged(n)) => {
|
|
|
|
tracing::error!("cursor channel lagged behind, skipping {} events", n);
|
2024-08-05 22:44:46 +02:00
|
|
|
Ok(stream
|
|
|
|
.recv()
|
|
|
|
.await
|
|
|
|
.expect("could not receive after lagging")
|
|
|
|
.into())
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-08-21 02:35:56 +02:00
|
|
|
|
|
|
|
/// await for changed mutex and then next op change
|
|
|
|
async fn poll(&self) -> crate::Result<()> {
|
2024-08-05 19:13:48 +02:00
|
|
|
Ok(self.0.last_op.lock().await.changed().await?)
|
2023-08-21 02:35:56 +02:00
|
|
|
}
|
2024-08-08 00:28:15 +02:00
|
|
|
|
|
|
|
fn stop(&self) -> bool {
|
|
|
|
self.0.stop.send(()).is_ok()
|
|
|
|
}
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|