wip: remove unnecessary addressing from cli
parent
9a2af86238
commit
a591db0cd4
|
@ -1,190 +0,0 @@
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use multihash::{Code, Multihash, MultihashDigest};
|
|
||||||
use serde::de::Visitor;
|
|
||||||
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
use std::fmt;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use thiserror::private::DisplayAsDisplay;
|
|
||||||
use upend_base::hash::{b58_decode, b58_encode, Hash, Hashable};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub enum Address {
|
|
||||||
Hash(Hash),
|
|
||||||
Uuid(Uuid),
|
|
||||||
Attribute(String),
|
|
||||||
Url(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
// multihash SHA2-256
|
|
||||||
const SHA2_256: u64 = 0x12;
|
|
||||||
// multihash identity
|
|
||||||
const IDENTITY: u64 = 0x00;
|
|
||||||
|
|
||||||
impl Address {
|
|
||||||
pub fn encode(&self) -> Result<Vec<u8>> {
|
|
||||||
let hash = match self {
|
|
||||||
Self::Hash(hash) => Multihash::wrap(SHA2_256, &hash.0).map_err(|err| anyhow!(err))?,
|
|
||||||
Self::Uuid(uuid) => {
|
|
||||||
Code::Identity.digest(&[vec![b'U'], uuid.as_bytes().to_vec()].concat())
|
|
||||||
}
|
|
||||||
Self::Attribute(attribute) => {
|
|
||||||
Code::Identity.digest(&[&[b'A'], attribute.as_bytes()].concat())
|
|
||||||
}
|
|
||||||
Self::Url(url) => Code::Identity.digest(&[&[b'X'], url.as_bytes()].concat()),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(hash.to_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode(buffer: &[u8]) -> Result<Self> {
|
|
||||||
let multihash = Multihash::from_bytes(buffer)
|
|
||||||
.map_err(|err| anyhow!("Error decoding address: {}", err))?;
|
|
||||||
|
|
||||||
match multihash.code() {
|
|
||||||
SHA2_256 => Ok(Self::Hash(Hash(multihash.digest().to_vec()))),
|
|
||||||
IDENTITY => {
|
|
||||||
let digest = multihash.digest().to_owned();
|
|
||||||
let digest_content: Vec<u8> = digest.clone().into_iter().skip(1).collect();
|
|
||||||
match digest[0] {
|
|
||||||
b'U' => Ok(Self::Uuid(uuid::Uuid::from_slice(
|
|
||||||
digest_content.as_slice(),
|
|
||||||
)?)),
|
|
||||||
b'A' => Ok(Self::Attribute(String::from_utf8(digest_content)?)),
|
|
||||||
b'X' => Ok(Self::Url(String::from_utf8(digest_content)?)),
|
|
||||||
_ => Err(anyhow!("Error decoding address: Unknown identity marker.")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(anyhow!(
|
|
||||||
"Error decoding address: Unknown hash function type."
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for Address {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(b58_encode(self.encode().map_err(ser::Error::custom)?).as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AddressVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for AddressVisitor {
|
|
||||||
type Value = Address;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("a valid UpEnd address (hash/UUID) as a multi-hashed string")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, str: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
let bytes = b58_decode(str)
|
|
||||||
.map_err(|e| de::Error::custom(format!("Error deserializing address: {}", e)))?;
|
|
||||||
Address::decode(bytes.as_ref())
|
|
||||||
.map_err(|e| de::Error::custom(format!("Error deserializing address: {}", e)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Address {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Address, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
deserializer.deserialize_str(AddressVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Address {
|
|
||||||
type Err = anyhow::Error;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Address::decode(
|
|
||||||
b58_decode(s)
|
|
||||||
.map_err(|e| anyhow!("Error deserializing address: {}", e))?
|
|
||||||
.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Address {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
b58_encode(self.encode().map_err(|_| std::fmt::Error)?)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Address {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Address<{}>: {}",
|
|
||||||
match self {
|
|
||||||
Address::Hash(_) => "Hash",
|
|
||||||
Address::Uuid(_) => "UUID",
|
|
||||||
Address::Attribute(_) => "Attribute",
|
|
||||||
Address::Url(_) => "URL",
|
|
||||||
},
|
|
||||||
self.as_display()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Addressable: Hashable {
|
|
||||||
fn address(&self) -> Result<Address> {
|
|
||||||
Ok(Address::Hash(self.hash()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use anyhow::Result;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::addressing::Address;
|
|
||||||
use upend_base::hash::Hash;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_hash_codec() -> Result<()> {
|
|
||||||
let addr = Address::Hash(Hash(vec![1, 2, 3, 4, 5]));
|
|
||||||
let encoded = addr.encode()?;
|
|
||||||
let decoded = Address::decode(&encoded)?;
|
|
||||||
assert_eq!(addr, decoded);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_uuid_codec() -> Result<()> {
|
|
||||||
let addr = Address::Uuid(Uuid::new_v4());
|
|
||||||
let encoded = addr.encode()?;
|
|
||||||
let decoded = Address::decode(&encoded)?;
|
|
||||||
assert_eq!(addr, decoded);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_attribute_codec() -> Result<()> {
|
|
||||||
let addr = Address::Attribute(String::from("ATTRIBUTE"));
|
|
||||||
let encoded = addr.encode()?;
|
|
||||||
let decoded = Address::decode(&encoded)?;
|
|
||||||
assert_eq!(addr, decoded);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_url_codec() -> Result<()> {
|
|
||||||
let addr = Address::Url(String::from("https://upend.dev"));
|
|
||||||
let encoded = addr.encode()?;
|
|
||||||
let decoded = Address::decode(&encoded)?;
|
|
||||||
assert_eq!(addr, decoded);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue