spacedrive born

This commit is contained in:
Jamie 2021-09-29 05:59:04 -07:00
parent f8c9ae9033
commit 0ec1bfc0c7
16 changed files with 157 additions and 91 deletions

View file

@ -1,7 +1,7 @@
{
"cSpell.words": [
"ipfs",
"nexusapp",
"spacedriveapp",
"tailwindcss"
]
}

View file

@ -1,5 +1,5 @@
{
"name": "nexus-client",
"name": "spacedrive-client",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",

55
src-tauri/Cargo.lock generated
View file

@ -492,6 +492,20 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "crossbeam"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
@ -526,6 +540,16 @@ dependencies = [
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
@ -1662,21 +1686,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nexus"
version = "0.1.0"
dependencies = [
"chrono",
"data-encoding",
"rebind",
"ring",
"rusqlite",
"serde",
"serde_json",
"tauri",
"tauri-build",
]
[[package]]
name = "nix"
version = "0.17.0"
@ -2756,6 +2765,22 @@ dependencies = [
"pango",
]
[[package]]
name = "spacedrive"
version = "0.1.0"
dependencies = [
"chrono",
"crossbeam",
"data-encoding",
"rebind",
"ring",
"rusqlite",
"serde",
"serde_json",
"tauri",
"tauri-build",
]
[[package]]
name = "spin"
version = "0.5.2"

View file

@ -1,11 +1,11 @@
[package]
name = "nexus"
name = "spacedrive"
version = "0.1.0"
description = "The next gen private virtual filesystem."
authors = ["you"]
license = ""
repository = ""
default-run = "nexus"
default-run = "spacedrive"
edition = "2018"
build = "src/build.rs"
@ -22,7 +22,8 @@ rebind = "0.2.1"
data-encoding = "2.3.2"
ring = "0.17.0-alpha.10"
rusqlite = "0.25.3"
chrono = { version = "0.4.0", features = ["serde"]}
chrono = { version = "0.4.0", features = ["serde"] }
crossbeam = "0.8.1"
[features]
default = [ "custom-protocol" ]

View file

View file

@ -8,7 +8,7 @@ pub struct AppConfig {
// returns the app config struct with complete values
pub fn get_config() -> AppConfig {
let app_name = "Nexus";
let app_name = "spacedrive";
let data_dir = path::data_dir()
.unwrap_or(std::path::PathBuf::from("./"))
.join(app_name);

11
src-tauri/src/commands.rs Normal file
View file

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

View file

@ -7,7 +7,6 @@ use std::io::{BufReader, Read};
fn sha256_digest<R: Read>(mut reader: R) -> io::Result<Digest> {
let mut context = Context::new(&SHA256);
let mut buffer = [0; 1024];
loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
@ -15,13 +14,14 @@ fn sha256_digest<R: Read>(mut reader: R) -> io::Result<Digest> {
}
context.update(&buffer[..count]);
}
Ok(context.finish())
}
pub fn create_hash(path: &str) -> io::Result<String> {
pub async fn create_hash(path: &str) -> io::Result<String> {
let input = File::open(path)?;
let reader = BufReader::new(input);
let digest = sha256_digest(reader)?;
Ok(HEXUPPER.encode(digest.as_ref()))
let hash = HEXUPPER.encode(digest.as_ref());
println!("hashing complete {}", hash);
Ok(hash)
}

View file

@ -0,0 +1,20 @@
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,8 +1,12 @@
use crate::crypto;
use chrono::prelude::*;
use crossbeam::thread;
use serde::{Deserialize, Serialize};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path;
use std::time::Instant;
use crate::filesystem::checksum;
use crate::util::time;
@ -11,7 +15,7 @@ use crate::util::time;
pub struct File {
// identity
pub id: Option<u64>,
pub checksum: String,
pub checksum: Option<String>,
pub uri: String,
// metadata
pub name: String,
@ -30,48 +34,50 @@ pub struct File {
pub date_indexed: DateTime<Utc>,
}
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>,
}
#[tauri::command]
pub fn read_file_command(path: &str) -> Result<File, String> {
let file = read_file(path).unwrap();
Ok(file)
}
pub fn read_file(path: &str) -> Result<File, String> {
// Read a file from path returning the File struct
// Generates checksum and extracts metadata
pub async fn read_file(path: &str) -> io::Result<File> {
// let start = Instant::now();
let path_buff = path::PathBuf::from(path);
// extract metadata
let metadata = fs::metadata(&path).unwrap();
if metadata.is_dir() {
panic!("Not a file, this is a directory");
}
let metadata = match fs::metadata(&path) {
Ok(metadata) => metadata,
Err(e) => return Err(e),
};
// if metadata.is_dir() {
// return Err();
// }
// let checksum = thread::scope(|s| {
// let res = s.spawn(move |_| checksum::create_hash(path).unwrap());
// res.join()
// })
// .unwrap()
// .unwrap();
// let checksum = match checksum {
// Ok(metadata) => metadata, // Err(e) => return Err(e.into()),
// };
// generate checksum
// let checksum = match checksum::create_hash(path) {
// Ok(checksum) => checksum,
// Err(e) => return Err(e),
// };
// assemble File struct with initial values
let file = File {
id: None,
name: path_buff.file_name().unwrap().to_str().unwrap().to_owned(),
extension: path_buff.extension().unwrap().to_str().unwrap().to_owned(),
name: extract_name(path_buff.file_name()),
extension: extract_name(path_buff.extension()),
uri: path.to_owned(),
checksum: checksum::create_hash(path).unwrap(),
size_in_bytes: metadata.len(),
date_created: time::system_time_to_date_time(metadata.created().unwrap()).unwrap(),
date_modified: time::system_time_to_date_time(metadata.created().unwrap()).unwrap(),
date_indexed: chrono::offset::Utc::now(),
date_created: time::system_time_to_date_time(metadata.created()).unwrap_or(Utc::now()),
date_modified: time::system_time_to_date_time(metadata.created()).unwrap_or(Utc::now()),
date_indexed: Utc::now(),
encryption: crypto::Encryption::NONE,
// this will be populated later, either by the database or other functions
id: None,
checksum: None,
ipfs_id: None,
user_id: None,
storage_device_id: None,
@ -79,7 +85,16 @@ pub fn read_file(path: &str) -> Result<File, String> {
parent_file_id: None,
};
println!("file: {:?}", file);
checksum::create_hash(path).await;
Ok(file)
}
// extract name from OsStr returned by PathBuff
fn extract_name(os_string: Option<&OsStr>) -> String {
os_string
.unwrap_or_default()
.to_str()
.unwrap_or_default()
.to_owned()
}

View file

@ -1,2 +1,3 @@
pub mod checksum;
pub mod directory;
pub mod file;

View file

@ -4,35 +4,20 @@
)]
mod app;
mod commands;
mod crypto;
mod db;
mod filesystem;
mod util;
use crate::app::menu;
#[derive(serde::Serialize)]
struct CustomResponse {
message: String,
}
#[tauri::command]
async fn fn_exposed_to_js(window: tauri::Window) -> Result<CustomResponse, String> {
println!("Called from window {}", window.label());
Ok(CustomResponse {
message: "Hello from rust!".to_string(),
})
}
fn main() {
let connection = db::init::create_connection();
// let hash = filestuff::create_hash("/Users/jamie/Desktop/jeff.MP4");
println!("jeff {:?}", connection);
println!("primary database connected {:?}", connection);
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
fn_exposed_to_js,
filesystem::file::read_file_command
])
.invoke_handler(tauri::generate_handler![commands::read_file_command])
.menu(menu::get_menu())
.run(tauri::generate_context!())
.expect("error while running tauri application");

View file

@ -2,9 +2,13 @@ use chrono::{offset::TimeZone, DateTime, NaiveDateTime, Utc};
use std::io;
use std::time::{SystemTime, UNIX_EPOCH};
pub fn system_time_to_date_time(system_time: SystemTime) -> io::Result<DateTime<Utc>> {
let std_duration = system_time.duration_since(UNIX_EPOCH).unwrap();
let chrono_duration = chrono::Duration::from_std(std_duration).unwrap();
pub fn system_time_to_date_time(
system_time: io::Result<SystemTime>,
) -> Result<DateTime<Utc>, Box<dyn std::error::Error>> {
// extract system time or resort to current time if failure
let system_time = system_time.unwrap_or(SystemTime::now());
let std_duration = system_time.duration_since(UNIX_EPOCH)?;
let chrono_duration = chrono::Duration::from_std(std_duration)?;
let unix = NaiveDateTime::from_timestamp(0, 0);
let naive = unix + chrono_duration;
let date_time: DateTime<Utc> = Utc.from_local_datetime(&naive).unwrap();

View file

@ -1,6 +1,6 @@
{
"package": {
"productName": "nexus",
"productName": "spacedrive",
"version": "0.1.0"
},
"build": {
@ -13,7 +13,7 @@
"bundle": {
"active": true,
"targets": "all",
"identifier": "org.nexusapp",
"identifier": "co.spacedrive.client",
"icon": ["icons/icon.icns"],
"resources": [],
"externalBin": [],
@ -52,7 +52,7 @@
},
"windows": [
{
"title": "Nexus",
"title": "spacedrive",
"width": 1200,
"height": 700,
"resizable": true,

View file

@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import { Button, colors, ColorScheme, extendTheme, Icon, Input, Switch } from '@vechaiui/react';
import { VechaiProvider } from '@vechaiui/react';
import { CookingPot } from 'phosphor-react';
@ -30,21 +30,25 @@ const theme = extendTheme({
export default function App() {
const fileUploader = useRef<HTMLInputElement | null>(null);
const [fileInputVal, setFileInputVal] = useState('/Users/jamie/Downloads/lol.mkv');
function changeHandler(e: any) {
console.log(e);
}
return (
<VechaiProvider theme={theme} colorScheme="pale">
<div data-tauri-drag-region className="max-w h-10 bg-primary-800"></div>
<div className="p-2">
<div className="flex flex-wrap w-full space-x-2">
<input type="file" id="file" onChange={changeHandler} />
<Input value={fileInputVal} onChange={(e) => setFileInputVal(e.target.value)} />
<input ref={fileUploader} type="file" id="file" onChange={changeHandler} />
<Button
variant="solid"
color="primary"
onClick={() => {
invoke('read_file_command', {
path: '/Users/jamie/Desktop/lol.png'
path: fileInputVal
}).then(console.log);
}}
>

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nexus</title>
<title>spacedrive</title>
</head>
<body style="overflow: hidden">
<div id="root"></div>