feat: improve native

This commit is contained in:
DarkSky
2026-02-01 20:15:34 +08:00
parent 948951d461
commit 059d3aa04a
8 changed files with 101 additions and 57 deletions

2
Cargo.lock generated
View File

@@ -44,6 +44,7 @@ dependencies = [
"docx-parser",
"infer",
"nanoid",
"napi",
"path-ext",
"pdf-extract",
"pulldown-cmark",
@@ -126,6 +127,7 @@ dependencies = [
"affine_nbstore",
"affine_sqlite_v1",
"chrono",
"mimalloc",
"napi",
"napi-build",
"napi-derive",

View File

@@ -11,6 +11,7 @@ crate-type = ["cdylib"]
affine_common = { workspace = true, features = [
"doc-loader",
"hashcash",
"napi",
"ydoc-loader",
] }
chrono = { workspace = true }

View File

@@ -1,4 +1,7 @@
use affine_common::doc_parser::{self, BlockInfo, CrawlResult, MarkdownResult, PageDocContent, WorkspaceDocContent};
use affine_common::{
doc_parser::{self, BlockInfo, CrawlResult, MarkdownResult, PageDocContent, WorkspaceDocContent},
napi_utils::map_napi_err,
};
use napi::bindgen_prelude::*;
use napi_derive::napi;
@@ -95,22 +98,25 @@ impl From<CrawlResult> for NativeCrawlResult {
#[napi]
pub fn parse_doc_from_binary(doc_bin: Buffer, doc_id: String) -> Result<NativeCrawlResult> {
let result = doc_parser::parse_doc_from_binary(doc_bin.into(), doc_id)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::parse_doc_from_binary(doc_bin.into(), doc_id),
Status::GenericFailure,
)?;
Ok(result.into())
}
#[napi]
pub fn parse_page_doc(doc_bin: Buffer, max_summary_length: Option<i32>) -> Result<Option<NativePageDocContent>> {
let result = doc_parser::parse_page_doc(doc_bin.into(), max_summary_length.map(|v| v as isize))
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::parse_page_doc(doc_bin.into(), max_summary_length.map(|v| v as isize)),
Status::GenericFailure,
)?;
Ok(result.map(Into::into))
}
#[napi]
pub fn parse_workspace_doc(doc_bin: Buffer) -> Result<Option<NativeWorkspaceDocContent>> {
let result =
doc_parser::parse_workspace_doc(doc_bin.into()).map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(doc_parser::parse_workspace_doc(doc_bin.into()), Status::GenericFailure)?;
Ok(result.map(Into::into))
}
@@ -121,15 +127,19 @@ pub fn parse_doc_to_markdown(
ai_editable: Option<bool>,
doc_url_prefix: Option<String>,
) -> Result<NativeMarkdownResult> {
let result = doc_parser::parse_doc_to_markdown(doc_bin.into(), doc_id, ai_editable.unwrap_or(false), doc_url_prefix)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::parse_doc_to_markdown(doc_bin.into(), doc_id, ai_editable.unwrap_or(false), doc_url_prefix),
Status::GenericFailure,
)?;
Ok(result.into())
}
#[napi]
pub fn read_all_doc_ids_from_root_doc(doc_bin: Buffer, include_trash: Option<bool>) -> Result<Vec<String>> {
let result = doc_parser::get_doc_ids_from_binary(doc_bin.into(), include_trash.unwrap_or(false))
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::get_doc_ids_from_binary(doc_bin.into(), include_trash.unwrap_or(false)),
Status::GenericFailure,
)?;
Ok(result)
}
@@ -144,8 +154,10 @@ pub fn read_all_doc_ids_from_root_doc(doc_bin: Buffer, include_trash: Option<boo
/// A Buffer containing the y-octo document update binary
#[napi]
pub fn create_doc_with_markdown(title: String, markdown: String, doc_id: String) -> Result<Buffer> {
let result = doc_parser::build_full_doc(&title, &markdown, &doc_id)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::build_full_doc(&title, &markdown, &doc_id),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}
@@ -161,8 +173,10 @@ pub fn create_doc_with_markdown(title: String, markdown: String, doc_id: String)
/// A Buffer containing only the delta (changes) as a y-octo update binary
#[napi]
pub fn update_doc_with_markdown(existing_binary: Buffer, new_markdown: String, doc_id: String) -> Result<Buffer> {
let result = doc_parser::update_doc(&existing_binary, &new_markdown, &doc_id)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::update_doc(&existing_binary, &new_markdown, &doc_id),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}
@@ -177,8 +191,10 @@ pub fn update_doc_with_markdown(existing_binary: Buffer, new_markdown: String, d
/// A Buffer containing only the delta (changes) as a y-octo update binary
#[napi]
pub fn update_doc_title(existing_binary: Buffer, title: String, doc_id: String) -> Result<Buffer> {
let result = doc_parser::update_doc_title(&existing_binary, &doc_id, &title)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::update_doc_title(&existing_binary, &doc_id, &title),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}
@@ -202,14 +218,16 @@ pub fn update_doc_properties(
created_by: Option<String>,
updated_by: Option<String>,
) -> Result<Buffer> {
let result = doc_parser::update_doc_properties(
let result = map_napi_err(
doc_parser::update_doc_properties(
&existing_binary,
&properties_doc_id,
&target_doc_id,
created_by.as_deref(),
updated_by.as_deref(),
)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}
@@ -225,8 +243,10 @@ pub fn update_doc_properties(
/// A Buffer containing the y-octo update binary to apply to the root doc
#[napi]
pub fn add_doc_to_root_doc(root_doc_bin: Buffer, doc_id: String, title: Option<String>) -> Result<Buffer> {
let result = doc_parser::add_doc_to_root_doc(root_doc_bin.into(), &doc_id, title.as_deref())
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::add_doc_to_root_doc(root_doc_bin.into(), &doc_id, title.as_deref()),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}
@@ -241,7 +261,9 @@ pub fn add_doc_to_root_doc(root_doc_bin: Buffer, doc_id: String, title: Option<S
/// A Buffer containing the y-octo update binary to apply to the root doc
#[napi]
pub fn update_root_doc_meta_title(root_doc_bin: Buffer, doc_id: String, title: String) -> Result<Buffer> {
let result = doc_parser::update_root_doc_meta_title(&root_doc_bin, &doc_id, &title)
.map_err(|e| Error::new(Status::GenericFailure, e.to_string()))?;
let result = map_napi_err(
doc_parser::update_root_doc_meta_title(&root_doc_bin, &doc_id, &title),
Status::GenericFailure,
)?;
Ok(Buffer::from(result))
}

View File

@@ -1,7 +1,6 @@
use affine_common::doc_loader::Doc;
use affine_common::{doc_loader::Doc, napi_utils::map_napi_err};
use napi::{
Env, Result, Task,
anyhow::anyhow,
Env, Result, Status, Task,
bindgen_prelude::{AsyncTask, Buffer},
};
@@ -54,7 +53,7 @@ impl Task for AsyncParseDocResponse {
type JsValue = ParsedDoc;
fn compute(&mut self) -> Result<Self::Output> {
let doc = Doc::new(&self.file_path, &self.doc).map_err(|e| anyhow!(e))?;
let doc = map_napi_err(Doc::new(&self.file_path, &self.doc), Status::GenericFailure)?;
Ok(Document { inner: doc })
}

View File

@@ -9,9 +9,8 @@ pub mod hashcash;
pub mod html_sanitize;
pub mod tiktoken;
use std::fmt::{Debug, Display};
use napi::{Error, Result, Status, bindgen_prelude::*};
use affine_common::napi_utils::map_napi_err;
use napi::{Result, Status, bindgen_prelude::*};
use y_octo::Doc;
#[cfg(not(target_arch = "arm"))]
@@ -21,35 +20,16 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
#[macro_use]
extern crate napi_derive;
fn map_err_inner<T, E: Display + Debug>(v: std::result::Result<T, E>, status: Status) -> Result<T> {
match v {
Ok(val) => Ok(val),
Err(e) => {
dbg!(&e);
Err(Error::new(status, e.to_string()))
}
}
}
macro_rules! map_err {
($val: expr) => {
map_err_inner($val, Status::GenericFailure)
};
($val: expr, $stauts: ident) => {
map_err_inner($val, $stauts)
};
}
/// Merge updates in form like `Y.applyUpdate(doc, update)` way and return the
/// result binary.
#[napi(catch_unwind)]
pub fn merge_updates_in_apply_way(updates: Vec<Buffer>) -> Result<Buffer> {
let mut doc = Doc::default();
for update in updates {
map_err!(doc.apply_update_from_binary_v1(update.as_ref()))?;
map_napi_err(doc.apply_update_from_binary_v1(update.as_ref()), Status::GenericFailure)?;
}
let buf = map_err!(doc.encode_update_v1())?;
let buf = map_napi_err(doc.encode_update_v1(), Status::GenericFailure)?;
Ok(buf.into())
}
@@ -59,3 +39,17 @@ pub const AFFINE_PRO_PUBLIC_KEY: Option<&'static str> = std::option_env!("AFFINE
#[napi]
pub const AFFINE_PRO_LICENSE_AES_KEY: Option<&'static str> = std::option_env!("AFFINE_PRO_LICENSE_AES_KEY");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_updates_reports_generic_failure() {
let err = match merge_updates_in_apply_way(vec![Buffer::from(vec![0])]) {
Ok(_) => panic!("expected error"),
Err(err) => err,
};
assert_eq!(err.status, Status::GenericFailure);
}
}

View File

@@ -22,6 +22,7 @@ doc-loader = [
"url",
]
hashcash = ["chrono", "sha3", "rand"]
napi = ["dep:napi"]
tree-sitter = [
"cc",
"dep:tree-sitter",
@@ -53,6 +54,7 @@ chrono = { workspace = true, optional = true }
docx-parser = { workspace = true, optional = true }
infer = { workspace = true, optional = true }
nanoid = { workspace = true, optional = true }
napi = { workspace = true, optional = true }
path-ext = { workspace = true, optional = true }
pdf-extract = { workspace = true, optional = true }
pulldown-cmark = { workspace = true, optional = true }

View File

@@ -4,3 +4,5 @@ pub mod doc_loader;
pub mod doc_parser;
#[cfg(feature = "hashcash")]
pub mod hashcash;
#[cfg(feature = "napi")]
pub mod napi_utils;

View File

@@ -0,0 +1,22 @@
use std::fmt::{Debug, Display};
use napi::{Error, Result, Status};
pub fn to_napi_error<E: Display + Debug>(err: E, status: Status) -> Error {
Error::new(status, err.to_string())
}
pub fn map_napi_err<T, E: Display + Debug>(value: std::result::Result<T, E>, status: Status) -> Result<T> {
value.map_err(|err| to_napi_error(err, status))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn map_napi_err_keeps_message() {
let err = map_napi_err::<(), _>(Err("boom"), Status::GenericFailure).unwrap_err();
assert!(err.to_string().contains("boom"));
}
}