feat(pubky): use builder pattern for client::list()

This commit is contained in:
nazeh
2024-08-05 12:16:36 +03:00
parent ed4afeea60
commit 38d9c98caa
7 changed files with 132 additions and 61 deletions

View File

@@ -20,7 +20,7 @@ pub type EntriesTable = Database<Str, Bytes>;
pub const ENTRIES_TABLE: &str = "entries";
const MAX_LIST_LIMIT: i32 = 100;
const MAX_LIST_LIMIT: u16 = 100;
impl DB {
pub fn put_entry(
@@ -90,7 +90,7 @@ impl DB {
public_key: &PublicKey,
prefix: &str,
reverse: bool,
limit: Option<i32>,
limit: Option<u16>,
cursor: Option<String>,
) -> anyhow::Result<Vec<String>> {
let db = self.tables.entries;

View File

@@ -88,7 +88,7 @@ pub async fn get(
public_key,
path.as_str(),
params.contains_key("reverse"),
params.get("limit").and_then(|l| l.parse::<i32>().ok()),
params.get("limit").and_then(|l| l.parse::<u16>().ok()),
params.get("cursor").map(|cursor| cursor.into()),
)?;

View File

@@ -28,6 +28,9 @@ pub enum Error {
#[error("Recovery file encrypted secret key should be 32 bytes, got {0}")]
RecoverFileInvalidSecretKeyLength(usize),
#[error("Could not convert the passed type into a Url")]
InvalidUrl,
// === Transparent ===
#[error(transparent)]
Dns(#[from] SimpleDnsError),

View File

@@ -12,7 +12,10 @@ use url::Url;
use crate::{
error::Result,
shared::recovery_file::{create_recovery_file, decrypt_recovery_file},
shared::{
list_builder::ListBuilder,
recovery_file::{create_recovery_file, decrypt_recovery_file},
},
PubkyClient,
};
@@ -104,6 +107,10 @@ impl PubkyClient {
self.inner_delete(url).await
}
pub fn list<T: TryInto<Url>>(&self, url: T) -> Result<ListBuilder> {
self.inner_list(url)
}
// === Helpers ===
/// Create a recovery file of the `keypair`, containing the secret key encrypted

View File

@@ -0,0 +1,73 @@
use reqwest::{Method, Response, StatusCode};
use url::Url;
use crate::{error::Result, PubkyClient};
#[derive(Debug)]
pub struct ListBuilder<'a> {
url: Url,
reverse: bool,
limit: Option<u16>,
cursor: Option<&'a str>,
client: &'a PubkyClient,
}
impl<'a> ListBuilder<'a> {
pub fn new(client: &'a PubkyClient, url: Url) -> Self {
Self {
client,
url,
limit: None,
cursor: None,
reverse: false,
}
}
pub fn reverse(mut self, reverse: bool) -> Self {
self.reverse = reverse;
self
}
pub fn limit(mut self, limit: u16) -> Self {
self.limit = limit.into();
self
}
pub fn cursor(mut self, cursor: &'a str) -> Self {
self.cursor = cursor.into();
self
}
pub async fn send(self) -> Result<Vec<String>> {
let mut url = self.client.pubky_to_http(self.url).await?;
let mut query = url.query_pairs_mut();
query.append_key_only("list");
if self.reverse {
query.append_key_only("reverse");
}
if let Some(limit) = self.limit {
query.append_pair("limit", &limit.to_string());
}
if let Some(cursor) = self.cursor {
query.append_pair("cursor", cursor);
}
drop(query);
let response = self.client.request(Method::GET, url).send().await?;
response.error_for_status_ref()?;
// TODO: bail on too large files.
let bytes = response.bytes().await?;
Ok(String::from_utf8_lossy(&bytes)
.lines()
.map(String::from)
.collect())
}
}

View File

@@ -1,4 +1,5 @@
pub mod auth;
pub mod list_builder;
pub mod pkarr;
pub mod public;
pub mod recovery_file;

View File

@@ -9,7 +9,7 @@ use crate::{
PubkyClient,
};
use super::pkarr::Endpoint;
use super::{list_builder::ListBuilder, pkarr::Endpoint};
impl PubkyClient {
pub async fn inner_put<T: TryInto<Url>>(&self, url: T, content: &[u8]) -> Result<()> {
@@ -53,49 +53,15 @@ impl PubkyClient {
Ok(())
}
pub async fn list<T: TryInto<Url>>(
&self,
url: T,
reverse: bool,
limit: Option<i32>,
cursor: Option<&str>,
) -> Result<Vec<String>> {
let mut url = self.pubky_to_http(url).await?;
let mut query = url.query_pairs_mut();
query.append_key_only("list");
if reverse {
query.append_key_only("reverse");
}
if let Some(limit) = limit {
query.append_pair("limit", &limit.to_string());
}
if let Some(cursor) = cursor {
query.append_pair("cursor", cursor);
}
drop(query);
let response = self.request(Method::GET, url).send().await?;
response.error_for_status_ref()?;
// TODO: bail on too large files.
let bytes = response.bytes().await?;
Ok(String::from_utf8_lossy(&bytes)
.lines()
.map(String::from)
.collect())
pub fn inner_list<T: TryInto<Url>>(&self, url: T) -> Result<ListBuilder> {
Ok(ListBuilder::new(
self,
url.try_into().map_err(|_| Error::InvalidUrl)?,
))
}
async fn pubky_to_http<T: TryInto<Url>>(&self, url: T) -> Result<Url> {
let mut original_url: Url = url
.try_into()
.map_err(|e| Error::Generic("Invalid Url".to_string()))?;
pub(crate) async fn pubky_to_http<T: TryInto<Url>>(&self, url: T) -> Result<Url> {
let mut original_url: Url = url.try_into().map_err(|_| Error::InvalidUrl)?;
if original_url.scheme() != "pubky" {
return Ok(original_url);
@@ -272,7 +238,7 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client.list(url.as_str(), false, None, None).await.unwrap();
let list = client.list(url.as_str()).unwrap().send().await.unwrap();
assert_eq!(
list,
@@ -289,7 +255,10 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str(), false, Some(2), None)
.list(url.as_str())
.unwrap()
.limit(2)
.send()
.await
.unwrap();
@@ -306,7 +275,11 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str(), false, Some(2), Some("a.txt"))
.list(url.as_str())
.unwrap()
.limit(2)
.cursor("a.txt")
.send()
.await
.unwrap();
@@ -323,15 +296,14 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(
url.as_str(),
false,
Some(2),
Some(&format!(
"pubky://{}/pub/example.com/a.txt",
keypair.public_key()
)),
)
.list(url.as_str())
.unwrap()
.limit(2)
.cursor(&format!(
"pubky://{}/pub/example.com/a.txt",
keypair.public_key()
))
.send()
.await
.unwrap();
@@ -347,7 +319,13 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client.list(url.as_str(), true, None, None).await.unwrap();
let list = client
.list(url.as_str())
.unwrap()
.reverse(true)
.send()
.await
.unwrap();
assert_eq!(
list,
@@ -364,7 +342,11 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str(), true, Some(2), None)
.list(url.as_str())
.unwrap()
.reverse(true)
.limit(2)
.send()
.await
.unwrap();
@@ -381,7 +363,12 @@ mod tests {
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str(), true, Some(2), Some("d.txt"))
.list(url.as_str())
.unwrap()
.reverse(true)
.limit(2)
.cursor("d.txt")
.send()
.await
.unwrap();