feat: bindings for changes and callback

This commit is contained in:
əlemi 2023-07-04 00:59:32 +02:00
parent 06523b2325
commit 4563cfdd09

View file

@ -2,7 +2,11 @@ use std::sync::Arc;
use neon::prelude::*; use neon::prelude::*;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use codemp::{cursor::Cursor, client::CodempClient, tokio::{runtime::Runtime, sync::{Mutex, broadcast}}, proto::buffer_client::BufferClient, operation::{OperationController, OperationFactory}}; use codemp::{
cursor::Cursor, client::CodempClient, operation::{OperationController, OperationFactory, OperationProcessor},
proto::buffer_client::BufferClient,
};
use codemp::tokio::{runtime::Runtime, sync::{Mutex, broadcast}};
fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
static RUNTIME: OnceCell<Runtime> = OnceCell::new(); static RUNTIME: OnceCell<Runtime> = OnceCell::new();
@ -52,8 +56,8 @@ fn create(mut cx: FunctionContext) -> JsResult<JsPromise> {
let content = cx.argument::<JsString>(1).ok().map(|x| x.value(&mut cx)); let content = cx.argument::<JsString>(1).ok().map(|x| x.value(&mut cx));
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone();
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise(); let (deferred, promise) = cx.promise();
let channel = cx.channel(); let channel = cx.channel();
@ -70,8 +74,8 @@ fn create(mut cx: FunctionContext) -> JsResult<JsPromise> {
fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> { fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> {
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone();
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise(); let (deferred, promise) = cx.promise();
let channel = cx.channel(); let channel = cx.channel();
@ -98,9 +102,9 @@ fn listen(mut cx: FunctionContext) -> JsResult<JsPromise> {
fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> { fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone();
let path = cx.argument::<JsString>(0)?.value(&mut cx); let path = cx.argument::<JsString>(0)?.value(&mut cx);
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise(); let (deferred, promise) = cx.promise();
let channel = cx.channel(); let channel = cx.channel();
@ -111,10 +115,14 @@ fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
let obj = cx.empty_object(); let obj = cx.empty_object();
let boxed_value = cx.boxed(OperationControllerHandle(controller)); let boxed_value = cx.boxed(OperationControllerHandle(controller));
obj.set(&mut cx, "boxed", boxed_value)?; obj.set(&mut cx, "boxed", boxed_value)?;
let apply_method = JsFunction::new(&mut cx, apply_operation)?;
obj.set(&mut cx, "apply", apply_method)?;
let poll_method = JsFunction::new(&mut cx, poll_operation)?; let poll_method = JsFunction::new(&mut cx, poll_operation)?;
obj.set(&mut cx, "poll", poll_method)?; obj.set(&mut cx, "poll", poll_method)?;
let content_method = JsFunction::new(&mut cx, content_operation)?; let content_method = JsFunction::new(&mut cx, content_operation)?;
obj.set(&mut cx, "content", content_method)?; obj.set(&mut cx, "content", content_method)?;
let callback_method = JsFunction::new(&mut cx, callback_operation)?;
obj.set(&mut cx, "set_callback", callback_method)?;
Ok(obj) Ok(obj)
}) })
}, },
@ -128,18 +136,19 @@ fn attach(mut cx: FunctionContext) -> JsResult<JsPromise> {
fn cursor(mut cx: FunctionContext) -> JsResult<JsPromise> { fn cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<ClientHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone();
let path = cx.argument::<JsString>(0)?.value(&mut cx);
let row = cx.argument::<JsNumber>(0)?.value(&mut cx) as i64;
let col = cx.argument::<JsNumber>(0)?.value(&mut cx) as i64;
let path = cx.argument::<JsString>(0)?.value(&mut cx);
let row = cx.argument::<JsNumber>(1)?.value(&mut cx) as i64;
let col = cx.argument::<JsNumber>(2)?.value(&mut cx) as i64;
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise(); let (deferred, promise) = cx.promise();
let channel = cx.channel(); let channel = cx.channel();
runtime(&mut cx)?.spawn(async move { runtime(&mut cx)?.spawn(async move {
match rc.lock().await.cursor(path, row, col).await { match rc.lock().await.cursor(path, row, col).await {
Ok(accepted) => deferred.settle_with(&channel, move |mut cx| Ok(cx.boolean(accepted))), Ok(accepted) => deferred.settle_with(&channel, move |mut cx| Ok(cx.boolean(accepted))),
Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<String, neon::handle::Handle<JsString>>(e.to_string())), Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle<JsString>>(e.to_string())),
} }
}); });
@ -150,11 +159,40 @@ fn cursor(mut cx: FunctionContext) -> JsResult<JsPromise> {
struct OperationControllerHandle(Arc<OperationController>); struct OperationControllerHandle(Arc<OperationController>);
impl Finalize for OperationControllerHandle {} impl Finalize for OperationControllerHandle {}
fn apply_operation(mut cx: FunctionContext) -> JsResult<JsPromise> {
let this = cx.this();
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
let skip = cx.argument::<JsNumber>(0)?.value(&mut cx).round() as usize;
let text = cx.argument::<JsString>(1)?.value(&mut cx);
let tail = cx.argument::<JsNumber>(2)?.value(&mut cx).round() as usize;
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise();
let channel = cx.channel();
runtime(&mut cx)?.spawn(async move {
let op = rc.delta(skip, text.as_str(), tail);
match rc.apply(op) {
Err(e) => deferred.settle_with(&channel, move |mut cx| cx.throw_error::<_, Handle<JsString>>(format!("could not apply operation: {}", e))),
Ok(span) => deferred.settle_with(&channel, move |mut cx| {
let obj = cx.empty_array();
let start_value = cx.number(span.start as u32);
obj.set(&mut cx, 0, start_value)?;
let end_value = cx.number(span.end as u32);
obj.set(&mut cx, 1, end_value)?;
Ok(obj)
}),
}
});
Ok(promise)
}
fn poll_operation(mut cx: FunctionContext) -> JsResult<JsPromise> { fn poll_operation(mut cx: FunctionContext) -> JsResult<JsPromise> {
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone();
let rc = boxed.0.clone();
let (deferred, promise) = cx.promise(); let (deferred, promise) = cx.promise();
let channel = cx.channel(); let channel = cx.channel();
@ -173,22 +211,38 @@ fn poll_operation(mut cx: FunctionContext) -> JsResult<JsPromise> {
Ok(promise) Ok(promise)
} }
fn content_operation(mut cx: FunctionContext) -> JsResult<JsPromise> { fn content_operation(mut cx: FunctionContext) -> JsResult<JsString> {
let this = cx.this(); let this = cx.this();
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?; let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
let rc = boxed.0.clone(); Ok(cx.string(boxed.0.content()))
}
let (deferred, promise) = cx.promise(); fn callback_operation(mut cx: FunctionContext) -> JsResult<JsUndefined> {
let this = cx.this();
let boxed : Handle<JsBox<OperationControllerHandle>> = this.get(&mut cx, "boxed")?;
let callback = Arc::new(cx.argument::<JsFunction>(0)?.root(&mut cx));
let rc = boxed.0.clone();
let channel = cx.channel(); let channel = cx.channel();
// TODO when garbage collecting OperationController stop this worker
runtime(&mut cx)?.spawn(async move { runtime(&mut cx)?.spawn(async move {
let content = rc.content(); loop{
deferred.settle_with(&channel, move |mut cx| { let span = rc.wait().await;
Ok(cx.string(content)) let cb = callback.clone();
}); channel.send(move |mut cx| {
cb.to_inner(&mut cx)
.call_with(&cx)
.arg(cx.number(span.start as i32))
.arg(cx.number(span.end as i32))
.apply::<JsUndefined, _>(&mut cx)?;
Ok(())
});
}
}); });
Ok(promise) Ok(cx.undefined())
} }