From be055c8e055552cfe29d04865c812af3e148ff15 Mon Sep 17 00:00:00 2001 From: frelodev Date: Thu, 26 Sep 2024 09:38:05 +0200 Subject: [PATCH 1/6] chore(js): added glue clear callback fn for cursor controller --- src/ffi/js/cursor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ffi/js/cursor.rs b/src/ffi/js/cursor.rs index b02f9f2..b1eb44e 100644 --- a/src/ffi/js/cursor.rs +++ b/src/ffi/js/cursor.rs @@ -62,7 +62,10 @@ impl CursorController { Ok(()) } - + #[napi(js_name = "clear_callback")] + pub fn js_clear_callback(&self) { + self.clear_callback(); + } #[napi(js_name = "send")] pub async fn js_send(&self, pos: JsCursor) -> napi::Result<()> { From a89b8a454c5cc43243fd6d14eb747d702b494a78 Mon Sep 17 00:00:00 2001 From: frelodev Date: Thu, 26 Sep 2024 09:54:56 +0200 Subject: [PATCH 2/6] chore(js): added glue buffer list fn --- src/ffi/js/workspace.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index 6021c12..bf7dd2a 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -36,6 +36,11 @@ impl Workspace { self.user_list() } + #[napi(js_name = "buffer_list")] + pub fn js_buffer_list(&self) -> Vec { + self.buffer_list() + } + #[napi(js_name = "cursor")] pub fn js_cursor(&self) -> CursorController { self.cursor() From 2daab9ed87a87943e03b07ca8c6a463b76086a31 Mon Sep 17 00:00:00 2001 From: frelodev Date: Thu, 26 Sep 2024 09:58:03 +0200 Subject: [PATCH 3/6] chore(js): added glue detach fn --- src/ffi/js/workspace.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index bf7dd2a..1dd43d5 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -66,6 +66,11 @@ impl Workspace { Ok(self.delete(&path).await?) } + #[napi(js_name = "detach")] + pub async fn js_detach(&self, path: String) -> bool { + self.detach(&path) + } + #[napi(js_name = "event")] pub async fn js_event(&self) -> napi::Result { Ok(JsEvent::from(self.event().await?)) From 512c2b30ea8055fbfb6c59dd0efceb11881f7292 Mon Sep 17 00:00:00 2001 From: frelodev Date: Fri, 27 Sep 2024 23:33:06 +0200 Subject: [PATCH 4/6] chore(js): added glue workspace functions --- src/ffi/js/workspace.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index 1dd43d5..3d003c7 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -2,6 +2,7 @@ use napi_derive::napi; use crate::Workspace; use crate::buffer::controller::BufferController; use crate::cursor::controller::CursorController; +use crate::ffi::js::client::JsUser; #[napi(object, js_name = "Event")] pub struct JsEvent { @@ -75,4 +76,27 @@ impl Workspace { pub async fn js_event(&self) -> napi::Result { Ok(JsEvent::from(self.event().await?)) } + + /// Re-fetch remote buffer list + #[napi(js_name = "fetch_buffers")] + pub async fn js_fetch_buffers(&self) -> napi::Result<()> { + Ok(self.fetch_buffers().await?) + } + /// Re-fetch the list of all users in the workspace. + #[napi(js_name = "fetch_users")] + pub async fn js_fetch_users(&self) -> napi::Result<()> { + Ok(self.fetch_users().await?) + } + + /// List users attached to a specific buffer + #[napi(js_name = "list_buffer_users")] + pub async fn js_list_buffer_users(&self, path: String) -> napi::Result> { + Ok( + self + .list_buffer_users(&path) + .await? + .into_iter() + .map(JsUser::from) + .collect()) + } } From 2b6d2037c76bfc2fd91e1800b22e45e60f7b2ffb Mon Sep 17 00:00:00 2001 From: frelodev Date: Fri, 27 Sep 2024 23:34:07 +0200 Subject: [PATCH 5/6] chore(js): added glue user object --- src/ffi/js/client.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/ffi/js/client.rs b/src/ffi/js/client.rs index c1ea64f..60c0de0 100644 --- a/src/ffi/js/client.rs +++ b/src/ffi/js/client.rs @@ -1,6 +1,31 @@ use napi_derive::napi; use crate::{Client, Workspace}; +#[napi(object, js_name = "User")] +pub struct JsUser { + pub uuid: String, + pub name: String, +} + +impl TryFrom for crate::api::User { + type Error = ::Err; + fn try_from(value: JsUser) -> Result { + Ok(Self { + id: value.uuid.parse()?, + name: value.name, + }) + } +} + +impl From for JsUser { + fn from(value: crate::api::User) -> Self { + Self { + uuid: value.id.to_string(), + name: value.name, + } + } +} + #[napi] /// connect to codemp servers and return a client session pub async fn connect(config: crate::api::Config) -> napi::Result{ @@ -51,10 +76,10 @@ impl Client { self.get_workspace(&workspace) } - #[napi(js_name = "user_id")] + #[napi(js_name = "user")] /// return current sessions's user id - pub fn js_user_id(&self) -> String { - self.user().id.to_string() + pub fn js_user(&self) -> JsUser { + self.user().clone().into() } #[napi(js_name = "active_workspaces")] From 52269324cd1645289aa041facda538100fde00b8 Mon Sep 17 00:00:00 2001 From: frelodev Date: Fri, 27 Sep 2024 23:34:48 +0200 Subject: [PATCH 6/6] chore(js): docs --- src/ffi/js/buffer.rs | 19 +++++++++++++------ src/ffi/js/client.rs | 2 +- src/ffi/js/cursor.rs | 15 ++++++++++----- src/ffi/js/ext.rs | 3 +++ src/ffi/js/workspace.rs | 14 ++++++++++++++ 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/ffi/js/buffer.rs b/src/ffi/js/buffer.rs index a1a3727..93663a6 100644 --- a/src/ffi/js/buffer.rs +++ b/src/ffi/js/buffer.rs @@ -8,6 +8,8 @@ use crate::buffer::controller::BufferController; #[napi] impl BufferController { + /// Register a callback to be invoked every time a new event is available to consume + /// There can only be one callback registered at any given time. #[napi(js_name = "callback", ts_args_type = "fun: (event: BufferController) => void")] pub fn js_callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ let tsfn : ThreadsafeFunction = @@ -17,48 +19,53 @@ impl BufferController { } )?; self.callback(move |controller : BufferController| { - - tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error + tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); + //check this with tracing also we could use Ok(event) to get the error // If it blocks the main thread too many time we have to change this - }); Ok(()) } + /// Remove registered buffer callback #[napi(js_name = "clear_callback")] pub fn js_clear_callback(&self) { self.clear_callback(); } - - + + /// Get buffer path #[napi(js_name = "get_path")] pub fn js_path(&self) -> &str { self.path() } + /// Block until next buffer event without returning it #[napi(js_name = "poll")] pub async fn js_poll(&self) -> napi::Result<()>{ Ok(self.poll().await?) } + /// Return next buffer event if present #[napi(js_name = "try_recv")] pub async fn js_try_recv(&self) -> napi::Result> { Ok(self.try_recv().await?) } + /// Wait for next buffer event and return it #[napi(js_name = "recv")] pub async fn js_recv(&self) -> napi::Result { Ok(self.recv().await?) } + /// Send a buffer update to workspace #[napi(js_name = "send")] pub async fn js_send(&self, op: TextChange) -> napi::Result<()> { Ok(self.send(op).await?) } + /// Return buffer whole content #[napi(js_name = "content")] pub async fn js_content(&self) -> napi::Result { Ok(self.content().await?) } -} +} \ No newline at end of file diff --git a/src/ffi/js/client.rs b/src/ffi/js/client.rs index 60c0de0..da6296d 100644 --- a/src/ffi/js/client.rs +++ b/src/ffi/js/client.rs @@ -93,4 +93,4 @@ impl Client { pub async fn js_refresh(&self) -> napi::Result<()> { Ok(self.refresh().await?) } -} +} \ No newline at end of file diff --git a/src/ffi/js/cursor.rs b/src/ffi/js/cursor.rs index b1eb44e..17289fb 100644 --- a/src/ffi/js/cursor.rs +++ b/src/ffi/js/cursor.rs @@ -4,7 +4,6 @@ use napi::threadsafe_function::{ThreadsafeFunction, ThreadSafeCallContext, Threa use crate::api::Controller; use crate::cursor::controller::CursorController; - #[napi(object, js_name = "Cursor")] pub struct JsCursor { /// range of text change, as char indexes in buffer previous state @@ -26,6 +25,7 @@ impl From for crate::api::Cursor { } } } + impl From for JsCursor { fn from(value: crate::api::Cursor) -> Self { JsCursor { @@ -44,6 +44,8 @@ impl From for JsCursor { #[napi] impl CursorController { + /// Register a callback to be called on receive. + /// There can only be one callback registered at any given time. #[napi(js_name = "callback", ts_args_type = "fun: (event: CursorController) => void")] pub fn js_callback(&self, fun: napi::JsFunction) -> napi::Result<()>{ let tsfn : ThreadsafeFunction = @@ -53,34 +55,37 @@ impl CursorController { } )?; self.callback(move |controller : CursorController| { - - tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error + tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); + //check this with tracing also we could use Ok(event) to get the error // If it blocks the main thread too many time we have to change this - }); Ok(()) } + /// Clear the registered callback #[napi(js_name = "clear_callback")] pub fn js_clear_callback(&self) { self.clear_callback(); } + /// Send a new cursor event to remote #[napi(js_name = "send")] pub async fn js_send(&self, pos: JsCursor) -> napi::Result<()> { Ok(self.send(crate::api::Cursor::from(pos)).await?) } + /// Get next cursor event if available without blocking #[napi(js_name= "try_recv")] pub async fn js_try_recv(&self) -> napi::Result> { Ok(self.try_recv().await? .map(JsCursor::from)) } + /// Block until next #[napi(js_name= "recv")] pub async fn js_recv(&self) -> napi::Result { Ok(self.recv().await?.into()) } -} +} \ No newline at end of file diff --git a/src/ffi/js/ext.rs b/src/ffi/js/ext.rs index 73795ac..39ff751 100644 --- a/src/ffi/js/ext.rs +++ b/src/ffi/js/ext.rs @@ -1,11 +1,14 @@ use napi_derive::napi; +/// Hash function #[napi(js_name = "hash")] pub fn js_hash(data: String) -> i64 { crate::ext::hash(data) } + +/// Get the current version of the client #[napi(js_name = "version")] pub fn js_version() -> String { crate::version() diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index 3d003c7..4c19f4b 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -22,56 +22,70 @@ impl From for JsEvent { #[napi] impl Workspace { + /// Get the unique workspace id #[napi(js_name = "id")] pub fn js_id(&self) -> String { self.id() } + /// List all available buffers in this workspace #[napi(js_name = "filetree")] pub fn js_filetree(&self, filter: Option<&str>, strict: bool) -> Vec { self.filetree(filter, strict) } + /// List all user names currently in this workspace #[napi(js_name = "user_list")] pub fn js_user_list(&self) -> Vec { self.user_list() } + /// List all currently active buffers #[napi(js_name = "buffer_list")] pub fn js_buffer_list(&self) -> Vec { self.buffer_list() } + /// Get workspace's Cursor Controller #[napi(js_name = "cursor")] pub fn js_cursor(&self) -> CursorController { self.cursor() } + /// Get a buffer controller by its name (path) #[napi(js_name = "buffer_by_name")] pub fn js_buffer_by_name(&self, path: String) -> Option { self.buffer_by_name(&path) } + /// Create a new buffer in the current workspace #[napi(js_name = "create")] pub async fn js_create(&self, path: String) -> napi::Result<()> { Ok(self.create(&path).await?) } + + /// Attach to a workspace buffer, starting a BufferController #[napi(js_name = "attach")] pub async fn js_attach(&self, path: String) -> napi::Result { Ok(self.attach(&path).await?) } + /// Delete a buffer from workspace #[napi(js_name = "delete")] pub async fn js_delete(&self, path: String) -> napi::Result<()> { Ok(self.delete(&path).await?) } + /// Detach from an active buffer, stopping its underlying worker + /// this method returns true if no reference or last reference was held, false if there are still + /// dangling references to clear #[napi(js_name = "detach")] pub async fn js_detach(&self, path: String) -> bool { self.detach(&path) } + /// Wait for next workspace event and return it #[napi(js_name = "event")] pub async fn js_event(&self) -> napi::Result { Ok(JsEvent::from(self.event().await?))