This commit is contained in:
Jamie 2021-10-02 11:42:04 -07:00
parent 2ea36666bc
commit 7b144525ed
13 changed files with 187 additions and 47 deletions

28
src-tauri/Cargo.lock generated
View file

@ -1121,6 +1121,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dotenv"
version = "0.15.0"
@ -3359,6 +3365,7 @@ dependencies = [
"serde",
"serde_json",
"sha256",
"snafu",
"sqlx",
"tauri",
"tauri-build",
@ -3669,6 +3676,27 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "snafu"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7"
dependencies = [
"doc-comment",
"snafu-derive",
]
[[package]]
name = "snafu-derive"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b"
dependencies = [
"proc-macro2",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]]
name = "socket2"
version = "0.4.1"

View file

@ -30,6 +30,8 @@ refinery = { version = "0.6.0", features = ["rusqlite"] }
sqlx = { version = "0.5.7", features = ["sqlite"] }
sea-orm = { version = "^0", features = [ "sqlx-sqlite", "runtime-async-std-rustls", "macros", "debug-print" ], default-features = false }
env_logger = "0.9.0"
# libusb = "0.3.0"
snafu = "0.6.10"
log = "0.4.14"
[features]

View file

@ -1,11 +1,11 @@
// use crate::filesystem::checksum;
use crate::filesystem::file;
use crate::filesystem::reader;
use tauri::InvokeError;
#[tauri::command(async)]
pub async fn read_file_command(path: &str) -> Result<String, InvokeError> {
let file = file::read_file(path)
let file = reader::read_file(path)
.await
.map_err(|error| InvokeError::from(format!("Failed to read file: {}", error)))?;

View file

@ -13,17 +13,48 @@ pub struct Model {
pub id: u32,
pub name: String,
pub uri: String,
pub watch: bool,
pub calculated_size_in_bytes: Option<String>,
pub calculated_file_count: Option<u32>,
pub date_created: Option<NaiveDateTime>,
pub date_modified: Option<NaiveDateTime>,
pub date_indexed: Option<NaiveDateTime>,
pub library_id: u32,
pub storage_device_id: Option<u32>,
pub parent_directory_id: Option<u32>,
pub storage_device_id: Option<u32>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
StorageDevice,
Library,
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Library => Entity::belongs_to(super::library::Entity)
.from(Column::LibraryId)
.to(super::library::Column::Id)
.into(),
Self::StorageDevice => Entity::belongs_to(super::storage_device::Entity)
.from(Column::StorageDeviceId)
.to(super::storage_device::Column::Id)
.into(),
}
}
}
impl Related<super::library::Entity> for Entity {
fn to() -> RelationDef {
Relation::Library.def()
}
}
impl Related<super::storage_device::Entity> for Entity {
fn to() -> RelationDef {
Relation::StorageDevice.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -24,6 +24,8 @@ pub struct Model {
pub name: String,
pub extension: String,
pub size_in_bytes: String,
pub library_id: String,
pub directory_id: String,
// #[sea_orm(column_type = "Int")]
// pub encryption: crypto::Encryption,
// ownership
@ -39,13 +41,24 @@ pub struct Model {
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Library,
Directory,
StorageDevice,
CaptureDevice,
ParentFile,
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Library => Entity::belongs_to(super::library::Entity)
.from(Column::LibraryId)
.to(super::library::Column::Id)
.into(),
Self::Directory => Entity::belongs_to(super::dir::Entity)
.from(Column::DirectoryId)
.to(super::dir::Column::Id)
.into(),
Self::StorageDevice => Entity::belongs_to(super::storage_device::Entity)
.from(Column::StorageDeviceId)
.to(super::storage_device::Column::Id)
@ -54,9 +67,23 @@ impl RelationTrait for Relation {
.from(Column::CaptureDeviceId)
.to(super::capture_device::Column::Id)
.into(),
Self::ParentFile => Entity::belongs_to(Entity)
.from(Column::ParentFileId)
.to(Column::Id)
.into(),
}
}
}
impl Related<super::library::Entity> for Entity {
fn to() -> RelationDef {
Relation::Library.def()
}
}
impl Related<super::dir::Entity> for Entity {
fn to() -> RelationDef {
Relation::Directory.def()
}
}
impl Related<super::storage_device::Entity> for Entity {
fn to() -> RelationDef {
Relation::StorageDevice.def()
@ -67,5 +94,10 @@ impl Related<super::capture_device::Entity> for Entity {
Relation::CaptureDevice.def()
}
}
impl Related<Entity> for Entity {
fn to() -> RelationDef {
Relation::ParentFile.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS files (
date_indexed DATE NOT NULL DEFAULT (datetime('now')),
library_id INTEGER NOT NULL,
storage_device_id INTEGER NOT NULL,
directory_id INTEGER,
directory_id INTEGER NOT NULL,
capture_device_id INTEGER,
parent_file_id INTEGER,
FOREIGN KEY(library_id) REFERENCES libraries(id),
@ -48,6 +48,7 @@ CREATE TABLE IF NOT EXISTS directories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
uri TEXT NOT NULL,
watch BOOLEAN NOT NULL DEFAULT FALSE,
encryption INTEGER DEFAULT 0,
calculated_size_in_bytes TEXT DEFAULT "0",
calculated_file_count INTEGER DEFAULT 0,

14
src-tauri/src/error.rs Normal file
View file

@ -0,0 +1,14 @@
use sea_orm::DbErr;
use snafu::Snafu;
use std::{io, path::PathBuf};
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("Unable to read configuration from {}: {}", path, source))]
DatabaseConnectionResult { source: DbErr, path: String },
#[snafu(display("Unable to write result to {}: {}", path.display(), source))]
WriteResult { source: io::Error, path: PathBuf },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;

View file

@ -18,7 +18,7 @@ fn sha256_digest<R: Read>(mut reader: R) -> io::Result<Digest> {
Ok(context.finish())
}
pub async fn create_hash(path: &str) -> io::Result<String> {
pub async fn create_buffer_checksum(path: &str) -> io::Result<String> {
let start = Instant::now();
// read file as buffer and convert to digest
let digest = sha256_digest(BufReader::new(std::fs::File::open(path)?))?;
@ -28,6 +28,6 @@ pub async fn create_hash(path: &str) -> io::Result<String> {
Ok(hex)
}
pub fn create_meta_hash(uri: String, size_in_bytes: u64) -> io::Result<String> {
pub fn create_meta_checksum(uri: String, size_in_bytes: u64) -> io::Result<String> {
Ok(digest(format!("{}{}", uri, size_in_bytes.to_string())))
}

View file

@ -0,0 +1,15 @@
use libusb;
pub async fn discover_storage_devices () => Result<()> {
let mut context = libusb::Context::new().unwrap();
for mut device in context.devices().unwrap().iter() {
let device_desc = device.device_descriptor().unwrap();
println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
device.bus_number(),
device.address(),
device_desc.vendor_id(),
device_desc.product_id());
}
}

View file

@ -1,20 +0,0 @@
use chrono::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Directory {
// identity
pub id: Option<u64>,
pub name: String,
// calculations
pub calculated_size_in_bytes: u64,
pub calculated_file_count: u32,
// ownership
pub user_id: Option<u64>,
pub storage_device_id: Option<u64>,
pub parent_directory_id: Option<u32>,
// date
pub date_created: DateTime<Utc>,
pub date_modified: DateTime<Utc>,
pub date_indexed: DateTime<Utc>,
}

View file

@ -1,4 +1,4 @@
pub mod checksum;
pub mod directory;
pub mod file;
// pub mod device;
pub mod init;
pub mod reader;

View file

@ -1,31 +1,70 @@
use crate::db;
use crate::db::entity::file;
use crate::filesystem::checksum;
use crate::util::time;
use sea_orm::entity::*;
use sea_orm::QueryFilter;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path;
use std::{fs, io, path, path::PathBuf};
// use crate::error::*;
use sea_orm::DbErr;
use snafu::{ResultExt, Snafu};
use crate::db::entity::file;
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("Unable to read configuration from {}: {}", path, source))]
DatabaseConnectionResult { source: DbErr, path: String },
#[snafu(display("Unable to read file metadata {}: {}", path.display(), source))]
ReadMetadata { source: io::Error, path: PathBuf },
#[snafu(display("Unable to check existing file {}: {}", meta_checksum, source))]
ExistingFileError {
source: DbErr,
meta_checksum: String,
},
#[snafu(display("Unable to check existing file {}", source))]
MetaChecksumError { source: io::Error },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub async fn path(path: &str) -> Result<()> {
let db = db::connection::get_connection()
.await
.context(DatabaseConnectionResult { path })?;
let path_buff = path::PathBuf::from(path);
let metadata = fs::metadata(&path).context(ReadMetadata { path: &path_buff })?;
if metadata.is_dir() {
// read_dir().await?;
} else {
read_file(&path, db, path_buff, metadata).await?;
}
Ok(())
}
// Read a file from path returning the File struct
// Generates meta checksum and extracts metadata
pub async fn read_file(path: &str) -> io::Result<()> {
let db = db::connection::get_connection().await.unwrap();
let path_buff = path::PathBuf::from(path);
let metadata = fs::metadata(&path)?;
pub async fn read_file(
path: &str,
db: sea_orm::DatabaseConnection,
path_buff: path::PathBuf,
metadata: fs::Metadata,
) -> Result<()> {
let size = metadata.len();
let meta_checksum = checksum::create_meta_hash(path.to_owned(), size)?;
let meta_checksum =
checksum::create_meta_checksum(path.to_owned(), size).context(MetaChecksumError {})?;
let existing_files = file::Entity::find()
.filter(file::Column::MetaChecksum.contains(&meta_checksum))
.all(&db)
.await
.unwrap();
.context(ExistingFileError {
meta_checksum: &meta_checksum,
})?;
if existing_files.len() == 0 {
let file = file::ActiveModel {
@ -69,8 +108,3 @@ fn extract_name(os_string: Option<&OsStr>) -> String {
.unwrap_or_default()
.to_owned()
}
// pub async fn commit_file(file: &File) -> Result<(), InvokeError> {
// let connection = db::connection::get_connection()?;
// });

View file

@ -7,6 +7,7 @@ mod app;
mod commands;
mod crypto;
mod db;
mod error;
mod filesystem;
mod util;
use crate::app::menu;
@ -25,6 +26,8 @@ fn main() {
// init filesystem and create library if missing
block_on(filesystem::init::init_library()).unwrap();
// block_on(filesystem::device::discover_storage_devices()).unwrap();
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
commands::read_file_command,