Skip to content

Commit

Permalink
Add discoverability feature to DataBroker
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaeling committed Aug 23, 2023
1 parent 85c2b8c commit 91bcc29
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 54 deletions.
27 changes: 27 additions & 0 deletions kuksa_databroker/databroker/src/broker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,24 @@ impl<'a, 'b> DatabaseReadAccess<'a, 'b> {
}
}

pub fn get_entries_by_regex(&self, regex: regex::Regex) -> Result<Vec<Entry>, ReadError> {
let mut entries: Vec<Entry> = Vec::new();
for key in self.db.path_to_id.keys() {
if regex.is_match(key) {
entries.push(
self.get_entry_by_id(self.db.path_to_id.get(key).unwrap().to_owned())
.unwrap()
.to_owned(),
);
}
}
if entries.is_empty() {
return Err(ReadError::NotFound);
}

Ok(entries)
}

pub fn get_metadata_by_id(&self, id: i32) -> Option<&Metadata> {
self.db.entries.get(&id).map(|entry| &entry.metadata)
}
Expand Down Expand Up @@ -1159,6 +1177,15 @@ impl<'a, 'b> AuthorizedAccess<'a, 'b> {
.cloned()
}

pub async fn get_entries_by_regex(&self, regex: regex::Regex) -> Result<Vec<Entry>, ReadError> {
self.broker
.database
.read()
.await
.authorized_read_access(self.permissions)
.get_entries_by_regex(regex)
}

pub async fn get_entry_by_id(&self, id: i32) -> Result<Entry, ReadError> {
self.broker
.database
Expand Down
165 changes: 153 additions & 12 deletions kuksa_databroker/databroker/src/glob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use regex::Regex;

#[derive(Debug)]
pub enum Error {
RegexError,
}
Expand All @@ -24,20 +25,30 @@ pub fn to_regex_string(glob: &str) -> String {
// Start from the beginning
let mut re = String::from("^");

// Replace all "standalone" wildcards with ".*"
re.push_str(
&glob
.split('.')
.map(|part| match part {
"*" => ".*",
other => other,
})
.collect::<Vec<&str>>()
.join(r"\."),
);
if glob.ends_with(".*") {
re.push_str(glob.replace(".*", ".[^.]+").as_str());
} else if glob.ends_with(".**") {
re.push_str(glob.replace(".**", ".*").as_str());
} else {
// Replace all "standalone" wildcards with ".*"
re.push_str(
&glob
.split('.')
.map(|part| match part {
"**" => ".*",
other => other,
})
.collect::<Vec<&str>>()
.join(r"\."),
);
}

// If it doesn't already end with a wildcard, add it
if !re.ends_with(".*") {
if !re.starts_with("^*")
&& !re.starts_with("^.*")
&& !re.ends_with(".*")
&& !re.ends_with("[^.]+")
{
re.push_str(".*");
}

Expand All @@ -51,3 +62,133 @@ pub fn to_regex(glob: &str) -> Result<Regex, Error> {
let re = to_regex_string(glob);
Regex::new(&re).map_err(|_err| Error::RegexError)
}

pub fn is_valid_pattern(input: &str) -> bool {
let re = regex::Regex::new(
r"(?x)
^ # anchor at start (only match full paths)
# At least one subpath (consisting of either of three):
(?:
[A-Z][a-zA-Z0-9]* # An alphanumeric name (first letter capitalized)
|
\* # An asterisk
|
\*\* # A double asterisk
)
# which can be followed by ( separator + another subpath )
# repeated any number of times
(?:
\. # Separator, literal dot
(?:
[A-Z][a-zA-Z0-9]* # Alphanumeric name (first letter capitalized)
|
\* # An asterisk
|
\*\* # A double asterisk
)
)*
$ # anchor at end (to match only full paths)
",
)
.unwrap();

re.is_match(input)
}

#[tokio::test]
async fn test_valid_request_path() {
assert!(is_valid_pattern("String.*"));
assert!(is_valid_pattern("String.**"));
assert!(is_valid_pattern("Vehicle.Chassis.Axle.Row2.Wheel.*"));
assert!(is_valid_pattern("String.String.String.String.*"));
assert!(is_valid_pattern("String.String.String.String.**"));
assert!(is_valid_pattern("String.String.String.String"));
assert!(is_valid_pattern("String.String.String.String.String.**"));
assert!(is_valid_pattern("String.String.String.*.String"));
assert!(is_valid_pattern("String.String.String.**.String"));
assert!(is_valid_pattern(
"String.String.String.String.String.**.String"
));
assert!(is_valid_pattern(
"String.String.String.String.*.String.String"
));

assert!(is_valid_pattern("String.*.String.String"));
assert!(is_valid_pattern("String.String.**.String.String"));
assert!(is_valid_pattern("String.**.String.String"));
assert!(is_valid_pattern("**.String.String.String.**"));
assert!(is_valid_pattern("**.String.String.String.*"));
assert!(is_valid_pattern("**.String"));
assert!(is_valid_pattern("*.String.String.String"));
assert!(is_valid_pattern("*.String"));
assert!(!is_valid_pattern("String.String.String."));
assert!(!is_valid_pattern("String.String.String.String.."));
assert!(!is_valid_pattern("String.*.String.String.."));
assert!(!is_valid_pattern("*.String.String.String.."));
}

#[tokio::test]
async fn test_valid_regex_path() {
assert_eq!(to_regex_string("String.*"), "^String.[^.]+$");
assert_eq!(to_regex_string("String.**"), "^String.*$");
assert_eq!(
to_regex_string("String.String.String.String.*"),
"^String.String.String.String.[^.]+$"
);
assert_eq!(
to_regex_string("String.String.String.String.**"),
"^String.String.String.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.String"),
"^String\\.String\\.String\\.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.String.String.**"),
"^String.String.String.String.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.*.String"),
"^String\\.String\\.String\\.*\\.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.**.String"),
"^String\\.String\\.String\\..*\\.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.String.String.**.String"),
"^String\\.String\\.String\\.String\\.String\\..*\\.String.*$"
);
assert_eq!(
to_regex_string("String.String.String.String.*.String.String"),
"^String\\.String\\.String\\.String\\.*\\.String\\.String.*$"
);
assert_eq!(
to_regex_string("String.*.String.String"),
"^String\\.*\\.String\\.String.*$"
);
assert_eq!(
to_regex_string("String.String.**.String.String"),
"^String\\.String\\..*\\.String\\.String.*$"
);
assert_eq!(
to_regex_string("String.**.String.String"),
"^String\\..*\\.String\\.String.*$"
);
assert_eq!(
to_regex_string("**.String.String.String.**"),
"^**.String.String.String.*$"
);
assert_eq!(
to_regex_string("**.String.String.String.*"),
"^**.String.String.String.[^.]+$"
);
assert_eq!(to_regex_string("**.String"), "^.*\\.String$");
assert_eq!(to_regex_string("*.String"), "^*\\.String$");
assert_eq!(
to_regex_string("*.String.String.String"),
"^*\\.String\\.String\\.String$"
);
}
Loading

0 comments on commit 91bcc29

Please sign in to comment.