mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-02 10:03:28 +00:00
spacedrive born
This commit is contained in:
parent
f8c9ae9033
commit
0ec1bfc0c7
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"ipfs",
|
||||
"nexusapp",
|
||||
"spacedriveapp",
|
||||
"tailwindcss"
|
||||
]
|
||||
}
|
|
@ -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
55
src-tauri/Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" ]
|
||||
|
|
|
@ -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
11
src-tauri/src/commands.rs
Normal 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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
20
src-tauri/src/filesystem/directory.rs
Normal file
20
src-tauri/src/filesystem/directory.rs
Normal 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>,
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod checksum;
|
||||
pub mod directory;
|
||||
pub mod 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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
10
src/App.tsx
10
src/App.tsx
|
@ -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);
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue