locus_core_rs/storage/surrealdb/
runtime.rs1#[cfg(all(feature = "surreal-runtime", not(target_arch = "wasm32")))]
2use std::env;
3#[cfg(all(feature = "surreal-runtime", not(target_arch = "wasm32")))]
4use std::path::{Path, PathBuf};
5
6use anyhow::{Result, anyhow};
7
8#[derive(Debug, Clone)]
9pub struct SurrealDbEndpointsSettings {
10 pub embedded: Option<String>,
11 pub remote: Option<String>,
12}
13
14impl Default for SurrealDbEndpointsSettings {
15 fn default() -> Self {
16 Self {
17 embedded: Some("surrealkv://data/locus".to_string()),
18 remote: None,
19 }
20 }
21}
22
23#[derive(Debug, Clone)]
24pub struct SurrealDbSettings {
25 pub endpoints: SurrealDbEndpointsSettings,
26 pub namespace: String,
27 pub database: String,
28 pub user: Option<String>,
29 pub password: Option<String>,
30}
31
32impl Default for SurrealDbSettings {
33 fn default() -> Self {
34 Self {
35 endpoints: SurrealDbEndpointsSettings::default(),
36 namespace: "entasis".to_string(),
37 database: "locus".to_string(),
38 user: Some("root".to_string()),
39 password: Some("root".to_string()),
40 }
41 }
42}
43
44impl SurrealDbSettings {
45 pub fn endpoint(&self, use_remote: bool) -> Result<String> {
46 if use_remote {
47 if let Some(remote) = self
48 .endpoints
49 .remote
50 .as_ref()
51 .filter(|value| !value.trim().is_empty())
52 {
53 return Ok(remote.clone());
54 }
55 }
56
57 if let Some(embedded) = self
58 .endpoints
59 .embedded
60 .as_ref()
61 .filter(|value| !value.trim().is_empty())
62 {
63 return Ok(embedded.clone());
64 }
65
66 let mode = if use_remote { "remote" } else { "embedded" };
67 Err(anyhow!(
68 "No SurrealDB endpoint configured for mode {mode}. Set SurrealDb Endpoints."
69 ))
70 }
71}
72
73#[derive(Debug, Clone)]
74pub struct SurrealDbRuntimeOptions {
75 pub root_dir: String,
76 pub use_remote: bool,
77 pub endpoint: String,
78 pub namespace: String,
79 pub database: String,
80}
81
82impl SurrealDbRuntimeOptions {
83 #[cfg(all(feature = "surreal-runtime", not(target_arch = "wasm32")))]
87 pub fn from_args(
88 args: &[String],
89 settings: &SurrealDbSettings,
90 root_directory_name: Option<&str>,
91 ) -> Result<Self> {
92 let use_remote = args.iter().any(|arg| arg.eq_ignore_ascii_case("--remote"));
93 let root_name = root_directory_name
94 .unwrap_or(".locus")
95 .trim()
96 .to_string();
97
98 let home = env::var("HOME").map_err(|_| anyhow!("HOME is not set"))?;
99 let root_dir = PathBuf::from(home).join(if root_name.is_empty() {
100 ".locus"
101 } else {
102 root_name.as_str()
103 });
104
105 let endpoint = settings.endpoint(use_remote)?;
106 let normalized_endpoint = normalize_embedded_endpoint(&endpoint, &root_dir, use_remote)?;
107
108 Ok(Self {
109 root_dir: root_dir.to_string_lossy().to_string(),
110 use_remote,
111 endpoint: normalized_endpoint,
112 namespace: settings.namespace.clone(),
113 database: settings.database.clone(),
114 })
115 }
116}
117
118#[cfg(all(feature = "surreal-runtime", not(target_arch = "wasm32")))]
119fn normalize_embedded_endpoint(
120 endpoint: &str,
121 root_dir: &Path,
122 use_remote: bool,
123) -> Result<String> {
124 if use_remote {
125 return Ok(endpoint.to_string());
126 }
127
128 const SCHEME: &str = "surrealkv://";
129 if !endpoint.starts_with(SCHEME) {
130 return Ok(endpoint.to_string());
131 }
132
133 let endpoint_path = endpoint.trim_start_matches(SCHEME);
134 let absolute_path = if Path::new(endpoint_path).is_absolute() {
135 PathBuf::from(endpoint_path)
136 } else {
137 root_dir.join(endpoint_path)
138 };
139
140 if let Some(parent) = absolute_path.parent() {
141 std::fs::create_dir_all(parent)?;
142 }
143
144 Ok(format!("{SCHEME}{}", absolute_path.to_string_lossy()))
145}