feat(control-plane): add libSQL Turso backend

This commit is contained in:
Agent Board
2026-07-03 13:24:20 +08:00
parent ee6612028d
commit a75b3d11f9
44 changed files with 11070 additions and 666 deletions
@@ -15,7 +15,7 @@ use axum::extract::{Extension, Multipart, Path as AxumPath, Query, State};
use axum::http::{header, HeaderMap, HeaderValue, StatusCode};
use axum::Json;
use bridge_runtime::project_legacy_content_to_block_document;
use control_plane::AppendAuditInput;
use control_plane::{AppendAuditInput, ResolvedAccess};
use control_plane::{
CreateShareLinkInput, DirectoryGrantInput, DirectoryGrantLookup, DirectoryGrantRecord,
OutboxEventInput, ShareLinkRecord,
@@ -657,10 +657,24 @@ pub(crate) fn ensure_local_workspace_access_with_state(
));
}
let actor_id = context.auth.actor_id.trim();
let canonical_root_uri = file_uri_for_path(&canonical_root);
let sqlite_access = state
.control_plane()
.resolve_access(actor_id, &file_uri_for_path(&canonical_root))
.map_err(|error| WebError::internal(format!("SQLite 控制面授权查询失败: {error}")))?;
.resolve_access(actor_id, &canonical_root_uri)
.unwrap_or_else(|error| {
tracing::warn!(
%actor_id,
%error,
root_uri = %canonical_root_uri,
"控制面授权查询失败,回退到本地文件系统权限检查"
);
ResolvedAccess {
user_id: actor_id.to_string(),
root_uri: canonical_root_uri.clone(),
permission: String::new(),
grant_ids: Vec::new(),
}
});
if local_access_permission_allows(&sqlite_access.permission, mode) {
return Ok(canonical_root);
}
@@ -766,18 +780,78 @@ fn local_access_policy_path() -> PathBuf {
})
}
pub(crate) fn control_plane_db_path_display() -> String {
std::env::var("MNOTE_CONTROL_PLANE_DB_PATH")
pub(crate) fn control_plane_status_display() -> String {
let backend = std::env::var("MNOTE_CONTROL_PLANE_BACKEND")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| {
default_local_workspace_base_dir()
.join("control-plane")
.join("control-plane.db")
.display()
.to_string()
})
.unwrap_or_else(|| "sqlite".to_string());
match backend.as_str() {
"sqlite" => {
let db_path = std::env::var("MNOTE_CONTROL_PLANE_DB_PATH")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| {
default_local_workspace_base_dir()
.join("control-plane")
.join("control-plane.db")
.display()
.to_string()
});
format!("backend=sqlite; db={db_path}")
}
"libsql-local" | "turso-local" | "turso" => {
let db_path = std::env::var("MNOTE_TURSO_LOCAL_PATH")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| {
default_local_workspace_base_dir()
.join("control-plane")
.join("control-plane-libsql.db")
.display()
.to_string()
});
format!("backend={backend}; local={db_path}")
}
"turso-local-replica" | "turso-remote-replica" => {
let db_path = std::env::var("MNOTE_TURSO_LOCAL_REPLICA_PATH")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| {
default_local_workspace_base_dir()
.join("control-plane")
.join("control-plane-replica.db")
.display()
.to_string()
});
format!("backend={backend}; replica={db_path}; remote=env:MNOTE_TURSO_DATABASE_URL")
}
"turso-remote" => "backend=turso-remote; remote=env:MNOTE_TURSO_DATABASE_URL".to_string(),
"turso-synced" => {
let db_path = std::env::var("MNOTE_TURSO_SYNCED_PATH")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.or_else(|| {
std::env::var("MNOTE_TURSO_LOCAL_REPLICA_PATH")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
})
.unwrap_or_else(|| {
default_local_workspace_base_dir()
.join("control-plane")
.join("control-plane-synced.db")
.display()
.to_string()
});
format!("backend=turso-synced; local={db_path}; remote=env:MNOTE_TURSO_DATABASE_URL")
}
other => format!("backend={other}; unsupported"),
}
}
fn local_share_grants_path() -> PathBuf {
@@ -3304,7 +3378,7 @@ fn save_local_markdown_page_inner(
fn refresh_local_search_index_best_effort(root: &Path, root_uri: &str, workspace_id: &str) {
let control_plane = open_control_plane_store();
let _ = local_search_index::refresh_local_search_index_for_change_with_store(
&control_plane,
control_plane.as_ref(),
root,
root_uri,
workspace_id,