Skip to content

Commit

Permalink
feat(pubky): shallow list folder and files
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Aug 7, 2024
1 parent dd2c9ea commit e10cf77
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 18 deletions.
69 changes: 56 additions & 13 deletions pubky-homeserver/src/database/tables/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,39 +98,82 @@ impl DB {
cursor: Option<String>,
shallow: bool,
) -> anyhow::Result<Vec<String>> {
// Vector to store results
let mut results = Vec::new();

let limit = limit.unwrap_or(MAX_LIST_LIMIT).min(MAX_LIST_LIMIT);

// Remove directories from the cursor;
let cursor = cursor
.as_deref()
.and_then(|mut cursor| cursor.rsplit('/').next())
.unwrap_or(if reverse { "~" } else { "" });

let cursor = format!("{path}{cursor}");
let mut cursor = cursor.as_str();

let limit = limit.unwrap_or(MAX_LIST_LIMIT).min(MAX_LIST_LIMIT);

// Vector to store results
let mut results = Vec::new();
let mut cursor = format!("{path}{cursor}");

// Fetch data based on direction
if reverse {
for _ in 0..limit {
if let Some((key, _)) = self.tables.entries.get_lower_than(txn, cursor)? {
if let Some((key, _)) = self.tables.entries.get_lower_than(txn, &cursor)? {
if !key.starts_with(path) {
break;
}
cursor = key;
results.push(format!("pubky://{}", key))

if shallow {
let mut split = key[path.len()..].split('/');
let item = split.next().expect("should not be reachable");

let is_directory = split.next().is_some();

cursor = format!(
"{}{}",
&key[..(path.len() + item.len())],
// `.` is immediately lower than `/`
if is_directory { "." } else { "" }
);

let url = format!(
"pubky://{path}{item}{}",
if is_directory { "/" } else { "" }
);

results.push(url);
} else {
cursor = key.to_string();
results.push(format!("pubky://{}", key))
}
};
}
} else {
for _ in 0..limit {
if let Some((key, _)) = self.tables.entries.get_greater_than(txn, cursor)? {
if let Some((key, _)) = self.tables.entries.get_greater_than(txn, &cursor)? {
if !key.starts_with(path) {
break;
}
cursor = key;
results.push(format!("pubky://{}", key))

if shallow {
let mut split = key[path.len()..].split('/');
let item = split.next().expect("should not be reachable");

let is_directory = split.next().is_some();

cursor = format!(
"{}{}",
&key[..(path.len() + item.len())],
// `0` is immediately higher than `/`
if is_directory { "0" } else { "" }
);

let url = format!(
"pubky://{path}{item}{}",
if is_directory { "/" } else { "" }
);

results.push(url);
} else {
cursor = key.to_string();
results.push(format!("pubky://{}", key))
}
};
}
};
Expand Down
15 changes: 13 additions & 2 deletions pubky/src/shared/list_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct ListBuilder<'a> {
limit: Option<u16>,
cursor: Option<&'a str>,
client: &'a PubkyClient,
shallow: bool,
}

impl<'a> ListBuilder<'a> {
Expand All @@ -21,12 +22,13 @@ impl<'a> ListBuilder<'a> {
limit: None,
cursor: None,
reverse: false,
shallow: false,
}
}

/// Set the `reverse` option.
pub fn reverse(mut self, reverse: bool) -> Self {
self.reverse = reverse;
pub fn reverse(mut self) -> Self {
self.reverse = true;
self
}

Expand All @@ -44,6 +46,11 @@ impl<'a> ListBuilder<'a> {
self
}

pub fn shallow(mut self) -> Self {
self.shallow = true;
self
}

/// Send the list request.
///
/// Returns a list of Pubky URLs of the files in the path of the `url`
Expand All @@ -68,6 +75,10 @@ impl<'a> ListBuilder<'a> {
query.append_key_only("reverse");
}

if self.shallow {
query.append_key_only("shallow");
}

if let Some(limit) = self.limit {
query.append_pair("limit", &limit.to_string());
}
Expand Down
86 changes: 83 additions & 3 deletions pubky/src/shared/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ mod tests {
let list = client
.list(url.as_str())
.unwrap()
.reverse(true)
.reverse()
.send()
.await
.unwrap();
Expand All @@ -340,7 +340,7 @@ mod tests {
let list = client
.list(url.as_str())
.unwrap()
.reverse(true)
.reverse()
.limit(2)
.send()
.await
Expand All @@ -360,7 +360,7 @@ mod tests {
let list = client
.list(url.as_str())
.unwrap()
.reverse(true)
.reverse()
.limit(2)
.cursor("d.txt")
.send()
Expand All @@ -377,4 +377,84 @@ mod tests {
);
}
}

#[tokio::test]
async fn list_shallow() {
let testnet = Testnet::new(10);
let server = Homeserver::start_test(&testnet).await.unwrap();

let client = PubkyClient::test(&testnet);

let keypair = Keypair::random();

client.signup(&keypair, &server.public_key()).await.unwrap();

let urls = vec![
format!("pubky://{}/pub/a.com/a.txt", keypair.public_key()),
format!("pubky://{}/pub/example.com/a.txt", keypair.public_key()),
format!("pubky://{}/pub/example.com/b.txt", keypair.public_key()),
format!("pubky://{}/pub/example.com/c.txt", keypair.public_key()),
format!("pubky://{}/pub/example.com/d.txt", keypair.public_key()),
format!("pubky://{}/pub/example.con/d.txt", keypair.public_key()),
format!("pubky://{}/pub/example.con", keypair.public_key()),
format!("pubky://{}/pub/file", keypair.public_key()),
format!("pubky://{}/pub/file2", keypair.public_key()),
format!("pubky://{}/pub/z.com/a.txt", keypair.public_key()),
];

for url in urls {
client.put(url.as_str(), &[0]).await.unwrap();
}

let url = format!("pubky://{}/pub/", keypair.public_key());

{
let list = client
.list(url.as_str())
.unwrap()
.shallow()
.send()
.await
.unwrap();

assert_eq!(
list,
vec![
format!("pubky://{}/pub/a.com/", keypair.public_key()),
format!("pubky://{}/pub/example.com/", keypair.public_key()),
format!("pubky://{}/pub/example.con", keypair.public_key()),
format!("pubky://{}/pub/example.con/", keypair.public_key()),
format!("pubky://{}/pub/file", keypair.public_key()),
format!("pubky://{}/pub/file2", keypair.public_key()),
format!("pubky://{}/pub/z.com/", keypair.public_key()),
],
"normal list shallow"
);
}

{
let list = client
.list(url.as_str())
.unwrap()
.shallow()
.reverse()
.send()
.await
.unwrap();

assert_eq!(
list,
vec![
format!("pubky://{}/pub/z.com/", keypair.public_key()),
format!("pubky://{}/pub/file2", keypair.public_key()),
format!("pubky://{}/pub/file", keypair.public_key()),
format!("pubky://{}/pub/example.con/", keypair.public_key()),
format!("pubky://{}/pub/example.con", keypair.public_key()),
format!("pubky://{}/pub/example.com/", keypair.public_key()),
format!("pubky://{}/pub/a.com/", keypair.public_key()),
],
"reverse list shallow"
);
}
}
}

0 comments on commit e10cf77

Please sign in to comment.