mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 15:24:48 +01:00
feat: bindings for changes and callback
This commit is contained in:
parent
06523b2325
commit
4563cfdd09
1 changed files with 72 additions and 18 deletions
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue