Fix relative paths (#2615)

This commit is contained in:
Rushmore Mushambi 2023-09-05 08:38:39 +02:00 committed by GitHub
parent e9821ee09e
commit 4259e05413
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 94 additions and 76 deletions

7
Cargo.lock generated
View file

@ -3575,6 +3575,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "path-clean"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
[[package]] [[package]]
name = "pbkdf2" name = "pbkdf2"
version = "0.12.2" version = "0.12.2"
@ -5301,6 +5307,7 @@ dependencies = [
"native-tls", "native-tls",
"nom", "nom",
"once_cell", "once_cell",
"path-clean",
"pbkdf2", "pbkdf2",
"pharos", "pharos",
"pin-project-lite", "pin-project-lite",

View file

@ -86,6 +86,7 @@ nanoid = "0.4.0"
native-tls = { version = "0.2.11", optional = true } native-tls = { version = "0.2.11", optional = true }
nom = { version = "7.1.3", features = ["alloc"] } nom = { version = "7.1.3", features = ["alloc"] }
once_cell = "1.18.0" once_cell = "1.18.0"
path-clean = "1.0.1"
pbkdf2 = { version = "0.12.2", features = ["simple"] } pbkdf2 = { version = "0.12.2", features = ["simple"] }
pin-project-lite = "0.2.12" pin-project-lite = "0.2.12"
radix_trie = { version = "0.2.1", features = ["serde"] } radix_trie = { version = "0.2.1", features = ["serde"] }

View file

@ -95,7 +95,10 @@ use crate::api::opt::Endpoint;
use crate::api::Connect; use crate::api::Connect;
use crate::api::Result; use crate::api::Result;
use crate::api::Surreal; use crate::api::Surreal;
use crate::opt::replace_tilde;
use path_clean::PathClean;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::sync::OnceLock; use std::sync::OnceLock;
use url::Url; use url::Url;
@ -108,12 +111,24 @@ pub trait IntoEndpoint {
impl IntoEndpoint for &str { impl IntoEndpoint for &str {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = match self { let (url, path) = match self {
"memory" => "mem://", "memory" | "mem://" => (Url::parse("mem://").unwrap(), "memory".to_owned()),
_ => self, url if url.starts_with("ws") | url.starts_with("http") => {
(Url::parse(url).map_err(|_| Error::InvalidUrl(self.to_owned()))?, String::new())
}
_ => {
let (scheme, _) = self.split_once(':').unwrap_or((self, ""));
let path = replace_tilde(self);
(
Url::parse(&format!("{scheme}://"))
.map_err(|_| Error::InvalidUrl(self.to_owned()))?,
Path::new(&path).clean().display().to_string(),
)
}
}; };
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(url).map_err(|_| Error::InvalidUrl(self.to_owned()))?, url,
path,
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -61,7 +61,7 @@ impl Connection for Any {
let (conn_tx, conn_rx) = flume::bounded::<Result<()>>(1); let (conn_tx, conn_rx) = flume::bounded::<Result<()>>(1);
let mut features = HashSet::new(); let mut features = HashSet::new();
match address.endpoint.scheme() { match address.url.scheme() {
"fdb" => { "fdb" => {
#[cfg(feature = "kv-fdb")] #[cfg(feature = "kv-fdb")]
{ {
@ -151,7 +151,7 @@ impl Connection for Any {
}; };
} }
let client = builder.build()?; let client = builder.build()?;
let base_url = address.endpoint; let base_url = address.url;
engine::remote::http::health( engine::remote::http::health(
client.get(base_url.join(Method::Health.as_str())?), client.get(base_url.join(Method::Health.as_str())?),
) )
@ -169,7 +169,7 @@ impl Connection for Any {
"ws" | "wss" => { "ws" | "wss" => {
#[cfg(feature = "protocol-ws")] #[cfg(feature = "protocol-ws")]
{ {
let url = address.endpoint.join(engine::remote::ws::PATH)?; let url = address.url.join(engine::remote::ws::PATH)?;
#[cfg(any(feature = "native-tls", feature = "rustls"))] #[cfg(any(feature = "native-tls", feature = "rustls"))]
let maybe_connector = address.config.tls_config.map(Connector::from); let maybe_connector = address.config.tls_config.map(Connector::from);
#[cfg(not(any(feature = "native-tls", feature = "rustls")))] #[cfg(not(any(feature = "native-tls", feature = "rustls")))]

View file

@ -46,7 +46,7 @@ impl Connection for Any {
let (conn_tx, conn_rx) = flume::bounded::<Result<()>>(1); let (conn_tx, conn_rx) = flume::bounded::<Result<()>>(1);
let mut features = HashSet::new(); let mut features = HashSet::new();
match address.endpoint.scheme() { match address.url.scheme() {
"fdb" => { "fdb" => {
#[cfg(feature = "kv-fdb")] #[cfg(feature = "kv-fdb")]
{ {
@ -144,7 +144,7 @@ impl Connection for Any {
#[cfg(feature = "protocol-ws")] #[cfg(feature = "protocol-ws")]
{ {
let mut address = address; let mut address = address;
address.endpoint = address.endpoint.join(engine::remote::ws::PATH)?; address.url = address.url.join(engine::remote::ws::PATH)?;
engine::remote::ws::wasm::router(address, capacity, conn_tx, route_rx); engine::remote::ws::wasm::router(address, capacity, conn_tx, route_rx);
conn_rx.into_recv_async().await??; conn_rx.into_recv_async().await??;
} }

View file

@ -6,7 +6,6 @@ use crate::api::conn::Route;
use crate::api::conn::Router; use crate::api::conn::Router;
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::DEFAULT_TICK_INTERVAL; use crate::api::engine::local::DEFAULT_TICK_INTERVAL;
use crate::api::err::Error;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::ExtraFeatures; use crate::api::ExtraFeatures;
use crate::api::OnceLockExt; use crate::api::OnceLockExt;
@ -95,7 +94,6 @@ pub(crate) fn router(
route_rx: Receiver<Option<Route>>, route_rx: Receiver<Option<Route>>,
) { ) {
tokio::spawn(async move { tokio::spawn(async move {
let url = address.endpoint;
let configured_root = match address.config.auth { let configured_root = match address.config.auth {
Level::Root => Some(Root { Level::Root => Some(Root {
username: &address.config.username, username: &address.config.username,
@ -104,36 +102,21 @@ pub(crate) fn router(
_ => None, _ => None,
}; };
let kvs = { let kvs = match Datastore::new(&address.path).await {
let path = match url.scheme() { Ok(kvs) => {
"mem" => "memory".to_owned(), // If a root user is specified, setup the initial datastore credentials
"fdb" | "rocksdb" | "speedb" | "file" => match url.to_file_path() { if let Some(root) = configured_root {
Ok(path) => format!("{}://{}", url.scheme(), path.display()), if let Err(error) = kvs.setup_initial_creds(root).await {
Err(_) => {
let error = Error::InvalidUrl(url.as_str().to_owned());
let _ = conn_tx.into_send_async(Err(error.into())).await; let _ = conn_tx.into_send_async(Err(error.into())).await;
return; return;
} }
},
_ => url.as_str().to_owned(),
};
match Datastore::new(&path).await {
Ok(kvs) => {
// If a root user is specified, setup the initial datastore credentials
if let Some(root) = configured_root {
if let Err(error) = kvs.setup_initial_creds(root).await {
let _ = conn_tx.into_send_async(Err(error.into())).await;
return;
}
}
let _ = conn_tx.into_send_async(Ok(())).await;
kvs.with_auth_enabled(configured_root.is_some())
}
Err(error) => {
let _ = conn_tx.into_send_async(Err(error.into())).await;
return;
} }
let _ = conn_tx.into_send_async(Ok(())).await;
kvs.with_auth_enabled(configured_root.is_some())
}
Err(error) => {
let _ = conn_tx.into_send_async(Err(error.into())).await;
return;
} }
}; };

View file

@ -91,7 +91,6 @@ pub(crate) fn router(
route_rx: Receiver<Option<Route>>, route_rx: Receiver<Option<Route>>,
) { ) {
spawn_local(async move { spawn_local(async move {
let url = address.endpoint;
let configured_root = match address.config.auth { let configured_root = match address.config.auth {
Level::Root => Some(Root { Level::Root => Some(Root {
username: &address.config.username, username: &address.config.username,
@ -100,12 +99,7 @@ pub(crate) fn router(
_ => None, _ => None,
}; };
let path = match url.scheme() { let kvs = match Datastore::new(&address.path).await {
"mem" => "memory",
_ => url.as_str(),
};
let kvs = match Datastore::new(path).await {
Ok(kvs) => { Ok(kvs) => {
// If a root user is specified, setup the initial datastore credentials // If a root user is specified, setup the initial datastore credentials
if let Some(root) = configured_root { if let Some(root) = configured_root {

View file

@ -57,7 +57,7 @@ impl Connection for Client {
let client = builder.build()?; let client = builder.build()?;
let base_url = address.endpoint; let base_url = address.url;
super::health(client.get(base_url.join(Method::Health.as_str())?)).await?; super::health(client.get(base_url.join(Method::Health.as_str())?)).await?;

View file

@ -94,7 +94,7 @@ pub(crate) fn router(
route_rx: Receiver<Option<Route>>, route_rx: Receiver<Option<Route>>,
) { ) {
spawn_local(async move { spawn_local(async move {
let base_url = address.endpoint; let base_url = address.url;
let client = match client(&base_url).await { let client = match client(&base_url).await {
Ok(client) => { Ok(client) => {

View file

@ -104,7 +104,7 @@ impl Connection for Client {
capacity: usize, capacity: usize,
) -> Pin<Box<dyn Future<Output = Result<Surreal<Self>>> + Send + Sync + 'static>> { ) -> Pin<Box<dyn Future<Output = Result<Surreal<Self>>> + Send + Sync + 'static>> {
Box::pin(async move { Box::pin(async move {
let url = address.endpoint.join(PATH)?; let url = address.url.join(PATH)?;
#[cfg(any(feature = "native-tls", feature = "rustls"))] #[cfg(any(feature = "native-tls", feature = "rustls"))]
let maybe_connector = address.config.tls_config.map(Connector::from); let maybe_connector = address.config.tls_config.map(Connector::from);
#[cfg(not(any(feature = "native-tls", feature = "rustls")))] #[cfg(not(any(feature = "native-tls", feature = "rustls")))]

View file

@ -69,7 +69,7 @@ impl Connection for Client {
capacity: usize, capacity: usize,
) -> Pin<Box<dyn Future<Output = Result<Surreal<Self>>> + Send + Sync + 'static>> { ) -> Pin<Box<dyn Future<Output = Result<Surreal<Self>>> + Send + Sync + 'static>> {
Box::pin(async move { Box::pin(async move {
address.endpoint = address.endpoint.join(PATH)?; address.url = address.url.join(PATH)?;
let (route_tx, route_rx) = match capacity { let (route_tx, route_rx) = match capacity {
0 => flume::unbounded(), 0 => flume::unbounded(),
@ -118,7 +118,7 @@ pub(crate) fn router(
route_rx: Receiver<Option<Route>>, route_rx: Receiver<Option<Route>>,
) { ) {
spawn_local(async move { spawn_local(async move {
let (mut ws, mut socket) = match WsMeta::connect(&address.endpoint, None).await { let (mut ws, mut socket) = match WsMeta::connect(&address.url, None).await {
Ok(pair) => pair, Ok(pair) => pair,
Err(error) => { Err(error) => {
let _ = conn_tx.into_send_async(Err(error.into())).await; let _ = conn_tx.into_send_async(Err(error.into())).await;
@ -330,7 +330,7 @@ pub(crate) fn router(
'reconnect: loop { 'reconnect: loop {
trace!("Reconnecting..."); trace!("Reconnecting...");
match WsMeta::connect(&address.endpoint, None).await { match WsMeta::connect(&address.url, None).await {
Ok((mut meta, stream)) => { Ok((mut meta, stream)) => {
socket = stream; socket = stream;
events = { events = {

View file

@ -30,7 +30,8 @@ impl IntoEndpoint<Test> for () {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse("test://")?, url: Url::parse("test://")?,
path: String::new(),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -1,6 +1,5 @@
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::FDb; use crate::api::engine::local::FDb;
use crate::api::err::Error;
use crate::api::opt::Config; use crate::api::opt::Config;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::opt::IntoEndpoint; use crate::api::opt::IntoEndpoint;
@ -16,9 +15,10 @@ macro_rules! endpoints {
type Client = Db; type Client = Db;
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = super::make_url("fdb", self); let protocol = "fdb://";
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(protocol).unwrap(),
path: super::path_to_string(protocol, self),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -18,7 +18,8 @@ macro_rules! endpoints {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("http://{self}"); let url = format!("http://{self}");
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?,
path: String::new(),
config: Default::default(), config: Default::default(),
}) })
} }
@ -40,7 +41,8 @@ macro_rules! endpoints {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("https://{self}"); let url = format!("https://{self}");
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?,
path: String::new(),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -1,6 +1,5 @@
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::IndxDb; use crate::api::engine::local::IndxDb;
use crate::api::err::Error;
use crate::api::opt::Config; use crate::api::opt::Config;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::opt::IntoEndpoint; use crate::api::opt::IntoEndpoint;
@ -14,9 +13,10 @@ macro_rules! endpoints {
type Client = Db; type Client = Db;
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("indxdb://{self}"); let protocol = "indxdb://";
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(protocol).unwrap(),
path: super::path_to_string(protocol, self),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -11,7 +11,8 @@ impl IntoEndpoint<Mem> for () {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse("mem://").unwrap(), url: Url::parse("mem://").unwrap(),
path: "memory".to_owned(),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -26,7 +26,8 @@ use super::Config;
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)] // used by the embedded and remote connections #[allow(dead_code)] // used by the embedded and remote connections
pub struct Endpoint { pub struct Endpoint {
pub(crate) endpoint: Url, pub(crate) url: Url,
pub(crate) path: String,
pub(crate) config: Config, pub(crate) config: Config,
} }
@ -38,7 +39,17 @@ pub trait IntoEndpoint<Scheme> {
fn into_endpoint(self) -> Result<Endpoint>; fn into_endpoint(self) -> Result<Endpoint>;
} }
#[cfg(any(feature = "kv-fdb", feature = "kv-rocksdb", feature = "kv-speedb"))] pub(crate) fn replace_tilde(path: &str) -> String {
fn make_url(scheme: &str, path: impl AsRef<std::path::Path>) -> String { let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_owned());
format!("{scheme}://{}", path.as_ref().display()) path.replacen("://~", &format!("://{home}"), 1).replacen(":~", &format!(":{home}"), 1)
}
#[allow(dead_code)]
fn path_to_string(protocol: &str, path: impl AsRef<std::path::Path>) -> String {
use path_clean::PathClean;
use std::path::Path;
let path = format!("{protocol}{}", path.as_ref().display());
let expanded = replace_tilde(&path);
Path::new(&expanded).clean().display().to_string()
} }

View file

@ -1,7 +1,6 @@
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::File; use crate::api::engine::local::File;
use crate::api::engine::local::RocksDb; use crate::api::engine::local::RocksDb;
use crate::api::err::Error;
use crate::api::opt::Config; use crate::api::opt::Config;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::opt::IntoEndpoint; use crate::api::opt::IntoEndpoint;
@ -17,9 +16,10 @@ macro_rules! endpoints {
type Client = Db; type Client = Db;
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = super::make_url("rocksdb", self); let protocol = "rocksdb://";
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(protocol).unwrap(),
path: super::path_to_string(protocol, self),
config: Default::default(), config: Default::default(),
}) })
} }
@ -39,9 +39,10 @@ macro_rules! endpoints {
type Client = Db; type Client = Db;
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = super::make_url("file", self); let protocol = "file://";
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(protocol).unwrap(),
path: super::path_to_string(protocol, self),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -1,6 +1,5 @@
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::SpeeDb; use crate::api::engine::local::SpeeDb;
use crate::api::err::Error;
use crate::api::opt::Config; use crate::api::opt::Config;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::opt::IntoEndpoint; use crate::api::opt::IntoEndpoint;
@ -16,9 +15,10 @@ macro_rules! endpoints {
type Client = Db; type Client = Db;
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = super::make_url("speedb", self); let protocol = "speedb://";
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(protocol).unwrap(),
path: super::path_to_string(protocol, self),
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -1,6 +1,5 @@
use crate::api::engine::local::Db; use crate::api::engine::local::Db;
use crate::api::engine::local::TiKv; use crate::api::engine::local::TiKv;
use crate::api::err::Error;
use crate::api::opt::Config; use crate::api::opt::Config;
use crate::api::opt::Endpoint; use crate::api::opt::Endpoint;
use crate::api::opt::IntoEndpoint; use crate::api::opt::IntoEndpoint;
@ -17,7 +16,8 @@ macro_rules! endpoints {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("tikv://{self}"); let url = format!("tikv://{self}");
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(&url).unwrap(),
path: url,
config: Default::default(), config: Default::default(),
}) })
} }

View file

@ -18,7 +18,8 @@ macro_rules! endpoints {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("ws://{self}"); let url = format!("ws://{self}");
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?,
path: String::new(),
config: Default::default(), config: Default::default(),
}) })
} }
@ -40,7 +41,8 @@ macro_rules! endpoints {
fn into_endpoint(self) -> Result<Endpoint> { fn into_endpoint(self) -> Result<Endpoint> {
let url = format!("wss://{self}"); let url = format!("wss://{self}");
Ok(Endpoint { Ok(Endpoint {
endpoint: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?, url: Url::parse(&url).map_err(|_| Error::InvalidUrl(url))?,
path: String::new(),
config: Default::default(), config: Default::default(),
}) })
} }