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 }