Skip to content

Commit 7b0a7c7

Browse files
feat: add api to list collections
This splits out listing content by blobs and collections
1 parent dfcbf7e commit 7b0a7c7

5 files changed

Lines changed: 123 additions & 25 deletions

File tree

src/blobs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use crate::util::Hash;
88
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
99
pub struct Collection {
1010
/// Links to the blobs in this collection
11-
blobs: Vec<Blob>,
11+
pub(crate) blobs: Vec<Blob>,
1212
/// The total size of the raw_data referred to by all links
13-
total_blobs_size: u64,
13+
pub(crate) total_blobs_size: u64,
1414
}
1515

1616
impl Collection {

src/main.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use iroh::protocol::{GetRequest, RangeSpecSeq};
1818
use iroh::provider::{Database, Provider, Ticket};
1919
use iroh::rpc_protocol::*;
2020
use iroh::rpc_protocol::{
21-
ListRequest, ProvideRequest, ProviderRequest, ProviderResponse, ProviderService, VersionRequest,
21+
ProvideRequest, ProviderRequest, ProviderResponse, ProviderService, VersionRequest,
2222
};
2323
use quic_rpc::transport::quinn::{QuinnConnection, QuinnServerEndpoint};
2424
use quic_rpc::{RpcClient, ServiceEndpoint};
@@ -123,12 +123,9 @@ enum Commands {
123123
#[clap(long, default_value_t = ProviderRpcPort::Enabled(DEFAULT_RPC_PORT))]
124124
rpc_port: ProviderRpcPort,
125125
},
126-
/// List hashes on the running provider.
127-
List {
128-
/// RPC port of the provider
129-
#[clap(long, default_value_t = DEFAULT_RPC_PORT)]
130-
rpc_port: u16,
131-
},
126+
/// List availble content on the provider.
127+
#[clap(subcommand)]
128+
List(ListCommands),
132129
/// Validate hashes on the running provider.
133130
Validate {
134131
/// RPC port of the provider
@@ -198,6 +195,22 @@ enum Commands {
198195
},
199196
}
200197

198+
#[derive(Subcommand, Debug, Clone)]
199+
enum ListCommands {
200+
/// List the available blobs on the running provider.
201+
Blobs {
202+
/// RPC port of the provider
203+
#[clap(long, default_value_t = DEFAULT_RPC_PORT)]
204+
rpc_port: u16,
205+
},
206+
/// List the available collections on the running provider.
207+
Collections {
208+
/// RPC port of the provider
209+
#[clap(long, default_value_t = DEFAULT_RPC_PORT)]
210+
rpc_port: u16,
211+
},
212+
}
213+
201214
// Note about writing to STDOUT vs STDERR
202215
// Looking at https://unix.stackexchange.com/questions/331611/do-progress-reports-logging-information-belong-on-stderr-or-stdout
203216
// it is a little complicated.
@@ -616,9 +629,9 @@ async fn main_impl() -> Result<()> {
616629
drop(fut);
617630
Ok(())
618631
}
619-
Commands::List { rpc_port } => {
632+
Commands::List(ListCommands::Blobs { rpc_port }) => {
620633
let client = make_rpc_client(rpc_port).await?;
621-
let mut response = client.server_streaming(ListRequest).await?;
634+
let mut response = client.server_streaming(ListBlobsRequest).await?;
622635
while let Some(item) = response.next().await {
623636
let item = item?;
624637
println!(
@@ -630,6 +643,25 @@ async fn main_impl() -> Result<()> {
630643
}
631644
Ok(())
632645
}
646+
Commands::List(ListCommands::Collections { rpc_port }) => {
647+
let client = make_rpc_client(rpc_port).await?;
648+
let mut response = client.server_streaming(ListCollectionsRequest).await?;
649+
while let Some(collection) = response.next().await {
650+
let collection = collection?;
651+
println!(
652+
"{}: {} {} ({})",
653+
Blake3Cid(collection.hash),
654+
collection.total_blobs_count,
655+
if collection.total_blobs_count > 1 {
656+
"blobs"
657+
} else {
658+
"blob"
659+
},
660+
HumanBytes(collection.total_blobs_size),
661+
);
662+
}
663+
Ok(())
664+
}
633665
Commands::Validate { rpc_port } => {
634666
let client = make_rpc_client(rpc_port).await?;
635667
let mut state = ValidateProgressState::new();

src/provider/database.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::BlobOrCollection;
22
use crate::{
3+
blobs::Collection,
34
rpc_protocol::ValidateProgress,
45
util::{validate_bao, BaoValidationError},
56
Hash,
@@ -439,6 +440,25 @@ impl Database {
439440
items.into_iter()
440441
}
441442

443+
/// Iterate over all collections in the database.
444+
pub fn collections(&self) -> impl Iterator<Item = (Hash, Collection)> + 'static {
445+
let items = self
446+
.0
447+
.read()
448+
.unwrap()
449+
.iter()
450+
.filter_map(|(hash, v)| match v {
451+
BlobOrCollection::Blob { .. } => None,
452+
BlobOrCollection::Collection { data, .. } => {
453+
Collection::from_bytes(&data[..]).ok().map(|c| (*hash, c))
454+
}
455+
})
456+
.collect::<Vec<_>>();
457+
// todo: make this a proper lazy iterator at some point
458+
// e.g. by using an immutable map or a real database that supports snapshots.
459+
items.into_iter()
460+
}
461+
442462
/// Unwrap into the inner HashMap
443463
pub fn to_inner(&self) -> HashMap<Hash, BlobOrCollection> {
444464
self.0.read().unwrap().clone()

src/provider/mod.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ use crate::protocol::{
4242
read_lp, write_lp, Closed, GetRequest, Handshake, RangeSpec, Request, VERSION,
4343
};
4444
use crate::rpc_protocol::{
45-
AddrsRequest, AddrsResponse, IdRequest, IdResponse, ListRequest, ListResponse, ProvideProgress,
46-
ProvideRequest, ProviderRequest, ProviderResponse, ProviderService, ShutdownRequest,
47-
ValidateProgress, ValidateRequest, VersionRequest, VersionResponse, WatchRequest,
48-
WatchResponse,
45+
AddrsRequest, AddrsResponse, IdRequest, IdResponse, ListBlobsRequest, ListBlobsResponse,
46+
ListCollectionsRequest, ListCollectionsResponse, ProvideProgress, ProvideRequest,
47+
ProviderRequest, ProviderResponse, ProviderService, ShutdownRequest, ValidateProgress,
48+
ValidateRequest, VersionRequest, VersionResponse, WatchRequest, WatchResponse,
4949
};
5050
use crate::tls::{self, Keypair, PeerId};
5151
use crate::tokio_util::read_as_bytes;
@@ -544,12 +544,31 @@ struct RpcHandler {
544544
}
545545

546546
impl RpcHandler {
547-
fn list(self, _msg: ListRequest) -> impl Stream<Item = ListResponse> + Send + 'static {
547+
fn list_blobs(
548+
self,
549+
_msg: ListBlobsRequest,
550+
) -> impl Stream<Item = ListBlobsResponse> + Send + 'static {
548551
let items = self
549552
.inner
550553
.db
551554
.blobs()
552-
.map(|(hash, path, size)| ListResponse { hash, path, size });
555+
.map(|(hash, path, size)| ListBlobsResponse { hash, path, size });
556+
futures::stream::iter(items)
557+
}
558+
559+
fn list_collections(
560+
self,
561+
_msg: ListCollectionsRequest,
562+
) -> impl Stream<Item = ListCollectionsResponse> + Send + 'static {
563+
let items = self
564+
.inner
565+
.db
566+
.collections()
567+
.map(|(hash, collection)| ListCollectionsResponse {
568+
hash,
569+
total_blobs_count: collection.blobs.len(),
570+
total_blobs_size: collection.total_blobs_size,
571+
});
553572
futures::stream::iter(items)
554573
}
555574

@@ -676,7 +695,14 @@ fn handle_rpc_request<C: ServiceEndpoint<ProviderService>>(
676695
tokio::spawn(async move {
677696
use ProviderRequest::*;
678697
match msg {
679-
List(msg) => chan.server_streaming(msg, handler, RpcHandler::list).await,
698+
ListBlobs(msg) => {
699+
chan.server_streaming(msg, handler, RpcHandler::list_blobs)
700+
.await
701+
}
702+
ListCollections(msg) => {
703+
chan.server_streaming(msg, handler, RpcHandler::list_collections)
704+
.await
705+
}
680706
Provide(msg) => {
681707
chan.server_streaming(msg, handler, RpcHandler::provide)
682708
.await

src/rpc_protocol.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,39 @@ impl ServerStreamingMsg<ProviderService> for ValidateRequest {
7171
}
7272

7373
#[derive(Debug, Serialize, Deserialize)]
74-
pub struct ListRequest;
74+
pub struct ListBlobsRequest;
7575

7676
#[derive(Debug, Serialize, Deserialize)]
77-
pub struct ListResponse {
77+
pub struct ListBlobsResponse {
7878
pub path: PathBuf,
7979
pub hash: Hash,
8080
pub size: u64,
8181
}
8282

83-
impl Msg<ProviderService> for ListRequest {
83+
impl Msg<ProviderService> for ListBlobsRequest {
8484
type Pattern = ServerStreaming;
8585
}
8686

87-
impl ServerStreamingMsg<ProviderService> for ListRequest {
88-
type Response = ListResponse;
87+
impl ServerStreamingMsg<ProviderService> for ListBlobsRequest {
88+
type Response = ListBlobsResponse;
89+
}
90+
91+
#[derive(Debug, Serialize, Deserialize)]
92+
pub struct ListCollectionsRequest;
93+
94+
#[derive(Debug, Serialize, Deserialize)]
95+
pub struct ListCollectionsResponse {
96+
pub hash: Hash,
97+
pub total_blobs_count: usize,
98+
pub total_blobs_size: u64,
99+
}
100+
101+
impl Msg<ProviderService> for ListCollectionsRequest {
102+
type Pattern = ServerStreaming;
103+
}
104+
105+
impl ServerStreamingMsg<ProviderService> for ListCollectionsRequest {
106+
type Response = ListCollectionsResponse;
89107
}
90108

91109
#[derive(Serialize, Deserialize, Debug)]
@@ -160,7 +178,8 @@ pub struct ProviderService;
160178
pub enum ProviderRequest {
161179
Watch(WatchRequest),
162180
Version(VersionRequest),
163-
List(ListRequest),
181+
ListBlobs(ListBlobsRequest),
182+
ListCollections(ListCollectionsRequest),
164183
Provide(ProvideRequest),
165184
Id(IdRequest),
166185
Addrs(AddrsRequest),
@@ -173,7 +192,8 @@ pub enum ProviderRequest {
173192
pub enum ProviderResponse {
174193
Watch(WatchResponse),
175194
Version(VersionResponse),
176-
List(ListResponse),
195+
ListBlobs(ListBlobsResponse),
196+
ListCollections(ListCollectionsResponse),
177197
Provide(ProvideProgress),
178198
Id(IdResponse),
179199
Addrs(AddrsResponse),

0 commit comments

Comments
 (0)