syncweb_core/node/
docs_engine.rs1use bytes::Bytes;
2use iroh_blobs::Hash;
3use iroh_docs::{
4 AuthorId, DocTicket, Entry, NamespaceId,
5 api::{
6 Doc,
7 protocol::{AddrInfoOptions, ShareMode},
8 },
9 engine::LiveEvent,
10 protocol::Docs,
11 store::Query,
12};
13use n0_future::StreamExt;
14
15use crate::error::{Result, SyncwebError};
16
17#[derive(Clone)]
18pub struct DocsEngine {
19 docs: Docs,
20}
21
22impl DocsEngine {
23 #[must_use]
24 pub fn new(docs: &Docs) -> Self {
25 Self { docs: docs.clone() }
26 }
27
28 #[must_use]
29 pub const fn inner(&self) -> &Docs {
30 &self.docs
31 }
32
33 pub async fn create_namespace(&self) -> Result<Doc> {
37 self.docs
38 .create()
39 .await
40 .map_err(|error| SyncwebError::operation("failed to create namespace", error))
41 }
42
43 pub async fn import_ticket(&self, ticket: DocTicket) -> Result<Doc> {
47 self.docs
48 .import(ticket)
49 .await
50 .map_err(|error| SyncwebError::operation("failed to import document ticket", error))
51 }
52
53 pub async fn open(&self, namespace_id: NamespaceId) -> Result<Option<Doc>> {
57 self.docs
58 .open(namespace_id)
59 .await
60 .map_err(|error| SyncwebError::operation("failed to open namespace", error))
61 }
62
63 pub async fn drop_namespace(&self, namespace_id: NamespaceId) -> Result<()> {
67 self.docs
68 .drop_doc(namespace_id)
69 .await
70 .map_err(|error| SyncwebError::operation("failed to drop namespace", error))?;
71 Ok(())
72 }
73
74 pub async fn start_sync(&self, doc: &Doc, peers: Vec<iroh::EndpointAddr>) -> Result<()> {
83 doc.start_sync(peers)
84 .await
85 .map_err(|error| SyncwebError::operation("failed to start document synchronization", error))
86 }
87
88 pub async fn share(&self, doc: &Doc, mode: ShareMode, _endpoint: iroh::EndpointAddr) -> Result<DocTicket> {
92 doc.share(mode, AddrInfoOptions::RelayAndAddresses)
93 .await
94 .map_err(|error| SyncwebError::operation("failed to share document", error))
95 }
96
97 pub async fn author(&self) -> Result<AuthorId> {
101 self.docs
102 .author_default()
103 .await
104 .map_err(|error| SyncwebError::operation("failed to retrieve document author", error))
105 }
106
107 pub async fn export_author(&self, author_id: AuthorId) -> Result<Option<iroh_docs::Author>> {
111 self.docs
112 .author_export(author_id)
113 .await
114 .map_err(|error| SyncwebError::operation("failed to export document author", error))
115 }
116
117 pub async fn import_author(&self, author: iroh_docs::Author) -> Result<AuthorId> {
121 self.docs
122 .author_import(author.clone())
123 .await
124 .map_err(|error| SyncwebError::operation("failed to import document author", error))?;
125 Ok(author.id())
126 }
127
128 pub async fn set(
132 &self,
133 doc: &Doc,
134 author: AuthorId,
135 key: impl AsRef<[u8]>,
136 value: impl AsRef<[u8]>,
137 ) -> Result<Hash> {
138 doc.set_bytes(
139 author,
140 Bytes::copy_from_slice(key.as_ref()),
141 Bytes::copy_from_slice(value.as_ref()),
142 )
143 .await
144 .map_err(|error| SyncwebError::operation("failed to set document entry", error))
145 }
146
147 pub async fn set_blob(
151 &self,
152 doc: &Doc,
153 author: AuthorId,
154 key: impl AsRef<[u8]>,
155 hash: Hash,
156 size: u64,
157 ) -> Result<()> {
158 doc.set_hash(author, Bytes::copy_from_slice(key.as_ref()), hash, size)
159 .await
160 .map_err(|error| SyncwebError::operation("failed to set document blob", error))?;
161 Ok(())
162 }
163
164 pub async fn get(&self, doc: &Doc, author: AuthorId, key: impl AsRef<[u8]>) -> Result<Option<Entry>> {
168 doc.get_exact(author, key, false)
169 .await
170 .map_err(|error| SyncwebError::operation("failed to get document entry", error))
171 }
172
173 pub async fn get_any(&self, doc: &Doc, key: impl AsRef<[u8]>) -> Result<Option<Entry>> {
179 let entries = doc
180 .get_many(Query::single_latest_per_key().key_exact(key))
181 .await
182 .map_err(|error| SyncwebError::operation("failed to query document entries", error))?;
183 tokio::pin!(entries);
184 n0_future::StreamExt::next(&mut entries)
185 .await
186 .transpose()
187 .map_err(|error| SyncwebError::operation("failed to read document query result", error))
188 }
189
190 pub async fn list_latest(&self, doc: &Doc) -> Result<Vec<Entry>> {
196 let entries = doc
197 .get_many(Query::single_latest_per_key().build())
198 .await
199 .map_err(|error| SyncwebError::operation("failed to query document entries", error))?;
200 tokio::pin!(entries);
201 let mut output = Vec::new();
202 while let Some(entry_result) = n0_future::StreamExt::next(&mut entries).await {
203 let entry =
204 entry_result.map_err(|error| SyncwebError::operation("failed to read document entry", error))?;
205 output.push(entry);
206 }
207 Ok(output)
208 }
209
210 pub async fn delete(&self, doc: &Doc, author: AuthorId, key: impl AsRef<[u8]>) -> Result<()> {
216 doc.del(author, key.as_ref().to_vec())
217 .await
218 .map_err(|error| SyncwebError::operation("failed to delete document entry", error))?;
219 Ok(())
220 }
221
222 pub async fn watch(
226 &self,
227 doc: &Doc,
228 ) -> Result<impl n0_future::Stream<Item = Result<LiveEvent>> + Send + Unpin + 'static> {
229 let stream = doc
230 .subscribe()
231 .await
232 .map_err(|error| SyncwebError::operation("failed to subscribe to document", error))?;
233 Ok(stream.map(|event| event.map_err(|error| SyncwebError::operation("document event failed", error))))
234 }
235
236 #[must_use]
237 pub fn namespace_id(&self, doc: &Doc) -> NamespaceId {
238 doc.id()
239 }
240}