use std::{str::FromStr, sync::Arc};
use futures::TryStreamExt;
use crate::{AuthorsClient, Iroh, IrohError};
#[derive(Debug, Clone, PartialEq, Eq, uniffi::Object)]
#[uniffi::export(Display)]
pub struct AuthorId(pub(crate) iroh_docs::AuthorId);
impl std::fmt::Display for AuthorId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[uniffi::export]
impl AuthorId {
#[uniffi::constructor]
pub fn from_string(str: String) -> Result<Self, IrohError> {
let author = iroh_docs::AuthorId::from_str(&str)?;
Ok(AuthorId(author))
}
#[uniffi::method]
pub fn equal(&self, other: &AuthorId) -> bool {
*self == *other
}
}
#[derive(Debug, Clone, uniffi::Object)]
#[uniffi::export(Display)]
pub struct Author(pub(crate) iroh_docs::Author);
#[uniffi::export]
impl Author {
#[uniffi::constructor]
pub fn from_string(str: String) -> Result<Self, IrohError> {
let author = iroh_docs::Author::from_str(&str)?;
Ok(Author(author))
}
#[uniffi::method]
pub fn id(&self) -> Arc<AuthorId> {
Arc::new(AuthorId(self.0.id()))
}
}
impl std::fmt::Display for Author {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(uniffi::Object)]
pub struct Authors {
client: AuthorsClient,
}
#[uniffi::export]
impl Iroh {
pub fn authors(&self) -> Authors {
Authors {
client: self.authors_client.clone().expect("missing docs"),
}
}
}
#[uniffi::export]
impl Authors {
#[uniffi::method(async_runtime = "tokio")]
pub async fn default(&self) -> Result<Arc<AuthorId>, IrohError> {
let author = self.client.default().await?;
Ok(Arc::new(AuthorId(author)))
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn list(&self) -> Result<Vec<Arc<AuthorId>>, IrohError> {
let authors = self
.client
.list()
.await?
.map_ok(|id| Arc::new(AuthorId(id)))
.try_collect::<Vec<_>>()
.await?;
Ok(authors)
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn create(&self) -> Result<Arc<AuthorId>, IrohError> {
let author = self.client.create().await?;
Ok(Arc::new(AuthorId(author)))
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn export(&self, author: Arc<AuthorId>) -> Result<Arc<Author>, IrohError> {
let author = self.client.export(author.0).await?;
match author {
Some(author) => Ok(Arc::new(Author(author))),
None => Err(anyhow::anyhow!("Author Not Found").into()),
}
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn import(&self, author: Arc<Author>) -> Result<Arc<AuthorId>, IrohError> {
self.client.import(author.0.clone()).await?;
Ok(Arc::new(AuthorId(author.0.id())))
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn import_author(&self, author: Arc<Author>) -> Result<Arc<AuthorId>, IrohError> {
self.import(author).await
}
#[uniffi::method(async_runtime = "tokio")]
pub async fn delete(&self, author: Arc<AuthorId>) -> Result<(), IrohError> {
self.client.delete(author.0).await?;
Ok(())
}
}
mod tests {
#[tokio::test]
async fn test_author_api() {
let dir = tempfile::tempdir().unwrap();
let options = crate::NodeOptions {
enable_docs: true,
..Default::default()
};
let node = crate::Iroh::persistent_with_options(dir.keep().display().to_string(), options)
.await
.unwrap();
assert_eq!(node.authors().list().await.unwrap().len(), 1);
let author_id = node.authors().create().await.unwrap();
let authors = node.authors().list().await.unwrap();
assert_eq!(authors.len(), 2);
let author = node.authors().export(author_id.clone()).await.unwrap();
assert!(author_id.equal(&author.id()));
node.authors().delete(author_id).await.unwrap();
let authors = node.authors().list().await.unwrap();
assert_eq!(authors.len(), 1);
node.authors().import(author).await.unwrap();
let authors = node.authors().list().await.unwrap();
assert_eq!(authors.len(), 2);
}
}