use crate::addressing::Address; use actix::prelude::*; use anyhow::Result; use diesel::backend::Backend; use diesel::deserialize::FromSql; use diesel::sqlite::Sqlite; use diesel::{deserialize, sql_types}; use filebuffer::FileBuffer; use multihash::Hasher; use serde::{ser, Serialize, Serializer}; use std::path::{Path, PathBuf}; use tracing::trace; #[derive(Debug, Clone, Eq, PartialEq, FromSqlRow, Hash)] pub struct Hash(pub Vec); impl AsRef<[u8]> for Hash { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl FromSql for Hash { fn from_sql(bytes: Option<&::RawValue>) -> deserialize::Result { Ok(Hash(Vec::from(not_none!(bytes).read_blob()))) } } impl Serialize for Hash { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where S: Serializer, { serializer.serialize_str( b58_encode( Address::Hash(self.clone()) .encode() .map_err(ser::Error::custom)?, ) .as_str(), ) } } pub trait Hashable { fn hash(&self) -> Result; } pub struct HasherWorker; impl Actor for HasherWorker { type Context = SyncContext; } #[derive(Message)] #[rtype(result = "Result")] pub struct ComputeHash { pub path: PathBuf, } impl Handler for HasherWorker { type Result = Result; fn handle(&mut self, msg: ComputeHash, _: &mut Self::Context) -> Self::Result { msg.path.as_path().hash() } } impl Hashable for Path { fn hash(self: &Path) -> Result { trace!("Hashing {:?}...", self); let fbuffer = FileBuffer::open(self)?; trace!("Finished hashing {:?}...", self); Ok(hash(&fbuffer)) } } pub fn hash>(input: T) -> Hash { let mut hasher = multihash::Sha2_256::default(); hasher.update(input.as_ref()); Hash(Vec::from(hasher.finalize())) } pub fn b58_encode>(vec: T) -> String { multibase::encode(multibase::Base::Base58Btc, vec.as_ref()) } pub fn b58_decode>(input: T) -> Result> { let input = input.as_ref(); let (_base, data) = multibase::decode(input)?; Ok(data) } #[cfg(test)] mod tests { use crate::util::hash::{b58_decode, b58_encode}; #[test] fn test_encode_decode() { let content = "Hello, World!".as_bytes(); let encoded = b58_encode(content); let decoded = b58_decode(encoded); assert!(decoded.is_ok()); assert_eq!(content, decoded.unwrap()); } }