#![allow(unused_variables)]
#![allow(clippy::type_complexity)]
use std::{ffi::c_void, str::FromStr};
use anyhow::anyhow;
use cid::Cid;
use noosphere_core::context::{SpherePetnameRead, SpherePetnameWrite, SphereWalker};
use noosphere_core::data::Did;
use safer_ffi::{char_p::InvalidNulTerminator, prelude::*};
use crate::ffi::{NsError, TryOrInitialize};
use super::{NsNoosphere, NsSphere};
#[ffi_export]
pub fn ns_sphere_petname_is_set(
noosphere: &NsNoosphere,
sphere: &NsSphere,
petname: char_p::Ref<'_>,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) -> u8 {
if let Some(result) = error_out.try_or_initialize(|| {
noosphere.async_runtime().block_on(async {
Ok(sphere
.inner()
.get_petname(petname.to_str())
.await?
.is_some())
})
}) {
u8::from(result)
} else {
0
}
}
#[ffi_export]
pub fn ns_sphere_petname_get(
noosphere: &NsNoosphere,
sphere: &NsSphere,
petname: char_p::Ref<'_>,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) -> Option<char_p::Box> {
error_out.try_or_initialize(|| {
noosphere.async_runtime().block_on(async {
sphere
.inner()
.get_petname(petname.to_str())
.await?
.ok_or_else(|| anyhow!("No petname '{}' has been set", petname.to_str()))?
.to_string()
.try_into()
.map_err(|error: InvalidNulTerminator<String>| anyhow!(error).into())
})
})
}
#[ffi_export]
pub fn ns_sphere_petnames_assigned_get(
noosphere: &NsNoosphere,
sphere: &NsSphere,
peer_identity: char_p::Ref<'_>,
context: Option<repr_c::Box<c_void>>,
callback: extern "C" fn(
Option<repr_c::Box<c_void>>,
Option<repr_c::Box<NsError>>,
Option<c_slice::Box<char_p::Box>>,
),
) {
let sphere = sphere.inner().clone();
let did = Did(peer_identity.to_string());
noosphere.async_runtime().spawn(async move {
let result = async {
let assigned_petnames = sphere
.get_assigned_petnames(&did)
.await?
.iter()
.filter_map(|name| name.to_owned().try_into().ok())
.collect::<Vec<char_p::Box>>();
Ok(assigned_petnames.into_boxed_slice().into()) as Result<_, anyhow::Error>
}
.await;
match result {
Ok(petnames) => {
tokio::task::spawn_blocking(move || callback(context, None, Some(petnames)))
}
Err(error) => tokio::task::spawn_blocking(move || {
callback(context, Some(NsError::from(error).into()), None)
}),
};
});
}
#[ffi_export]
pub fn ns_sphere_petname_set(
noosphere: &NsNoosphere,
sphere: &mut NsSphere,
petname: char_p::Ref<'_>,
did: Option<char_p::Ref<'_>>,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) {
error_out.try_or_initialize(|| {
noosphere.async_runtime().block_on(async {
sphere
.inner_mut()
.set_petname(petname.to_str(), did.map(|did| did.to_str().into()))
.await?;
Ok(())
})
});
}
#[ffi_export]
pub fn ns_sphere_petname_resolve(
noosphere: &NsNoosphere,
sphere: &NsSphere,
petname: char_p::Ref<'_>,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) -> Option<char_p::Box> {
let closure = || {
let version = noosphere
.async_runtime()
.block_on(async { sphere.inner().resolve_petname(petname.to_str()).await })?;
if let Some(version) = version {
let version_str = version.to_string().try_into().map_err(
|error: InvalidNulTerminator<String>| -> NsError { anyhow!(error).into() },
)?;
Ok(Some(version_str))
} else {
Ok(None)
}
};
match error_out.try_or_initialize(closure) {
Some(maybe_version) => maybe_version,
None => None,
}
}
#[ffi_export]
pub fn ns_sphere_petname_list(
noosphere: &NsNoosphere,
sphere: &NsSphere,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) -> c_slice::Box<char_p::Box> {
let possible_output = error_out.try_or_initialize(|| {
noosphere.async_runtime().block_on(async {
let petname_set = SphereWalker::from(sphere.inner()).list_petnames().await?;
let mut all_petnames: Vec<char_p::Box> = Vec::new();
for petname in petname_set.into_iter() {
all_petnames.push(
petname
.try_into()
.map_err(|error: InvalidNulTerminator<String>| anyhow!(error))?,
);
}
Ok(all_petnames)
})
});
match possible_output {
Some(slugs) => slugs,
None => Vec::new(),
}
.into_boxed_slice()
.into()
}
#[ffi_export]
pub fn ns_sphere_petname_changes(
noosphere: &NsNoosphere,
sphere: &NsSphere,
since_cid: Option<char_p::Ref<'_>>,
error_out: Option<Out<'_, repr_c::Box<NsError>>>,
) -> c_slice::Box<char_p::Box> {
let possible_output = error_out.try_or_initialize(|| {
noosphere.async_runtime().block_on(async {
let since = match since_cid {
Some(cid_string) => Some(
Cid::from_str(cid_string.to_str())
.map_err(|error| anyhow!(error))?
.into(),
),
None => None,
};
let changed_petname_set = SphereWalker::from(sphere.inner())
.petname_changes(since.as_ref())
.await?;
let mut changed_petnames: Vec<char_p::Box> = Vec::new();
for petname in changed_petname_set.into_iter() {
changed_petnames.push(
petname
.try_into()
.map_err(|error: InvalidNulTerminator<String>| anyhow!(error))?,
);
}
Ok(changed_petnames)
})
});
match possible_output {
Some(petnames) => petnames,
None => Vec::new(),
}
.into_boxed_slice()
.into()
}