use std::str::FromStr;
use napi::bindgen_prelude::*;
use napi_derive::napi;
use crate::{
blob::{BlobDownloadOptions, BlobFormat},
doc::CapabilityKind,
NodeAddr,
};
#[derive(Debug, PartialEq)]
#[napi]
pub struct BlobTicket {
node_addr: NodeAddr,
#[napi(readonly)]
pub format: BlobFormat,
#[napi(readonly)]
pub hash: String,
}
impl From<iroh_blobs::ticket::BlobTicket> for BlobTicket {
fn from(value: iroh_blobs::ticket::BlobTicket) -> Self {
Self {
node_addr: value.node_addr().clone().into(),
format: value.format().into(),
hash: value.hash().to_string(),
}
}
}
impl TryFrom<&BlobTicket> for iroh_blobs::ticket::BlobTicket {
type Error = anyhow::Error;
fn try_from(value: &BlobTicket) -> anyhow::Result<Self> {
let ticket = iroh_blobs::ticket::BlobTicket::new(
value.node_addr.clone().try_into()?,
value.hash.parse()?,
value.format.clone().into(),
)?;
Ok(ticket)
}
}
#[napi]
impl BlobTicket {
#[napi(constructor)]
pub fn new(node_addr: NodeAddr, hash: String, format: BlobFormat) -> Self {
Self {
node_addr,
hash,
format,
}
}
#[napi(factory)]
pub fn from_string(str: String) -> Result<Self> {
let ticket = iroh_blobs::ticket::BlobTicket::from_str(&str).map_err(anyhow::Error::from)?;
Ok(ticket.into())
}
#[napi(getter)]
pub fn node_addr(&self) -> NodeAddr {
self.node_addr.clone()
}
#[napi]
pub fn is_equal(&self, other: &BlobTicket) -> bool {
self == other
}
#[napi]
pub fn to_string(&self) -> Result<String> {
let ticket: iroh_blobs::ticket::BlobTicket = self.try_into()?;
Ok(ticket.to_string())
}
#[napi]
pub fn recursive(&self) -> bool {
matches!(self.format, BlobFormat::HashSeq)
}
#[napi]
pub fn as_download_options(&self) -> Result<BlobDownloadOptions> {
let res = iroh_blobs::rpc::client::blobs::DownloadOptions {
format: self.format.clone().into(),
nodes: vec![self.node_addr.clone().try_into()?],
tag: iroh_blobs::util::SetTagOption::Auto,
mode: iroh_blobs::rpc::client::blobs::DownloadMode::Direct,
}
.into();
Ok(res)
}
}
#[derive(Debug)]
#[napi(string_enum)]
pub enum AddrInfoOptions {
Id,
RelayAndAddresses,
Relay,
Addresses,
}
impl From<AddrInfoOptions> for iroh_docs::rpc::AddrInfoOptions {
fn from(options: AddrInfoOptions) -> iroh_docs::rpc::AddrInfoOptions {
match options {
AddrInfoOptions::Id => iroh_docs::rpc::AddrInfoOptions::Id,
AddrInfoOptions::RelayAndAddresses => {
iroh_docs::rpc::AddrInfoOptions::RelayAndAddresses
}
AddrInfoOptions::Relay => iroh_docs::rpc::AddrInfoOptions::Relay,
AddrInfoOptions::Addresses => iroh_docs::rpc::AddrInfoOptions::Addresses,
}
}
}
#[derive(Clone, Debug)]
#[napi]
pub struct DocTicket {
#[napi(readonly)]
pub capability: String,
#[napi(readonly)]
pub capability_kind: CapabilityKind,
nodes: Vec<NodeAddr>,
}
impl From<iroh_docs::DocTicket> for DocTicket {
fn from(value: iroh_docs::DocTicket) -> Self {
let (capability, kind) = match value.capability {
iroh_docs::Capability::Read(v) => (v.to_string(), CapabilityKind::Read),
iroh_docs::Capability::Write(v) => (v.to_string(), CapabilityKind::Write),
};
Self {
capability,
capability_kind: kind,
nodes: value.nodes.into_iter().map(Into::into).collect(),
}
}
}
impl TryFrom<&DocTicket> for iroh_docs::DocTicket {
type Error = anyhow::Error;
fn try_from(value: &DocTicket) -> anyhow::Result<Self> {
let peers = value
.nodes
.iter()
.map(|v| v.clone().try_into())
.collect::<anyhow::Result<_>>()?;
let capability = match value.capability_kind {
CapabilityKind::Read => iroh_docs::Capability::Read(value.capability.parse()?),
CapabilityKind::Write => iroh_docs::Capability::Write(value.capability.parse()?),
};
let ticket = iroh_docs::DocTicket::new(capability, peers);
Ok(ticket)
}
}
#[napi]
impl DocTicket {
#[napi(factory)]
pub fn from_string(str: String) -> Result<Self> {
let ticket = iroh_docs::DocTicket::from_str(&str).map_err(anyhow::Error::from)?;
Ok(ticket.into())
}
#[napi]
pub fn to_string(&self) -> Result<String> {
let ticket: iroh_docs::DocTicket = self.try_into()?;
Ok(ticket.to_string())
}
#[napi(getter)]
pub fn nodes(&self) -> Vec<NodeAddr> {
self.nodes.clone()
}
}