Skip to main content

syncweb_core/folder/
public_subscription.rs

1use std::path::Path;
2
3use async_trait::async_trait;
4use iroh_blobs::Hash;
5
6use crate::error::Result;
7
8/// Lightweight metadata for a folder or subscription entry.
9#[derive(Clone, Debug)]
10#[non_exhaustive]
11pub struct EntryLike {
12    pub path: String,
13    pub hash: Hash,
14    pub size: u64,
15}
16
17/// Common trait for folders and subscriptions that commands can operate on.
18#[async_trait]
19pub trait FolderLike: Send + Sync {
20    fn namespace_id(&self) -> String;
21    fn label(&self) -> String;
22    fn kind(&self) -> &'static str;
23    fn path(&self) -> Option<&Path>;
24    async fn list_entries(&self) -> Result<Vec<EntryLike>>;
25}
26
27/// A public blob subscription. Stores enough to identify the blob and
28/// reconstruct the ticket (hash + provider). Size is cached since it never
29/// changes for content-addressed blobs.
30#[derive(Clone, Debug)]
31pub struct PublicSubscription {
32    hash: Hash,
33    provider: Option<iroh::EndpointAddr>,
34    size: u64,
35}
36
37impl PublicSubscription {
38    #[must_use]
39    pub const fn new(hash: Hash, provider: Option<iroh::EndpointAddr>, size: u64) -> Self {
40        Self { hash, provider, size }
41    }
42
43    #[must_use]
44    pub const fn hash(&self) -> Hash {
45        self.hash
46    }
47
48    #[must_use]
49    pub const fn size(&self) -> u64 {
50        self.size
51    }
52
53    #[must_use]
54    pub const fn provider(&self) -> Option<&iroh::EndpointAddr> {
55        self.provider.as_ref()
56    }
57
58    /// Reconstruct a blob ticket from the stored hash and provider.
59    /// Returns `None` if no provider was recorded with this subscription.
60    #[must_use]
61    pub fn ticket(&self) -> Option<iroh_blobs::ticket::BlobTicket> {
62        self.provider
63            .as_ref()
64            .map(|addr| iroh_blobs::ticket::BlobTicket::new(addr.clone(), self.hash, iroh_blobs::BlobFormat::Raw))
65    }
66
67    #[must_use]
68    pub fn label(&self) -> String {
69        let hex = self.hash.to_string();
70        format!("{}..", &hex[..hex.len().min(12)])
71    }
72}
73
74#[async_trait]
75impl FolderLike for PublicSubscription {
76    fn namespace_id(&self) -> String {
77        format!("blob:{}", self.hash())
78    }
79
80    fn label(&self) -> String {
81        self.label()
82    }
83
84    fn kind(&self) -> &'static str {
85        "subscription"
86    }
87
88    fn path(&self) -> Option<&Path> {
89        None
90    }
91
92    async fn list_entries(&self) -> Result<Vec<EntryLike>> {
93        Ok(vec![EntryLike {
94            path: self.label(),
95            hash: self.hash(),
96            size: self.size(),
97        }])
98    }
99}