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 }
|
||||
# global
|
||||
lazy_static = { version = "1.4", optional = true }
|
||||
futures = "0.3"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.9"
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
//! codemp client manager, containing grpc services
|
||||
|
||||
use std::{sync::Arc, collections::BTreeMap};
|
||||
use futures::stream::FuturesUnordered;
|
||||
|
||||
use tokio_stream::StreamExt;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use crate::{
|
||||
api::Controller,
|
||||
cursor::{worker::CursorControllerWorker, controller::CursorController},
|
||||
proto::{
|
||||
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
|
||||
/// [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
|
||||
// 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();
|
||||
|
@ -103,7 +106,7 @@ impl Client {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
self.client.buffer
|
||||
.create(BufferPayload {
|
||||
|
@ -122,7 +125,7 @@ impl Client {
|
|||
///
|
||||
/// to interact with such buffer use [crate::api::Controller::send] or
|
||||
/// [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 {
|
||||
let mut client = self.client.buffer.clone();
|
||||
let req = BufferPayload {
|
||||
|
@ -148,4 +151,24 @@ impl Client {
|
|||
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 {
|
||||
/// 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?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -62,7 +62,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -72,7 +72,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -82,7 +82,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -92,7 +92,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -102,7 +102,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -112,7 +112,7 @@ pub mod a_sync {
|
|||
}
|
||||
|
||||
/// 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
|
||||
.lock().await
|
||||
.as_mut()
|
||||
|
@ -120,6 +120,16 @@ pub mod a_sync {
|
|||
.disconnect_buffer(path);
|
||||
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
|
||||
};
|
||||
|
||||
/// 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.
|
||||
/// also contains a tokio runtime to execute async futures on
|
||||
|
@ -157,7 +167,7 @@ pub mod sync {
|
|||
}
|
||||
|
||||
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() {
|
||||
Ok(op(c))
|
||||
} else {
|
||||
|
@ -175,38 +185,42 @@ pub mod sync {
|
|||
}
|
||||
|
||||
/// 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)))?
|
||||
}
|
||||
|
||||
/// 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)))?
|
||||
}
|
||||
|
||||
/// 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)))?
|
||||
}
|
||||
|
||||
/// 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() }))?
|
||||
}
|
||||
|
||||
/// 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() }))?
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
|
||||
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