mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 15:24:48 +01:00
feat: experimental select_buffer client api
This commit is contained in:
parent
99ba5f708d
commit
8dc3538f32
3 changed files with 58 additions and 20 deletions
|
@ -25,6 +25,7 @@ serde_json = { version = "1", optional = true }
|
||||||
tokio-stream = { version = "0.1", optional = true }
|
tokio-stream = { version = "0.1", optional = true }
|
||||||
# global
|
# global
|
||||||
lazy_static = { version = "1.4", optional = true }
|
lazy_static = { version = "1.4", optional = true }
|
||||||
|
futures = "0.3"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = "0.9"
|
tonic-build = "0.9"
|
||||||
|
|
|
@ -3,10 +3,13 @@
|
||||||
//! codemp client manager, containing grpc services
|
//! codemp client manager, containing grpc services
|
||||||
|
|
||||||
use std::{sync::Arc, collections::BTreeMap};
|
use std::{sync::Arc, collections::BTreeMap};
|
||||||
|
use futures::stream::FuturesUnordered;
|
||||||
|
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
use tonic::transport::Channel;
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
api::Controller,
|
||||||
cursor::{worker::CursorControllerWorker, controller::CursorController},
|
cursor::{worker::CursorControllerWorker, controller::CursorController},
|
||||||
proto::{
|
proto::{
|
||||||
buffer_client::BufferClient, cursor_client::CursorClient, UserIdentity, BufferPayload,
|
buffer_client::BufferClient, cursor_client::CursorClient, UserIdentity, BufferPayload,
|
||||||
|
@ -76,7 +79,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// to interact with such workspace [crate::api::Controller::send] cursor events or
|
/// to interact with such workspace [crate::api::Controller::send] cursor events or
|
||||||
/// [crate::api::Controller::recv] for events on the associated [crate::cursor::Controller].
|
/// [crate::api::Controller::recv] for events on the associated [crate::cursor::Controller].
|
||||||
pub async fn join(&mut self, _session: &str) -> Result<Arc<CursorController>, Error> {
|
pub async fn join(&mut self, _session: &str) -> crate::Result<Arc<CursorController>> {
|
||||||
// TODO there is no real workspace handling in codemp server so it behaves like one big global
|
// TODO there is no real workspace handling in codemp server so it behaves like one big global
|
||||||
// session. I'm still creating this to start laying out the proper use flow
|
// session. I'm still creating this to start laying out the proper use flow
|
||||||
let stream = self.client.cursor.listen(UserIdentity { id: "".into() }).await?.into_inner();
|
let stream = self.client.cursor.listen(UserIdentity { id: "".into() }).await?.into_inner();
|
||||||
|
@ -103,7 +106,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// create a new buffer in current workspace, with optional given content
|
/// create a new buffer in current workspace, with optional given content
|
||||||
pub async fn create(&mut self, path: &str, content: Option<&str>) -> Result<(), Error> {
|
pub async fn create(&mut self, path: &str, content: Option<&str>) -> crate::Result<()> {
|
||||||
if let Some(_workspace) = &self.workspace {
|
if let Some(_workspace) = &self.workspace {
|
||||||
self.client.buffer
|
self.client.buffer
|
||||||
.create(BufferPayload {
|
.create(BufferPayload {
|
||||||
|
@ -122,7 +125,7 @@ impl Client {
|
||||||
///
|
///
|
||||||
/// to interact with such buffer use [crate::api::Controller::send] or
|
/// to interact with such buffer use [crate::api::Controller::send] or
|
||||||
/// [crate::api::Controller::recv] to exchange [crate::api::TextChange]
|
/// [crate::api::Controller::recv] to exchange [crate::api::TextChange]
|
||||||
pub async fn attach(&mut self, path: &str) -> Result<Arc<BufferController>, Error> {
|
pub async fn attach(&mut self, path: &str) -> crate::Result<Arc<BufferController>> {
|
||||||
if let Some(workspace) = &mut self.workspace {
|
if let Some(workspace) = &mut self.workspace {
|
||||||
let mut client = self.client.buffer.clone();
|
let mut client = self.client.buffer.clone();
|
||||||
let req = BufferPayload {
|
let req = BufferPayload {
|
||||||
|
@ -148,4 +151,24 @@ impl Client {
|
||||||
Err(Error::InvalidState { msg: "join a workspace first".into() })
|
Err(Error::InvalidState { msg: "join a workspace first".into() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn select_buffer(&self) -> crate::Result<String> {
|
||||||
|
let mut futures = FuturesUnordered::new();
|
||||||
|
match &self.workspace {
|
||||||
|
None => Err(Error::InvalidState { msg: "join workspace first".into() }),
|
||||||
|
Some(workspace) => {
|
||||||
|
for (id, buffer) in workspace.buffers.iter() {
|
||||||
|
futures.push(async move {
|
||||||
|
buffer.poll().await?;
|
||||||
|
Ok::<&String, Error>(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
match futures.next().await {
|
||||||
|
None => Err(Error::Deadlocked), // TODO shouldn't really happen???
|
||||||
|
Some(x) => Ok(x?.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,13 +46,13 @@ pub mod a_sync {
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
/// connect to remote address instantiating a new client [crate::client::Client::new]
|
/// connect to remote address instantiating a new client [crate::client::Client::new]
|
||||||
pub async fn connect(&self, addr: &str) -> Result<(), Error> {
|
pub async fn connect(&self, addr: &str) -> crate::Result<()> {
|
||||||
*self.client.lock().await = Some(Client::new(addr).await?);
|
*self.client.lock().await = Some(Client::new(addr).await?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::join]
|
/// threadsafe version of [crate::client::Client::join]
|
||||||
pub async fn join(&self, session: &str) -> Result<Arc<CursorController>, Error> {
|
pub async fn join(&self, session: &str) -> crate::Result<Arc<CursorController>> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -62,7 +62,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::create]
|
/// threadsafe version of [crate::client::Client::create]
|
||||||
pub async fn create(&self, path: &str, content: Option<&str>) -> Result<(), Error> {
|
pub async fn create(&self, path: &str, content: Option<&str>) -> crate::Result<()> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -72,7 +72,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::attach]
|
/// threadsafe version of [crate::client::Client::attach]
|
||||||
pub async fn attach(&self, path: &str) -> Result<Arc<BufferController>, Error> {
|
pub async fn attach(&self, path: &str) -> crate::Result<Arc<BufferController>> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -82,7 +82,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::get_cursor]
|
/// threadsafe version of [crate::client::Client::get_cursor]
|
||||||
pub async fn get_cursor(&self) -> Result<Arc<CursorController>, Error> {
|
pub async fn get_cursor(&self) -> crate::Result<Arc<CursorController>> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -92,7 +92,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::get_buffer]
|
/// threadsafe version of [crate::client::Client::get_buffer]
|
||||||
pub async fn get_buffer(&self, path: &str) -> Result<Arc<BufferController>, Error> {
|
pub async fn get_buffer(&self, path: &str) -> crate::Result<Arc<BufferController>> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -102,7 +102,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::leave_workspace]
|
/// threadsafe version of [crate::client::Client::leave_workspace]
|
||||||
pub async fn leave_workspace(&self) -> Result<(), Error> {
|
pub async fn leave_workspace(&self) -> crate::Result<()> {
|
||||||
self.client
|
self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -112,7 +112,7 @@ pub mod a_sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe version of [crate::client::Client::disconnect_buffer]
|
/// threadsafe version of [crate::client::Client::disconnect_buffer]
|
||||||
pub async fn disconnect_buffer(&self, path: &str) -> Result<bool, Error> {
|
pub async fn disconnect_buffer(&self, path: &str) -> crate::Result<bool> {
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.lock().await
|
.lock().await
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -120,6 +120,16 @@ pub mod a_sync {
|
||||||
.disconnect_buffer(path);
|
.disconnect_buffer(path);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn select_buffer(&self) -> crate::Result<String> {
|
||||||
|
let res = self.client
|
||||||
|
.lock().await
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(Error::InvalidState { msg: "connect first".into() })?
|
||||||
|
.select_buffer()
|
||||||
|
.await?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +145,7 @@ pub mod sync {
|
||||||
buffer::controller::BufferController
|
buffer::controller::BufferController
|
||||||
};
|
};
|
||||||
|
|
||||||
/// persistant session manager for codemp client
|
/// persistent session manager for codemp client
|
||||||
///
|
///
|
||||||
/// will hold a std mutex over an optional client, and drop its reference when disconnecting.
|
/// will hold a std mutex over an optional client, and drop its reference when disconnecting.
|
||||||
/// also contains a tokio runtime to execute async futures on
|
/// also contains a tokio runtime to execute async futures on
|
||||||
|
@ -157,7 +167,7 @@ pub mod sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
fn if_client<T>(&self, op: impl FnOnce(&mut Client) -> T) -> Result<T, Error> {
|
fn if_client<T>(&self, op: impl FnOnce(&mut Client) -> T) -> crate::Result<T> {
|
||||||
if let Some(c) = self.client.lock().expect("client mutex poisoned").as_mut() {
|
if let Some(c) = self.client.lock().expect("client mutex poisoned").as_mut() {
|
||||||
Ok(op(c))
|
Ok(op(c))
|
||||||
} else {
|
} else {
|
||||||
|
@ -175,38 +185,42 @@ pub mod sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::join]
|
/// threadsafe and sync version of [crate::client::Client::join]
|
||||||
pub fn join(&self, session: &str) -> Result<Arc<CursorController>, Error> {
|
pub fn join(&self, session: &str) -> crate::Result<Arc<CursorController>> {
|
||||||
self.if_client(|c| self.rt().block_on(c.join(session)))?
|
self.if_client(|c| self.rt().block_on(c.join(session)))?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::create]
|
/// threadsafe and sync version of [crate::client::Client::create]
|
||||||
pub fn create(&self, path: &str, content: Option<&str>) -> Result<(), Error> {
|
pub fn create(&self, path: &str, content: Option<&str>) -> crate::Result<()> {
|
||||||
self.if_client(|c| self.rt().block_on(c.create(path, content)))?
|
self.if_client(|c| self.rt().block_on(c.create(path, content)))?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::attach]
|
/// threadsafe and sync version of [crate::client::Client::attach]
|
||||||
pub fn attach(&self, path: &str) -> Result<Arc<BufferController>, Error> {
|
pub fn attach(&self, path: &str) -> crate::Result<Arc<BufferController>> {
|
||||||
self.if_client(|c| self.rt().block_on(c.attach(path)))?
|
self.if_client(|c| self.rt().block_on(c.attach(path)))?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::get_cursor]
|
/// threadsafe and sync version of [crate::client::Client::get_cursor]
|
||||||
pub fn get_cursor(&self) -> Result<Arc<CursorController>, Error> {
|
pub fn get_cursor(&self) -> crate::Result<Arc<CursorController>> {
|
||||||
self.if_client(|c| c.get_cursor().ok_or(Error::InvalidState { msg: "join workspace first".into() }))?
|
self.if_client(|c| c.get_cursor().ok_or(Error::InvalidState { msg: "join workspace first".into() }))?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::get_buffer]
|
/// threadsafe and sync version of [crate::client::Client::get_buffer]
|
||||||
pub fn get_buffer(&self, path: &str) -> Result<Arc<BufferController>, Error> {
|
pub fn get_buffer(&self, path: &str) -> crate::Result<Arc<BufferController>> {
|
||||||
self.if_client(|c| c.get_buffer(path).ok_or(Error::InvalidState { msg: "join workspace or create requested buffer first".into() }))?
|
self.if_client(|c| c.get_buffer(path).ok_or(Error::InvalidState { msg: "join workspace or create requested buffer first".into() }))?
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::leave_workspace]
|
/// threadsafe and sync version of [crate::client::Client::leave_workspace]
|
||||||
pub fn leave_workspace(&self) -> Result<(), Error> {
|
pub fn leave_workspace(&self) -> crate::Result<()> {
|
||||||
self.if_client(|c| c.leave_workspace())
|
self.if_client(|c| c.leave_workspace())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// threadsafe and sync version of [crate::client::Client::disconnect_buffer]
|
/// threadsafe and sync version of [crate::client::Client::disconnect_buffer]
|
||||||
pub fn disconnect_buffer(&self, path: &str) -> Result<bool, Error> {
|
pub fn disconnect_buffer(&self, path: &str) -> crate::Result<bool> {
|
||||||
self.if_client(|c| c.disconnect_buffer(path))
|
self.if_client(|c| c.disconnect_buffer(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn select_buffer(&self) -> crate::Result<String> {
|
||||||
|
self.if_client(|c| self.rt().block_on(c.select_buffer()))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue