feat(js): add list() method

This commit is contained in:
nazeh
2024-08-05 16:34:26 +03:00
parent 38d9c98caa
commit 1db1d3a21d
6 changed files with 207 additions and 14 deletions

View File

@@ -40,5 +40,5 @@ tokio = "1.37.0"
[package.metadata.docs.rs]
all-features = true
# [package.metadata.wasm-pack.profile.release]
# wasm-opt = ['-g', '-O']
[package.metadata.wasm-pack.profile.release]
wasm-opt = ['-g', '-O']

View File

@@ -111,3 +111,135 @@ test("forbidden", async (t) => {
`HTTP status client error (403 Forbidden) for url (http://localhost:15411/${publicKey.z32()}/priv/example.com/arbitrary)`
)
})
test("list", async (t) => {
const client = PubkyClient.testnet();
const keypair = Keypair.random()
const publicKey = keypair.publicKey()
const pubky = publicKey.z32()
const homeserver = PublicKey.from('8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo')
await client.signup(keypair, homeserver)
let urls = [
`pubky://${pubky}/pub/a.wrong/a.txt`,
`pubky://${pubky}/pub/example.com/a.txt`,
`pubky://${pubky}/pub/example.com/b.txt`,
`pubky://${pubky}/pub/example.wrong/a.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
`pubky://${pubky}/pub/example.com/d.txt`,
`pubky://${pubky}/pub/z.wrong/a.txt`,
]
for (let url of urls) {
await client.put(url, Buffer.from(""));
}
let url = `pubky://${pubky}/pub/example.com/`;
{
let list = await client.list(url);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/a.txt`,
`pubky://${pubky}/pub/example.com/b.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
`pubky://${pubky}/pub/example.com/d.txt`,
],
"normal list with no limit or cursor"
);
}
{
let list = await client.list(url, null, null, 2);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/a.txt`,
`pubky://${pubky}/pub/example.com/b.txt`,
],
"normal list with limit but no cursor"
);
}
{
let list = await client.list(url, "a.txt", null, 2);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/b.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
],
"normal list with limit and a suffix cursor"
);
}
{
let list = await client.list(url, `pubky://${pubky}/pub/example.com/a.txt`, null, 2);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/b.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
],
"normal list with limit and a full url cursor"
);
}
{
let list = await client.list(url, null, true);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/d.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
`pubky://${pubky}/pub/example.com/b.txt`,
`pubky://${pubky}/pub/example.com/a.txt`,
],
"reverse list with no limit or cursor"
);
}
{
let list = await client.list(url, null, true, 2);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/d.txt`,
`pubky://${pubky}/pub/example.com/c.txt`,
],
"reverse list with limit but no cursor"
);
}
{
let list = await client.list(url, "d.txt", true, 2);
t.deepEqual(
list,
[
`pubky://${pubky}/pub/example.com/c.txt`,
`pubky://${pubky}/pub/example.com/b.txt`,
],
"reverse list with limit and a suffix cursor"
);
}
})

View File

@@ -107,6 +107,9 @@ impl PubkyClient {
self.inner_delete(url).await
}
/// Returns a [ListBuilder] to help pass options before calling [ListBuilder::send].
///
/// `url` sets the path you want to lest within.
pub fn list<T: TryInto<Url>>(&self, url: T) -> Result<ListBuilder> {
self.inner_list(url)
}

View File

@@ -13,6 +13,7 @@ pub struct ListBuilder<'a> {
}
impl<'a> ListBuilder<'a> {
/// Create a new List request builder
pub fn new(client: &'a PubkyClient, url: Url) -> Self {
Self {
client,
@@ -23,21 +24,31 @@ impl<'a> ListBuilder<'a> {
}
}
/// Set the `reverse` option.
pub fn reverse(mut self, reverse: bool) -> Self {
self.reverse = reverse;
self
}
/// Set the `limit` value.
pub fn limit(mut self, limit: u16) -> Self {
self.limit = limit.into();
self
}
/// Set the `cursor` value.
///
/// usually the last url from previous responses.
pub fn cursor(mut self, cursor: &'a str) -> Self {
self.cursor = cursor.into();
self
}
/// Send the list request.
///
/// Returns a list of Pubky URLs of the files in the path of the `url`
/// respecting [ListBuilder::reverse], [ListBuilder::limit] and [ListBuilder::cursor]
/// options.
pub async fn send(self) -> Result<Vec<String>> {
let mut url = self.client.pubky_to_http(self.url).await?;

View File

@@ -236,8 +236,9 @@ mod tests {
client.put(url.as_str(), &[0]).await.unwrap();
}
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client.list(url.as_str()).unwrap().send().await.unwrap();
assert_eq!(
@@ -253,7 +254,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()
@@ -273,7 +273,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()
@@ -294,7 +293,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()
@@ -318,7 +316,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()
@@ -340,7 +337,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()
@@ -361,7 +357,6 @@ mod tests {
}
{
let url = format!("pubky://{}/pub/example.com/", keypair.public_key());
let list = client
.list(url.as_str())
.unwrap()

View File

@@ -3,7 +3,8 @@ use std::{
sync::{Arc, RwLock},
};
use wasm_bindgen::prelude::*;
use js_sys::{Array, Uint8Array};
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
use reqwest::{IntoUrl, Method, RequestBuilder, Response};
use url::Url;
@@ -58,7 +59,7 @@ impl PubkyClient {
pub fn create_recovery_file(
keypair: &Keypair,
passphrase: &str,
) -> Result<js_sys::Uint8Array, JsValue> {
) -> Result<Uint8Array, JsValue> {
create_recovery_file(keypair.as_inner(), passphrase)
.map(|b| b.as_slice().into())
.map_err(|e| e.into())
@@ -138,18 +139,69 @@ impl PubkyClient {
self.inner_put(url, content).await.map_err(|e| e.into())
}
#[wasm_bindgen]
/// Download a small payload from a given path relative to a pubky author.
pub async fn get(&self, url: &str) -> Result<Option<js_sys::Uint8Array>, JsValue> {
#[wasm_bindgen]
pub async fn get(&self, url: &str) -> Result<Option<Uint8Array>, JsValue> {
self.inner_get(url)
.await
.map(|b| b.map(|b| (&*b).into()))
.map_err(|e| e.into())
}
#[wasm_bindgen]
/// Delete a file at a path relative to a pubky author.
#[wasm_bindgen]
pub async fn delete(&self, url: &str) -> Result<(), JsValue> {
self.inner_delete(url).await.map_err(|e| e.into())
}
/// Returns a list of Pubky URLs of the files within the `url` path,
/// respecting the `cursor`, `reverse` and `limit` options.
///
/// `cursor` is usually the last url from previous responses.
#[wasm_bindgen]
pub async fn list(
&self,
url: &str,
cursor: Option<String>,
reverse: Option<bool>,
limit: Option<u16>,
) -> Result<Array, JsValue> {
// TODO: try later to return Vec<String> from async function.
if let Some(cursor) = cursor {
return self
.inner_list(url)?
.reverse(reverse.unwrap_or(false))
.limit(limit.unwrap_or(u16::MAX))
.cursor(&cursor)
.send()
.await
.map(|urls| {
let js_array = Array::new();
for url in urls {
js_array.push(&JsValue::from_str(&url));
}
js_array
})
.map_err(|e| e.into());
}
self.inner_list(url)?
.reverse(reverse.unwrap_or(false))
.limit(limit.unwrap_or(u16::MAX))
.send()
.await
.map(|urls| {
let js_array = Array::new();
for url in urls {
js_array.push(&JsValue::from_str(&url));
}
js_array
})
.map_err(|e| e.into())
}
}