mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 23:34:49 +01:00
feat: javascript glue
Co-authored-by: alemi.dev <me@alemi.dev>
This commit is contained in:
parent
f699d2e8fe
commit
754b88fd73
6 changed files with 47 additions and 104 deletions
|
@ -52,6 +52,7 @@ impl AuthWrap {
|
||||||
/// will disconnect when dropped
|
/// will disconnect when dropped
|
||||||
/// can be used to interact with server
|
/// can be used to interact with server
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[cfg_attr(feature = "js", napi_derive::napi)]
|
||||||
pub struct Client(Arc<ClientInner>);
|
pub struct Client(Arc<ClientInner>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,27 +1,11 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use napi::threadsafe_function::{ErrorStrategy::Fatal, ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode};
|
use napi::threadsafe_function::{ErrorStrategy::Fatal, ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode};
|
||||||
use napi_derive::napi;
|
use napi_derive::napi;
|
||||||
use crate::api::TextChange;
|
use crate::api::TextChange;
|
||||||
use crate::ffi::js::JsCodempError;
|
|
||||||
use crate::api::Controller;
|
use crate::api::Controller;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl From<crate::Error> for napi::Error {
|
|
||||||
fn from(value: crate::Error) -> Self {
|
|
||||||
let msg = format!("{value}");
|
|
||||||
match value {
|
|
||||||
crate::Error::Deadlocked => napi::Error::new(napi::Status::WouldDeadlock, msg),
|
|
||||||
_ => napi::Error::new(napi::Status::GenericFailure, msg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
impl CodempBufferController {
|
impl CodempBufferController {
|
||||||
|
|
||||||
|
|
||||||
#[napi(ts_args_type = "fun: (event: JsTextChange) => void")]
|
#[napi(ts_args_type = "fun: (event: JsTextChange) => void")]
|
||||||
pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{
|
pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{
|
||||||
let tsfn : ThreadsafeFunction<crate::api::TextChange, Fatal> =
|
let tsfn : ThreadsafeFunction<crate::api::TextChange, Fatal> =
|
||||||
|
@ -47,14 +31,13 @@ impl CodempBufferController {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[napi(js_name = "recv")]
|
#[napi(js_name = "recv")]
|
||||||
pub async fn jsrecv(&self) -> napi::Result<TextChange> {
|
pub async fn js_recv(&self) -> napi::Result<TextChange> {
|
||||||
Ok(self.recv().await?.into())
|
Ok(self.recv().await?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi(js_name = "send")]
|
||||||
pub fn send(&self, op: TextChange) -> napi::Result<()> {
|
pub fn js_send(&self, op: TextChange) -> napi::Result<()> {
|
||||||
Ok(self.send(op)?)
|
Ok(self.send(op)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,43 +1,37 @@
|
||||||
use napi_derive::napi;
|
use napi_derive::napi;
|
||||||
use crate::ffi::js::JsCodempError;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[napi]
|
|
||||||
/// main codemp client session
|
|
||||||
pub struct JsCodempClient(tokio::sync::RwLock<crate::Client>);
|
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
/// connect to codemp servers and return a client session
|
/// connect to codemp servers and return a client session
|
||||||
pub async fn connect(addr: Option<String>) -> napi::Result<JsCodempClient>{
|
pub async fn connect(addr: Option<String>, username: String, password: String) -> napi::Result<CodempClient>{
|
||||||
let client = crate::Client::new(addr.as_deref().unwrap_or("http://codemp.alemi.dev:50053"))
|
let client = crate::Client::new(addr.as_deref().unwrap_or("http://codemp.alemi.dev:50053"), username, password)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(JsCodempClient(tokio::sync::RwLock::new(client)))
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
impl JsCodempClient {
|
impl CodempClient {
|
||||||
#[napi]
|
#[napi(js_name = "join_workspace")]
|
||||||
/// login against AuthService with provided credentials, optionally requesting access to a workspace
|
|
||||||
pub async fn login(&self, username: String, password: String, workspace_id: Option<String>) -> napi::Result<()> {
|
|
||||||
self.0.read().await.login(username, password, workspace_id).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
/// join workspace with given id (will start its cursor controller)
|
/// join workspace with given id (will start its cursor controller)
|
||||||
pub async fn join_workspace(&self, workspace: String) -> napi::Result<JsWorkspace> {
|
pub async fn js_join_workspace(&self, workspace: String) -> napi::Result<CodempWorkspace> {
|
||||||
Ok(JsWorkspace::from(self.0.write().await.join_workspace(&workspace).await?))
|
Ok(self.join_workspace(workspace).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi(js_name = "get_workspace")]
|
||||||
/// get workspace with given id, if it exists
|
/// get workspace with given id, if it exists
|
||||||
pub async fn get_workspace(&self, workspace: String) -> Option<JsWorkspace> {
|
pub fn js_get_workspace(&self, workspace: String) -> Option<CodempWorkspace> {
|
||||||
self.0.read().await.get_workspace(&workspace).map(|w| JsWorkspace::from(w))
|
self.get_workspace(&workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi(js_name = "user_id")]
|
||||||
/// return current sessions's user id
|
/// return current sessions's user id
|
||||||
pub async fn user_id(&self) -> String {
|
pub fn js_user_id(&self) -> String {
|
||||||
self.0.read().await.user_id().to_string()
|
self.user_id().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(js_name = "active_workspaces")]
|
||||||
|
pub fn js_active_workspaces(&self) -> Vec<String> {
|
||||||
|
self.active_workspaces()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,10 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use napi_derive::napi;
|
use napi_derive::napi;
|
||||||
use uuid::Uuid;
|
|
||||||
use napi::threadsafe_function::{ThreadsafeFunction, ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy};
|
use napi::threadsafe_function::{ThreadsafeFunction, ThreadSafeCallContext, ThreadsafeFunctionCallMode, ErrorStrategy};
|
||||||
use crate::api::Controller;
|
use crate::api::Controller;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[napi(object, js_name = "Cursor")]
|
||||||
|
|
||||||
#[napi(js_name = "Cursor")]
|
|
||||||
pub struct JsCursor {
|
pub struct JsCursor {
|
||||||
/// range of text change, as char indexes in buffer previous state
|
/// range of text change, as char indexes in buffer previous state
|
||||||
pub start_row: i32,
|
pub start_row: i32,
|
||||||
|
@ -46,7 +42,6 @@ impl From<CodempCursor> for JsCursor {
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
impl CodempCursorController {
|
impl CodempCursorController {
|
||||||
|
|
||||||
#[napi(ts_args_type = "fun: (event: JsCursorEvent) => void")]
|
#[napi(ts_args_type = "fun: (event: JsCursorEvent) => void")]
|
||||||
pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{
|
pub fn callback(&self, fun: napi::JsFunction) -> napi::Result<()>{
|
||||||
let tsfn : ThreadsafeFunction<JsCursor, ErrorStrategy::Fatal> =
|
let tsfn : ThreadsafeFunction<JsCursor, ErrorStrategy::Fatal> =
|
||||||
|
@ -70,46 +65,14 @@ impl CodempCursorController {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi(js_name = "send")]
|
||||||
pub fn send(&self, pos: &CodempCursorController) -> napi::Result<()> {
|
pub fn js_send(&self, pos: JsCursor) -> napi::Result<()> {
|
||||||
Ok(self.send(pos)?)
|
Ok(self.send(crate::api::Cursor::from(pos))?)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
#[napi(js_name= "try_recv")]
|
||||||
|
pub fn js_try_recv(&self) -> napi::Result<Option<JsCursor>> {
|
||||||
#[derive(Debug)]
|
Ok(self.try_recv()?.map(|x| JsCursor::from(x)))
|
||||||
#[napi(object)]
|
|
||||||
pub struct JsCursorEvent {
|
|
||||||
pub user: String,
|
|
||||||
pub buffer: String,
|
|
||||||
pub start: JsRowCol,
|
|
||||||
pub end: JsRowCol,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From::<codemp_proto::cursor::CursorEvent> for JsCursorEvent {
|
|
||||||
fn from(value: codemp_proto::cursor::CursorEvent) -> Self {
|
|
||||||
let pos = value.position;
|
|
||||||
let start = pos.start;
|
|
||||||
let end = pos.end;
|
|
||||||
JsCursorEvent {
|
|
||||||
user: Uuid::from(value.user).to_string(),
|
|
||||||
buffer: pos.buffer.into(),
|
|
||||||
start: JsRowCol { row: start.row, col: start.col },
|
|
||||||
end: JsRowCol { row: end.row, col: end.col },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[napi(object)]
|
|
||||||
pub struct JsRowCol {
|
|
||||||
pub row: i32,
|
|
||||||
pub col: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From::<codemp_proto::cursor::RowCol> for JsRowCol {
|
|
||||||
fn from(value: codemp_proto::cursor::RowCol) -> Self {
|
|
||||||
JsRowCol { row: value.row, col: value.col }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,12 +6,13 @@ pub mod cursor;
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
pub mod op_cache;
|
pub mod op_cache;
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl From<crate::Error> for napi::Error {
|
||||||
struct JsCodempError(crate::Error);
|
fn from(value: crate::Error) -> Self {
|
||||||
|
let msg = format!("{value}");
|
||||||
impl From::<JsCodempError> for napi::Error {
|
match value {
|
||||||
fn from(value: JsCodempError) -> Self {
|
crate::Error::Deadlocked => napi::Error::new(napi::Status::WouldDeadlock, msg),
|
||||||
napi::Error::new(napi::Status::GenericFailure, &format!("CodempError: {:?}", value))
|
_ => napi::Error::new(napi::Status::GenericFailure, msg),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +37,12 @@ impl JsLogger {
|
||||||
.with_line_number(false)
|
.with_line_number(false)
|
||||||
.with_source_location(false)
|
.with_source_location(false)
|
||||||
.compact();
|
.compact();
|
||||||
tracing_subscriber::fmt()
|
let _initialized = tracing_subscriber::fmt()
|
||||||
.event_format(format)
|
.event_format(format)
|
||||||
.with_max_level(level)
|
.with_max_level(level)
|
||||||
.with_writer(std::sync::Mutex::new(JsLoggerProducer(tx)))
|
.with_writer(std::sync::Mutex::new(JsLoggerProducer(tx)))
|
||||||
.init();
|
.try_init()
|
||||||
|
.is_ok();
|
||||||
JsLogger(std::sync::Arc::new(tokio::sync::Mutex::new(rx)))
|
JsLogger(std::sync::Arc::new(tokio::sync::Mutex::new(rx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@ impl CodempWorkspace {
|
||||||
Ok(self.attach(&path).await?)
|
Ok(self.attach(&path).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#[napi]
|
#[napi(js_name = "delete")]
|
||||||
pub async fn delete(&self, path: String) -> napi::Result<>{
|
pub async fn js_delete(&self, path: String) -> napi::Result<()> {
|
||||||
self.0.delete(&path)
|
Ok(self.delete(&path).await?)
|
||||||
}*/
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue