feat(control-plane): add libSQL Turso backend
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user