use std::fmt::Display;
use iroh::NodeAddr;
use iroh_blobs::{ticket::BlobTicket, BlobFormat, Hash, HashAndFormat};
use serde::{Deserialize, Serialize};
use crate::crypto::PublicKey;
use super::ipld::{Cid, LinkedData, Multihash, BLAKE3_HASH_CODE, LD_CBOR_CODEC, LD_RAW_CODEC};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Link(Cid);
impl Display for Link {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.hash())
}
}
#[allow(clippy::doc_overindented_list_items)]
#[allow(clippy::doc_lazy_continuation)]
impl Default for Link {
fn default() -> Self {
let hash = Hash::from_bytes([0; 32]);
let mh = Multihash::wrap(BLAKE3_HASH_CODE, hash.as_bytes()).expect("valid blake3 hash");
Link(Cid::new_v1(LD_RAW_CODEC, mh))
}
}
impl From<Link> for Cid {
fn from(val: Link) -> Self {
val.0
}
}
impl From<Cid> for Link {
fn from(val: Cid) -> Self {
let hash = val.hash();
let code = hash.code();
let codec = val.codec();
if code != BLAKE3_HASH_CODE {
panic!("invalid hash code");
}
if codec != LD_RAW_CODEC && codec != LD_CBOR_CODEC {
panic!("unsupported codec");
}
Link(val)
}
}
impl From<Link> for LinkedData {
fn from(val: Link) -> Self {
LinkedData::Link(val.0)
}
}
impl From<Link> for HashAndFormat {
fn from(val: Link) -> Self {
HashAndFormat {
hash: val.hash(),
format: BlobFormat::Raw,
}
}
}
impl From<Link> for Hash {
fn from(val: Link) -> Self {
val.hash()
}
}
impl Link {
pub fn new(codec: u64, hash: Hash) -> Self {
let mh = Multihash::wrap(BLAKE3_HASH_CODE, hash.as_bytes()).expect("valid blake3 hash");
Link(Cid::new_v1(codec, mh))
}
pub fn codec(&self) -> u64 {
self.0.codec()
}
pub fn hash(&self) -> Hash {
let hash_digest = self.0.hash().digest();
let mut hash_bytes: [u8; 32] = [0; 32];
hash_bytes.copy_from_slice(hash_digest);
Hash::from_bytes(hash_bytes)
}
pub fn cid(&self) -> &Cid {
&self.0
}
pub fn ticket(&self, source: PublicKey, format: Option<BlobFormat>) -> BlobTicket {
let node_addr = NodeAddr::new(*source);
BlobTicket::new(node_addr, self.hash(), format.unwrap_or(BlobFormat::Raw))
}
}