parent
2ddfec4bfc
commit
a515ac47ae
@ -0,0 +1,4 @@
|
|||||||
|
//! Consts
|
||||||
|
|
||||||
|
/// Size for most buffers
|
||||||
|
pub const BUFFER_SIZE: usize = 4096;
|
@ -1 +1,47 @@
|
|||||||
//! Handles building the database, and exposes data structures for the database and ways to interact with them
|
//! Handles building the database, and exposes data structures for the database and ways to interact with them
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
collections::{
|
||||||
|
HashMap,
|
||||||
|
HashSet,
|
||||||
|
},
|
||||||
|
path::{
|
||||||
|
PathBuf,
|
||||||
|
Path,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use chrono::{
|
||||||
|
DateTime,
|
||||||
|
Utc,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Database
|
||||||
|
{
|
||||||
|
/// Key here is the actual location in /tmp/videl of the database and versioned files
|
||||||
|
database: HashMap<PathBuf,Entry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Entry
|
||||||
|
{
|
||||||
|
/// Versions are a hashset because we don't need to version files that are /entirely/ identical. (i.e. same timestamp and hash)
|
||||||
|
versions: HashSet<Version>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Version
|
||||||
|
{
|
||||||
|
date: DateTime<Utc>,
|
||||||
|
hash: hash::Sha256Sum,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Version
|
||||||
|
{
|
||||||
|
/// Gets the lowermost name of the path for this specific version
|
||||||
|
pub fn get_pathname(&self) -> String
|
||||||
|
{
|
||||||
|
format!("{}", self.date.timestamp_nanos())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,149 @@
|
|||||||
|
//! Hashing abstraction
|
||||||
|
use super::*;
|
||||||
|
use sha2::{
|
||||||
|
Sha256, Digest,
|
||||||
|
};
|
||||||
|
use tokio::{
|
||||||
|
prelude::*,
|
||||||
|
io::{
|
||||||
|
AsyncRead,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
marker::Unpin,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SHA256_SIZE: usize = 32;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Ord, PartialOrd)]
|
||||||
|
pub struct Sha256Sum([u8; SHA256_SIZE]);
|
||||||
|
|
||||||
|
impl Default for Sha256Sum
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self([0; SHA256_SIZE])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sha256Sum
|
||||||
|
{
|
||||||
|
/// Create a new empty hash sum container
|
||||||
|
pub const fn empty() -> Self
|
||||||
|
{
|
||||||
|
Self([0; SHA256_SIZE])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_raw(from: [u8; SHA256_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_slice(from: &[u8]) -> Self
|
||||||
|
{
|
||||||
|
let mut output = [0u8; SHA256_SIZE];
|
||||||
|
assert_eq!(util::copy_slice(&mut output, from), SHA256_SIZE);
|
||||||
|
Self(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute SHA256 hash from a slice
|
||||||
|
pub fn compute_slice<T>(from: T) -> Self
|
||||||
|
where T: AsRef<[u8]>
|
||||||
|
{
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(from.as_ref());
|
||||||
|
|
||||||
|
Self::from_slice(&hasher.finalize()[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute SHA256 from a stream
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
/// Will read until 0 bytes are returned from the `read()` call.
|
||||||
|
pub async fn compute_stream<W>(from: &mut W) -> io::Result<Self>
|
||||||
|
where W: AsyncRead + Unpin
|
||||||
|
{
|
||||||
|
let mut read;
|
||||||
|
let mut buffer = [0u8; consts::BUFFER_SIZE];
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
while {read = from.read(&mut buffer[..]).await?; read != 0} {
|
||||||
|
hasher.update(&buffer[..read]);
|
||||||
|
}
|
||||||
|
Ok(Self::from_slice(&hasher.finalize()[..]))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute from a stream into this instance. Return the number of bytes successfully written into the instance.
|
||||||
|
pub async fn compute_into<W>(&mut self, from: &mut W) -> io::Result<usize>
|
||||||
|
where W: AsyncRead + Unpin
|
||||||
|
{
|
||||||
|
let mut read;
|
||||||
|
let mut done=0;
|
||||||
|
let mut buffer = [0u8; consts::BUFFER_SIZE];
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
while {read = from.read(&mut buffer[..]).await?; done += read; read !=0} {
|
||||||
|
hasher.update(&buffer[..read]);
|
||||||
|
}
|
||||||
|
util::copy_slice(self, hasher.finalize());
|
||||||
|
Ok(done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Sha256Sum
|
||||||
|
{
|
||||||
|
#[inline] fn as_ref(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
&self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for Sha256Sum
|
||||||
|
{
|
||||||
|
#[inline] fn as_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
&mut self.0[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<[u8; SHA256_SIZE]> for Sha256Sum
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: [u8; SHA256_SIZE]) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sha256> for Sha256Sum
|
||||||
|
{
|
||||||
|
fn from(from: Sha256) -> Self
|
||||||
|
{
|
||||||
|
Self::from_slice(&from.finalize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update a hasher from a stream async
|
||||||
|
pub async fn stream_async<H, W>(hasher: &mut H, from: &mut W) -> io::Result<usize>
|
||||||
|
where H: Digest,
|
||||||
|
W: AsyncRead + Unpin
|
||||||
|
{
|
||||||
|
let mut read;
|
||||||
|
let mut done=0;
|
||||||
|
let mut buffer = [0u8; consts::BUFFER_SIZE];
|
||||||
|
while {read = from.read(&mut buffer[..]).await?; done += read; read !=0} {
|
||||||
|
hasher.update(&buffer[..read]);
|
||||||
|
}
|
||||||
|
Ok(done)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Sha256Sum
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
for byte in self.0.iter()
|
||||||
|
{
|
||||||
|
write!(f, "{:02x}", byte)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
//! Utility functions
|
||||||
|
use std::{
|
||||||
|
borrow::{
|
||||||
|
Borrow,
|
||||||
|
ToOwned,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Copy slice `src` into `dst` and return the number of elements copied.
|
||||||
|
#[inline] pub fn copy_slice<T,U,V,W,X>(mut dst: V, src: W) -> usize
|
||||||
|
where V: AsMut<[T]>,
|
||||||
|
W: AsRef<[U]>,
|
||||||
|
U: ToOwned<Owned=X>,
|
||||||
|
X: Borrow<U> + Into<T>
|
||||||
|
{
|
||||||
|
|
||||||
|
let mut i=0;
|
||||||
|
for (d, s) in dst.as_mut().iter_mut().zip(src.as_ref().iter())
|
||||||
|
{
|
||||||
|
*d = s.to_owned().into();
|
||||||
|
i+=1
|
||||||
|
}
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
#[test]
|
||||||
|
fn copy_slice()
|
||||||
|
{
|
||||||
|
let mut to = [0u8; 40];
|
||||||
|
let from = [10u8; 37];
|
||||||
|
|
||||||
|
assert_eq!(super::copy_slice(&mut to, &from), 37);
|
||||||
|
|
||||||
|
assert_eq!(from, &to[0..37]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue