iroh_base/ticket.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
use crate::base32;
#[cfg(feature = "key")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
mod blob;
#[cfg(feature = "key")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
mod node;
#[cfg(feature = "key")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "key")))]
pub use self::{blob::BlobTicket, node::NodeTicket};
/// A ticket is a serializable object combining information required for an operation.
///
/// Typically tickets contain all information required for an operation, e.g. an iroh blob
/// ticket would contain the hash of the data as well as information about how to reach the
/// provider.
///
/// Tickets support serialization to a string using base32 encoding. The kind of
/// ticket will be prepended to the string to make it somewhat self describing.
///
/// Versioning is left to the implementer. Some kinds of tickets might need
/// versioning, others might not.
///
/// The serialization format for converting the ticket from and to bytes is left
/// to the implementer. We recommend using [postcard] for serialization.
///
/// [postcard]: https://docs.rs/postcard/latest/postcard/
pub trait Ticket: Sized {
/// String prefix describing the kind of iroh ticket.
///
/// This should be lower case ascii characters.
const KIND: &'static str;
/// Serialize to bytes used in the base32 string representation.
fn to_bytes(&self) -> Vec<u8>;
/// Deserialize from the base32 string representation bytes.
fn from_bytes(bytes: &[u8]) -> Result<Self, Error>;
/// Serialize to string.
fn serialize(&self) -> String {
let mut out = Self::KIND.to_string();
base32::fmt_append(self.to_bytes(), &mut out);
out
}
/// Deserialize from a string.
fn deserialize(str: &str) -> Result<Self, Error> {
let expected = Self::KIND;
let Some(rest) = str.strip_prefix(expected) else {
return Err(Error::Kind { expected });
};
let bytes = base32::parse_vec(rest)?;
let ticket = Self::from_bytes(&bytes)?;
Ok(ticket)
}
}
/// An error deserializing an iroh ticket.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Found a ticket of with the wrong prefix, indicating the wrong kind.
#[error("wrong prefix, expected {expected}")]
Kind { expected: &'static str },
/// This looks like a ticket, but postcard deserialization failed.
#[error("deserialization failed: {_0}")]
Postcard(#[from] postcard::Error),
/// This looks like a ticket, but base32 decoding failed.
#[error("decoding failed: {_0}")]
Encoding(#[from] base32::DecodeError),
/// Verification of the deserialized bytes failed.
#[error("verification failed: {_0}")]
Verify(&'static str),
}