fix: 优化endpoint new的逻辑

This commit is contained in:
shiro.lee
2024-07-05 11:47:13 +08:00
parent e9f9af0e7a
commit 9db3a04275
5 changed files with 73 additions and 34 deletions
Generated
+7
View File
@@ -319,6 +319,7 @@ dependencies = [
"lazy_static", "lazy_static",
"netif", "netif",
"path-absolutize", "path-absolutize",
"path-clean",
"reed-solomon-erasure", "reed-solomon-erasure",
"regex", "regex",
"rmp-serde", "rmp-serde",
@@ -882,6 +883,12 @@ dependencies = [
"path-dedot", "path-dedot",
] ]
[[package]]
name = "path-clean"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
[[package]] [[package]]
name = "path-dedot" name = "path-dedot"
version = "3.1.1" version = "3.1.1"
+1
View File
@@ -33,6 +33,7 @@ tokio-util = { version = "0.7.11", features = ["io"] }
s3s = "0.10.0" s3s = "0.10.0"
crc32fast = "1.4.2" crc32fast = "1.4.2"
siphasher = "1.0.1" siphasher = "1.0.1"
path-clean = "1.0.1"
[dev-dependencies] [dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
+11 -4
View File
@@ -283,11 +283,11 @@ fn possible_set_counts_with_symmetry(set_counts: &[usize], arg_patterns: &[ArgPa
for &ss in set_counts { for &ss in set_counts {
let mut symmetry = false; let mut symmetry = false;
for arg_pattern in arg_patterns { for arg_pattern in arg_patterns {
for p in arg_pattern.inner.iter() { for p in arg_pattern.as_ref().iter() {
if p.seq.len() > ss { if p.len() > ss {
symmetry = (p.seq.len() % ss) == 0; symmetry = (p.len() % ss) == 0;
} else { } else {
symmetry = (ss % p.seq.len()) == 0; symmetry = (ss % p.len()) == 0;
} }
} }
} }
@@ -520,6 +520,13 @@ mod test {
]], ]],
success: true, success: true,
}, },
TestCase {
num: 15,
args: vec!["https://node{1...3}.example.net/mnt/drive{1...8}"],
total_sizes: vec![24],
indexes: vec![vec![12, 12]],
success: true,
},
]; ];
for test_case in test_cases { for test_case in test_cases {
+20 -4
View File
@@ -16,9 +16,9 @@ const ELLIPSES: &str = "...";
/// associated prefix and suffixes. /// associated prefix and suffixes.
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq)]
pub struct Pattern { pub struct Pattern {
pub prefix: String, pub(crate) prefix: String,
pub suffix: String, pub(crate) suffix: String,
pub seq: Vec<String>, pub(crate) seq: Vec<String>,
} }
impl Pattern { impl Pattern {
@@ -37,12 +37,28 @@ impl Pattern {
ret ret
} }
pub fn len(&self) -> usize {
self.seq.len()
}
} }
/// contains a list of patterns provided in the input. /// contains a list of patterns provided in the input.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct ArgPattern { pub struct ArgPattern {
pub inner: Vec<Pattern>, inner: Vec<Pattern>,
}
impl AsRef<Vec<Pattern>> for ArgPattern {
fn as_ref(&self) -> &Vec<Pattern> {
&self.inner
}
}
impl AsMut<Vec<Pattern>> for ArgPattern {
fn as_mut(&mut self) -> &mut Vec<Pattern> {
&mut self.inner
}
} }
impl ArgPattern { impl ArgPattern {
+34 -26
View File
@@ -2,6 +2,7 @@ use super::disks_layout::DisksLayout;
use super::error::{Error, Result}; use super::error::{Error, Result};
use super::utils::net; use super::utils::net;
use path_absolutize::Absolutize; use path_absolutize::Absolutize;
use path_clean::PathClean;
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Display; use std::fmt::Display;
use std::{collections::HashMap, path::Path, usize}; use std::{collections::HashMap, path::Path, usize};
@@ -70,20 +71,18 @@ impl TryFrom<&str> for Endpoint {
/// Performs the conversion. /// Performs the conversion.
fn try_from(value: &str) -> Result<Self, Self::Error> { fn try_from(value: &str) -> Result<Self, Self::Error> {
/// check whether given path is not empty. /// check whether given path is not empty.
fn is_empty_path(path: &str) -> bool { fn is_empty_path(path: impl AsRef<Path>) -> bool {
["", "/", "\\"].iter().any(|&v| v.eq(path)) ["", "/", "\\"].iter().any(|&v| Path::new(v).eq(path.as_ref()))
} }
if is_empty_path(value) { if is_empty_path(value) {
return Err(Error::from_string("empty or root endpoint is not supported")); return Err(Error::from_string("empty or root endpoint is not supported"));
} }
// TODO What if the value passed in is something like d:\data\rustfs
let mut is_local = false; let mut is_local = false;
let url = match Url::parse(value) { let url = match Url::parse(value) {
#[allow(unused_mut)] #[allow(unused_mut)]
Ok(mut url) => { Ok(mut url) if url.has_host() => {
// URL style of endpoint. // URL style of endpoint.
// Valid URL style endpoint is // Valid URL style endpoint is
// - Scheme field must contain "http" or "https" // - Scheme field must contain "http" or "https"
@@ -96,7 +95,7 @@ impl TryFrom<&str> for Endpoint {
return Err(Error::from_string("invalid URL endpoint format")); return Err(Error::from_string("invalid URL endpoint format"));
} }
if is_empty_path(url.path()) { if is_empty_path(Path::new(url.path()).clean()) {
return Err(Error::from_string("empty or root endpoint is not supported")); return Err(Error::from_string("empty or root endpoint is not supported"));
} }
@@ -124,31 +123,20 @@ impl TryFrom<&str> for Endpoint {
url url
} }
Ok(_) => {
// like d:/foo
is_local = true;
url_parse_from_file_path(value)?
}
Err(e) => match e { Err(e) => match e {
ParseError::InvalidPort => { ParseError::InvalidPort => {
return Err(Error::from_string("invalid URL endpoint format: port number must be between 1 to 65535")) return Err(Error::from_string("invalid URL endpoint format: port number must be between 1 to 65535"))
} }
ParseError::EmptyHost => return Err(Error::from_string("invalid URL endpoint format: empty host name")), ParseError::EmptyHost => return Err(Error::from_string("invalid URL endpoint format: empty host name")),
ParseError::RelativeUrlWithoutBase => { ParseError::RelativeUrlWithoutBase => {
// Only check if the arg is an ip address and ask for scheme since its absent. // like /foo
// localhost, example.com, any FQDN cannot be disambiguated from a regular file path such as is_local = true;
// /mnt/export1. So we go ahead and start the rustfs server in FS modes in these cases. url_parse_from_file_path(value)?
if net::is_socket_addr(value) {
return Err(Error::from_string("invalid URL endpoint format: missing scheme http or https"));
}
let file_path = match Path::new(value).absolutize() {
Ok(path) => path,
Err(err) => return Err(Error::from_string(format!("absolute path failed: {}", err))),
};
match Url::from_file_path(file_path) {
Ok(url) => {
is_local = true;
url
}
Err(_) => return Err(Error::from_string("Convert a file path into an URL failed")),
}
} }
_ => return Err(Error::from_string(format!("invalid URL endpoint format: {}", e))), _ => return Err(Error::from_string(format!("invalid URL endpoint format: {}", e))),
}, },
@@ -503,6 +491,26 @@ impl EndpointServerPools {
} }
} }
/// parse a file path into an URL.
fn url_parse_from_file_path(value: &str) -> Result<url::Url> {
// Only check if the arg is an ip address and ask for scheme since its absent.
// localhost, example.com, any FQDN cannot be disambiguated from a regular file path such as
// /mnt/export1. So we go ahead and start the rustfs server in FS modes in these cases.
if net::is_socket_addr(value) {
return Err(Error::from_string("invalid URL endpoint format: missing scheme http or https"));
}
let file_path = match Path::new(value).absolutize() {
Ok(path) => path,
Err(err) => return Err(Error::from_string(format!("absolute path failed: {}", err))),
};
match Url::from_file_path(file_path) {
Ok(url) => Ok(url),
Err(_) => return Err(Error::from_string("Convert a file path into an URL failed")),
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@@ -519,7 +527,7 @@ mod test {
let u2 = url::Url::parse("https://example.org/path").unwrap(); let u2 = url::Url::parse("https://example.org/path").unwrap();
let u4 = url::Url::parse("http://192.168.253.200/path").unwrap(); let u4 = url::Url::parse("http://192.168.253.200/path").unwrap();
let root_slash_foo = url::Url::from_file_path("d:/foo").unwrap(); let root_slash_foo = url::Url::from_file_path("/foo").unwrap();
let test_cases = [ let test_cases = [
TestCase { TestCase {