diff --git a/base/src/addressing.rs b/base/src/addressing.rs index 0f49a91..611749e 100644 --- a/base/src/addressing.rs +++ b/base/src/addressing.rs @@ -46,7 +46,7 @@ pub type UpCid = cid::CidGeneric<256>; impl Address { pub fn encode(&self) -> Result, UpEndError> { let (codec, hash) = match self { - Self::Hash(hash) => (RAW, hash.0), + Self::Hash(hash) => (RAW, LargeMultihash::from(hash)), Self::Uuid(uuid) => ( UP_UUID, LargeMultihash::wrap(IDENTITY, uuid.as_bytes()).map_err(UpEndError::from_any)?, @@ -74,7 +74,7 @@ impl Address { })?; if cid.codec() == RAW { - return Ok(Address::Hash(UpMultihash(*cid.hash()))); + return Ok(Address::Hash(UpMultihash::from(*cid.hash()))); } let hash = cid.hash(); @@ -109,7 +109,7 @@ impl Address { pub fn as_components<'a>(&'a self) -> AddressComponents { // TODO: make this automatically derive from `Address` definition let (entity_type, entity_content) = match self { - Address::Hash(uphash) => ("Hash", Some(b58_encode(uphash.0.to_bytes()))), + Address::Hash(uphash) => ("Hash", Some(b58_encode(uphash.to_bytes()))), Address::Uuid(uuid) => ("Uuid", Some(uuid.to_string())), Address::Attribute(attribute) => ("Attribute", Some(attribute.clone())), Address::Url(url) => ("Url", Some(url.to_string())), @@ -250,7 +250,7 @@ mod tests { #[test] fn test_hash_codec() -> Result<(), UpEndError> { - let addr = Address::Hash(UpMultihash( + let addr = Address::Hash(UpMultihash::from( LargeMultihash::wrap(IDENTITY, &vec![1, 2, 3, 4, 5]).unwrap(), )); let encoded = addr.encode()?; diff --git a/base/src/constants.rs b/base/src/constants.rs index 5e5e08f..96ae18d 100644 --- a/base/src/constants.rs +++ b/base/src/constants.rs @@ -1,6 +1,6 @@ use crate::addressing::Address; use crate::entry::InvariantEntry; -use crate::hash::LargeMultihash; +use crate::hash::{LargeMultihash, UpMultihash}; /// Attribute denoting (hierarchical) relation, in the "upwards" direction. For example, a file `IN` a group, an image `IN` photos, etc. pub const ATTR_IN: &str = "IN"; @@ -24,7 +24,7 @@ lazy_static! { }; pub static ref HIER_ROOT_ADDR: Address = HIER_ROOT_INVARIANT.entity().unwrap(); pub static ref TYPE_HASH_ADDRESS: Address = - Address::Hash(crate::hash::UpMultihash(LargeMultihash::default())); + Address::Hash(UpMultihash::from(LargeMultihash::default())); pub static ref TYPE_UUID_ADDRESS: Address = Address::Uuid(uuid::Uuid::nil()); pub static ref TYPE_ATTRIBUTE_ADDRESS: Address = Address::Attribute("".to_string()); pub static ref TYPE_URL_ADDRESS: Address = Address::Url(url::Url::parse("up:").unwrap()); diff --git a/base/src/hash.rs b/base/src/hash.rs index f218bf8..e90d15c 100644 --- a/base/src/hash.rs +++ b/base/src/hash.rs @@ -7,17 +7,48 @@ use serde::{ ser, Deserialize, Deserializer, Serialize, Serializer, }; -pub type LargeMultihash = multihash::MultihashGeneric<256>; - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "diesel", derive(diesel::FromSqlRow))] -pub struct UpMultihash(pub LargeMultihash); - /// multihash SHA2-256 code pub const SHA2_256: u64 = 0x12; /// multihash identity code pub const IDENTITY: u64 = 0x00; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "diesel", derive(diesel::FromSqlRow))] +pub struct UpMultihash(LargeMultihash); + +impl UpMultihash { + pub fn to_bytes(&self) -> Vec { + self.0.to_bytes() + } + + pub fn from_bytes>(input: T) -> Result { + Ok(UpMultihash( + LargeMultihash::from_bytes(input.as_ref()) + .map_err(|e| UpEndError::HashDecodeError(e.to_string()))?, + )) + } + + pub fn from_sha256>(input: T) -> Result { + Ok(UpMultihash( + LargeMultihash::wrap(SHA2_256, input.as_ref()).map_err(UpEndError::from_any)?, + )) + } +} + +pub(crate) type LargeMultihash = multihash::MultihashGeneric<256>; + +impl From for UpMultihash { + fn from(value: LargeMultihash) -> Self { + UpMultihash(value) + } +} + +impl From<&UpMultihash> for LargeMultihash { + fn from(value: &UpMultihash) -> Self { + value.0 + } +} + impl Serialize for UpMultihash { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where diff --git a/cli/src/main.rs b/cli/src/main.rs index 1b02884..cd744c7 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -307,10 +307,7 @@ async fn main() -> Result<()> { AddressType::File => hash_path(&input)?, AddressType::Sha256sum => { let digest = multibase::Base::Base16Lower.decode(input)?; - Address::Hash(UpMultihash( - upend_base::hash::LargeMultihash::wrap(upend_base::hash::SHA2_256, &digest) - .unwrap(), - )) + Address::Hash(UpMultihash::from_sha256(&digest).unwrap()) } }; diff --git a/cli/src/previews/mod.rs b/cli/src/previews/mod.rs index a56710e..6663b6f 100644 --- a/cli/src/previews/mod.rs +++ b/cli/src/previews/mod.rs @@ -61,7 +61,7 @@ impl PreviewStore { } else { let thumbpath = self.path.join(format!( "{}{}", - b58_encode(hash.0.to_bytes()), + b58_encode(hash.to_bytes()), if options_concat.is_empty() { String::from("") } else { diff --git a/cli/src/routes.rs b/cli/src/routes.rs index bc5b6d3..473bc36 100644 --- a/cli/src/routes.rs +++ b/cli/src/routes.rs @@ -1010,14 +1010,8 @@ mod tests { >(None, vec![], get_state())) .await; - let digest = UpMultihash( - upend_base::hash::LargeMultihash::wrap( - upend_base::hash::IDENTITY, - &vec![1, 2, 3, 4, 5], - ) - .unwrap(), - ); - let digest_str = b58_encode(&digest.0.to_bytes()); + let digest = UpMultihash::from_sha256(&vec![1, 2, 3, 4, 5]).unwrap(); + let digest_str = b58_encode(&digest.to_bytes()); let address = Address::Hash(digest); let req = actix_web::test::TestRequest::get() .uri(&format!("/api/obj/{}", address.to_string())) diff --git a/db/src/stores/fs/mod.rs b/db/src/stores/fs/mod.rs index ad9239f..b081f0d 100644 --- a/db/src/stores/fs/mod.rs +++ b/db/src/stores/fs/mod.rs @@ -24,7 +24,7 @@ use tracing::{debug, error, info, trace, warn}; use upend_base::addressing::Address; use upend_base::constants::{ATTR_ADDED, ATTR_BY, ATTR_IN, ATTR_LABEL, ATTR_OF, TYPE_HASH_ADDRESS}; use upend_base::entry::Entry; -use upend_base::hash::{b58_encode, LargeMultihash, UpMultihash}; +use upend_base::hash::{b58_encode, UpMultihash}; use walkdir::WalkDir; mod db; @@ -393,7 +393,7 @@ impl FsStore { .to_str() .ok_or(anyhow!("Path not UTF-8?!"))? .to_string(), - hash: hash.0.to_bytes(), + hash: hash.to_bytes(), added: NaiveDateTime::from_timestamp_opt(Utc::now().timestamp(), 0).unwrap(), size, mtime, @@ -494,7 +494,7 @@ impl FsStore { debug!( "Inserting {} ({})...", &file.path, - Address::Hash(UpMultihash(LargeMultihash::from_bytes(&file.hash)?)) + Address::Hash(UpMultihash::from_bytes(&file.hash)?) ); let _lock = self.lock.write().unwrap(); @@ -521,7 +521,7 @@ impl FsStore { let matches = files .filter(valid.eq(true)) - .filter(hash.eq(&obj_hash.0.to_bytes())) + .filter(hash.eq(&obj_hash.to_bytes())) .load::(&conn)?; let matches = matches