lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

client.rs (4625B)


      1 //! Curated client construction and operation entry points.
      2 
      3 #[cfg(any(feature = "nostr", feature = "full"))]
      4 use std::sync::Arc;
      5 
      6 #[cfg(any(feature = "nostr", feature = "full"))]
      7 use radroots_transport::{EventSink, EventSource};
      8 
      9 #[cfg(any(
     10     feature = "client",
     11     feature = "native",
     12     feature = "nostr",
     13     feature = "nip46",
     14     feature = "full"
     15 ))]
     16 use crate::ClientBuilder;
     17 use crate::transport::Profile;
     18 
     19 /// Creates the safe ordinary client builder with deterministic in-process
     20 /// storage and no transport, signer, runtime, worker, or file authority.
     21 #[cfg(feature = "client")]
     22 #[must_use]
     23 pub fn memory() -> ClientBuilder {
     24     ClientBuilder::memory_default()
     25 }
     26 
     27 /// Returns the explicit no-transport profile used by ordinary local work.
     28 #[must_use]
     29 pub const fn local_only() -> Profile {
     30     Profile::local_only()
     31 }
     32 
     33 /// Adds caller-owned source and sink capabilities without connecting them or
     34 /// selecting a fallback transport.
     35 #[cfg(any(feature = "nostr", feature = "full"))]
     36 #[must_use]
     37 pub fn with_transport(
     38     builder: ClientBuilder,
     39     source: Arc<dyn EventSource>,
     40     sink: Arc<dyn EventSink>,
     41 ) -> ClientBuilder {
     42     builder.source(source).sink(sink)
     43 }
     44 
     45 /// Adds an explicitly constructed NIP-46 signer provider.
     46 #[cfg(any(feature = "nip46", feature = "full"))]
     47 #[must_use]
     48 #[cfg_attr(coverage_nightly, coverage(off))]
     49 pub fn with_nip46_signer(
     50     builder: ClientBuilder,
     51     provider: crate::signing::Provider,
     52 ) -> ClientBuilder {
     53     builder.signing(provider)
     54 }
     55 
     56 /// Explicitly opens validated native SQLite storage.
     57 #[cfg(any(feature = "native", feature = "full"))]
     58 #[cfg_attr(coverage_nightly, coverage(off))]
     59 pub async fn native(options: crate::storage::SqliteOptions) -> crate::Result<ClientBuilder> {
     60     ClientBuilder::sqlite(options).await
     61 }
     62 
     63 /// Reports whether the concrete GeoNames capability was selected at compile
     64 /// time. Asset inspection, acquisition, and database opening remain explicit.
     65 #[cfg(any(feature = "geonames", feature = "full"))]
     66 #[must_use]
     67 pub const fn geonames_enabled() -> bool {
     68     true
     69 }
     70 
     71 /// Reports whether canonical knowledge contracts were selected at compile
     72 /// time. Merely selecting the feature performs no event or storage operation.
     73 #[cfg(any(feature = "knowledge", feature = "full"))]
     74 #[must_use]
     75 pub const fn knowledge_enabled() -> bool {
     76     true
     77 }
     78 
     79 #[cfg(all(test, feature = "full"))]
     80 mod tests {
     81     use super::{
     82         Arc, EventSink, EventSource, Profile, geonames_enabled, knowledge_enabled, local_only,
     83         memory, with_transport,
     84     };
     85     use radroots_transport::{
     86         DeliveryReceipt, DeliveryRequest, Error as TransportError, FetchPage, FetchRequest,
     87         SinkFailure, SinkStatus, SourceStatus, outcome::Retryability,
     88         source::BoxFuture as TransportFuture,
     89     };
     90 
     91     struct TestSource;
     92     struct TestSink;
     93 
     94     impl EventSource for TestSource {
     95         fn status(&self) -> TransportFuture<'_, Result<SourceStatus, TransportError>> {
     96             Box::pin(async { Err(TransportError::UnsupportedOperation) })
     97         }
     98 
     99         fn fetch(
    100             &self,
    101             _request: FetchRequest,
    102         ) -> TransportFuture<'_, Result<FetchPage, TransportError>> {
    103             Box::pin(async { Err(TransportError::UnsupportedOperation) })
    104         }
    105     }
    106 
    107     impl EventSink for TestSink {
    108         fn status(&self) -> TransportFuture<'_, Result<SinkStatus, TransportError>> {
    109             Box::pin(async { Err(TransportError::UnsupportedOperation) })
    110         }
    111 
    112         fn deliver(
    113             &self,
    114             request: DeliveryRequest,
    115         ) -> TransportFuture<'_, Result<DeliveryReceipt, SinkFailure>> {
    116             Box::pin(async move {
    117                 Err(SinkFailure::for_request(
    118                     &request,
    119                     "test_sink_unavailable",
    120                     Retryability::Terminal,
    121                     None,
    122                     None,
    123                     Vec::new(),
    124                 )
    125                 .expect("test sink failure"))
    126             })
    127         }
    128     }
    129 
    130     #[test]
    131     fn curated_builders_cover_every_directly_testable_entry_point() {
    132         let local = memory().build().expect("memory client");
    133         assert_eq!(local_only(), Profile::local_only());
    134         assert!(local.source().expect("source").is_none());
    135 
    136         let composed = with_transport(memory(), Arc::new(TestSource), Arc::new(TestSink))
    137             .build()
    138             .expect("transport client");
    139         assert!(composed.source().expect("source").is_some());
    140         assert!(composed.sink().expect("sink").is_some());
    141 
    142         assert!(geonames_enabled());
    143         assert!(knowledge_enabled());
    144     }
    145 }