2020-09-07 21:21:54 +02:00
|
|
|
use actix::prelude::*;
|
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
use filebuffer::FileBuffer;
|
2021-02-19 21:45:33 +01:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-09-20 19:32:28 +02:00
|
|
|
use std::path::PathBuf;
|
2020-09-07 21:21:54 +02:00
|
|
|
use tiny_keccak::{Hasher, KangarooTwelve};
|
|
|
|
|
2021-02-19 21:45:33 +01:00
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
2020-09-07 21:21:54 +02:00
|
|
|
pub struct Hash(pub Vec<u8>);
|
|
|
|
|
2021-02-19 20:27:30 +01:00
|
|
|
impl AsRef<[u8]> for Hash {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
self.0.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-07 21:21:54 +02:00
|
|
|
// impl Hash {
|
|
|
|
// pub fn encode(&self) -> String {
|
|
|
|
// encode(self.0.clone()).into_string()
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// pub fn decode<T: AsRef<str>>(string: T) -> Result<Hash> {
|
|
|
|
// Ok(Hash(decode(string.as_ref())?))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl std::fmt::Display for Hash {
|
|
|
|
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
// write!(f, "{}", self.encode())
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
pub trait Hashable {
|
|
|
|
fn hash(&self) -> Result<Hash>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct HasherWorker;
|
|
|
|
|
|
|
|
impl Actor for HasherWorker {
|
|
|
|
type Context = SyncContext<Self>;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Message)]
|
|
|
|
#[rtype(result = "Result<Hash>")]
|
|
|
|
pub struct ComputeHash {
|
|
|
|
pub path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Handler<ComputeHash> for HasherWorker {
|
|
|
|
type Result = Result<Hash>;
|
|
|
|
|
|
|
|
fn handle(&mut self, msg: ComputeHash, _: &mut Self::Context) -> Self::Result {
|
|
|
|
msg.path.hash()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 19:28:44 +02:00
|
|
|
impl Hashable for PathBuf {
|
|
|
|
fn hash(self: &PathBuf) -> Result<Hash> {
|
2020-09-07 21:21:54 +02:00
|
|
|
let fbuffer = FileBuffer::open(self)?;
|
|
|
|
Ok(hash(&fbuffer))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn hash<T: AsRef<[u8]>>(input: T) -> Hash {
|
|
|
|
let mut k12 = KangarooTwelve::new(b"");
|
|
|
|
k12.update(input.as_ref());
|
|
|
|
|
|
|
|
let mut result = [0u8; 256 / 8];
|
|
|
|
k12.finalize(&mut result);
|
|
|
|
Hash(Vec::from(result))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn encode<T: AsRef<[u8]>>(vec: T) -> String {
|
|
|
|
// multibase base58
|
|
|
|
format!("z{}", bs58::encode(vec).into_string())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn decode<T: AsRef<str>>(string: T) -> Result<Vec<u8>> {
|
|
|
|
let string = string.as_ref();
|
|
|
|
let (base, data) = string.split_at(1);
|
|
|
|
|
|
|
|
// multibase base58
|
|
|
|
if base != "z" {
|
|
|
|
Err(anyhow!("data not base58 encoded, bailing"))
|
|
|
|
} else {
|
|
|
|
Ok(bs58::decode(data).into_vec()?)
|
|
|
|
}
|
|
|
|
}
|
2021-02-19 22:27:54 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::hash::{decode, encode};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_encode_decode() {
|
|
|
|
let content = "Hello, World!".as_bytes();
|
|
|
|
|
|
|
|
let encoded = encode(content);
|
|
|
|
let decoded = decode(encoded);
|
|
|
|
|
|
|
|
assert!(decoded.is_ok());
|
|
|
|
|
|
|
|
assert_eq!(content, decoded.unwrap());
|
|
|
|
}
|
|
|
|
}
|