feat: WASM-based doc viewer (pulldown-cmark)

This commit is contained in:
Accusys
2026-05-18 10:07:38 +08:00
parent 78ba6f3d3d
commit 6452ac5af2
21 changed files with 2828 additions and 7 deletions

View File

@@ -3447,6 +3447,40 @@ async fn unregister(
}
/// Serve documentation HTML pages with cookie-based auth.
async fn wasm_doc_handler() -> Result<impl axum::response::IntoResponse, (StatusCode, &'static str)> {
let path = std::path::Path::new("/Users/accusys/momentry_core_0.1/docs_v1.0/doc_wasm/index.html");
match tokio::fs::read_to_string(path).await {
Ok(html) => Ok(([("content-type", "text/html; charset=utf-8")], html)),
Err(_) => Err((StatusCode::NOT_FOUND, "Doc not found")),
}
}
async fn wasm_doc_file_handler(
Path(file): Path<String>,
) -> Result<impl axum::response::IntoResponse, (StatusCode, &'static str)> {
if file.contains("..") || file.contains("//") {
return Err((StatusCode::NOT_FOUND, "Invalid path"));
}
let base = std::path::Path::new("/Users/accusys/momentry_core_0.1/docs_v1.0/doc_wasm");
let path = base.join(&file);
if !path.exists() || !path.starts_with(base) {
return Err((StatusCode::NOT_FOUND, "File not found"));
}
let data = tokio::fs::read(&path).await.map_err(|_| (StatusCode::NOT_FOUND, "Read error"))?;
let mime = if file.ends_with(".wasm") {
"application/wasm"
} else if file.ends_with(".js") {
"application/javascript"
} else if file.ends_with(".md") {
"text/markdown; charset=utf-8"
} else if file.ends_with(".css") {
"text/css"
} else {
"application/octet-stream"
};
Ok(([("content-type", mime)], data))
}
async fn doc_handler(
State(state): State<AppState>,
headers: axum::http::HeaderMap,
@@ -3673,6 +3707,8 @@ pub async fn start_server(host: &str, port: u16) -> anyhow::Result<()> {
.route("/doc", get(doc_handler))
.route("/doc/*file", get(doc_file_handler))
.route("/dev-doc", get(dev_doc_handler))
.route("/doc-wasm", get(wasm_doc_handler))
.route("/doc-wasm/*file", get(wasm_doc_file_handler))
.route("/api/v1/auth/login", post(login))
.route("/api/v1/auth/logout", post(logout))
.route("/api/v1/stats/sftpgo", get(get_sftpgo_status))
@@ -3813,16 +3849,20 @@ async fn get_ingestion_status(
let tkg_edges = count_sql!(&format!("SELECT COUNT(*) FROM {} WHERE file_uuid = '{file_uuid}'", schema::table_name("tkg_edges")));
let scene_5w1h = count_sql!(&format!("SELECT COUNT(*) FROM {chunk} WHERE file_uuid = '{file_uuid}' AND chunk_type = 'cut' AND summary_text IS NOT NULL AND summary_text != ''"));
let related_identities: Vec<IdentityRef> = sqlx::query_as::<_, (String, String)>(&format!(
"SELECT DISTINCT i.uuid, i.name FROM {identities} i \
let related_identities: Vec<IdentityRef> = match sqlx::query_as::<_, (String, String)>(&format!(
"SELECT DISTINCT i.uuid::text, i.name FROM {identities} i \
JOIN {fd} fd ON fd.identity_id = i.id \
WHERE fd.file_uuid = '{file_uuid}' AND fd.identity_id IS NOT NULL \
ORDER BY i.name"
)).fetch_all(pool).await.unwrap_or_default().into_iter()
.map(|(uuid, name)| {
let uuid = uuid.replace('-', "");
IdentityRef { uuid, name }
}).collect();
)).fetch_all(pool).await {
Ok(rows) => rows.into_iter().map(|(uuid, name)| {
IdentityRef { uuid: uuid.replace('-', ""), name }
}).collect(),
Err(e) => {
tracing::error!("related_identities query failed: {}", e);
vec![]
}
};
let strangers = count_sql!(&format!(
"SELECT COUNT(DISTINCT trace_id) FROM {fd} \