diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock index ad9c79f92..1b11c1aad 100644 --- a/apps/desktop/src-tauri/Cargo.lock +++ b/apps/desktop/src-tauri/Cargo.lock @@ -3980,9 +3980,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.11.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3518a68fc597f6a42f83a31e41c039c3cbaa10fa8bb239c936c235e81cce873f" +checksum = "71643f290d126e18ac2598876d01e1d57aed164afc78fdb6e2a0c6589a1f6662" dependencies = [ "aliasable", "ouroboros_macro", @@ -3991,9 +3991,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.11.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e23813b1bcb2d41a838849a2bbae40ae5c03c85ecabf04ba97086f438484714" +checksum = "ed9a247206016d424fe8497bc611e510887af5c261fbbf977877c4bb55ca4d82" dependencies = [ "Inflector", "proc-macro-error", @@ -5177,21 +5177,22 @@ dependencies = [ "swift-rs", "tokio", "ts-rs", + "uuid", "walkdir", ] [[package]] name = "sea-orm" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f594c2a48a3f2c7c911187c67a39d08f63af932801073737358bef0b5f06576" +checksum = "dd24380b48dacd3ed1c3d467c7b17ffa5818555a2c04066f4a0a9e17d830abc9" dependencies = [ "async-stream", "async-trait", "chrono", "futures", "futures-util", - "log", + "once_cell", "ouroboros", "rust_decimal", "sea-orm-macros", @@ -5200,15 +5201,16 @@ dependencies = [ "serde", "serde_json", "sqlx", + "tracing", "url", "uuid", ] [[package]] name = "sea-orm-macros" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73786f2ccb8f697d83e80a1ddd3c580ead76dddd068ebb4349b5ab648e625cd2" +checksum = "c199fa8630b1e195d7aef24ce8944af8f4ced67c4eccffd8926453b59f2565a1" dependencies = [ "bae", "heck 0.3.3", @@ -5219,9 +5221,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.19.4" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c6353d854a61e47b2691feded408c6ffd07ba9913311f0ff17c889ef2f102f" +checksum = "9088ff96158860a75d98a85a654fdd9d97b10515773af6d87339bfc48258c800" dependencies = [ "chrono", "rust_decimal", @@ -5245,22 +5247,23 @@ dependencies = [ [[package]] name = "sea-strum" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c77c6c6c8b3950fccb65edd5d04985b5377f4c8f669cb9a215553f0369ec001" +checksum = "391d06a6007842cfe79ac6f7f53911b76dfd69fc9a6769f1cf6569d12ce20e1b" dependencies = [ "sea-strum_macros", ] [[package]] name = "sea-strum_macros" -version = "0.21.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c247af6c2c4ffd372fe97e9afa579b4438e4c306c9aa3f11cbf72f1e845180" +checksum = "69b4397b825df6ccf1e98bcdabef3bbcfc47ff5853983467850eeab878384f21" dependencies = [ "heck 0.3.3", "proc-macro2", "quote", + "rustversion", "syn", ] @@ -6378,6 +6381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", + "log", "pin-project-lite 0.2.7", "tracing-attributes", "tracing-core", diff --git a/apps/desktop/src-tauri/src/commands.rs b/apps/desktop/src-tauri/src/commands.rs index db09caf26..8b5a2d551 100644 --- a/apps/desktop/src-tauri/src/commands.rs +++ b/apps/desktop/src-tauri/src/commands.rs @@ -1,15 +1,16 @@ use anyhow::Result; use sdcorelib::{ core_send_stream, - CoreConfig, - db::connection::db_instance, - file::{icon, indexer, locations, retrieve, retrieve::Directory, watcher::watch_dir}, get_core_config, native, + db::connection::db, + file::{icon, indexer, locations, retrieve, retrieve::Directory, watcher::watch_dir}, + native, + state::client::{get, ClientState}, }; use swift_rs::types::SRObjectArray; #[tauri::command(async)] pub async fn scan_dir(path: String) -> Result<(), String> { - db_instance().await?; + db().await?; let files = indexer::scan(&path).await.map_err(|e| e.to_string())?; @@ -23,9 +24,9 @@ pub async fn get_files(path: String) -> Result { Ok(retrieve::get_dir_with_contents(&path).await?) } -#[tauri::command(async)] -pub async fn get_config() -> Result<&'static CoreConfig, String> { - Ok(get_core_config()) +#[tauri::command] +pub fn get_config() -> ClientState { + get().unwrap() } #[tauri::command] @@ -56,9 +57,8 @@ pub async fn start_watcher(path: &str) -> Result<(), String> { Ok(()) } - #[tauri::command] pub async fn create_location(path: &str) -> Result<(), String> { let _location = locations::create_location(path); Ok(()) -} \ No newline at end of file +} diff --git a/packages/core/Cargo.lock b/packages/core/Cargo.lock index 1d56f7d85..82bf827b7 100644 --- a/packages/core/Cargo.lock +++ b/packages/core/Cargo.lock @@ -2795,9 +2795,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.11.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3518a68fc597f6a42f83a31e41c039c3cbaa10fa8bb239c936c235e81cce873f" +checksum = "71643f290d126e18ac2598876d01e1d57aed164afc78fdb6e2a0c6589a1f6662" dependencies = [ "aliasable", "ouroboros_macro", @@ -2806,9 +2806,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.11.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e23813b1bcb2d41a838849a2bbae40ae5c03c85ecabf04ba97086f438484714" +checksum = "ed9a247206016d424fe8497bc611e510887af5c261fbbf977877c4bb55ca4d82" dependencies = [ "Inflector", "proc-macro-error", @@ -3583,6 +3583,12 @@ dependencies = [ "webpki 0.22.0", ] +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + [[package]] name = "rw-stream-sink" version = "0.2.1" @@ -3677,21 +3683,22 @@ dependencies = [ "swift-rs", "tokio", "ts-rs", + "uuid", "walkdir", ] [[package]] name = "sea-orm" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f594c2a48a3f2c7c911187c67a39d08f63af932801073737358bef0b5f06576" +checksum = "dd24380b48dacd3ed1c3d467c7b17ffa5818555a2c04066f4a0a9e17d830abc9" dependencies = [ "async-stream", "async-trait", "chrono", "futures", "futures-util", - "log", + "once_cell", "ouroboros", "rust_decimal", "sea-orm-macros", @@ -3700,15 +3707,16 @@ dependencies = [ "serde", "serde_json", "sqlx", + "tracing", "url", "uuid", ] [[package]] name = "sea-orm-macros" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73786f2ccb8f697d83e80a1ddd3c580ead76dddd068ebb4349b5ab648e625cd2" +checksum = "c199fa8630b1e195d7aef24ce8944af8f4ced67c4eccffd8926453b59f2565a1" dependencies = [ "bae", "heck", @@ -3719,9 +3727,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.19.4" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c6353d854a61e47b2691feded408c6ffd07ba9913311f0ff17c889ef2f102f" +checksum = "9088ff96158860a75d98a85a654fdd9d97b10515773af6d87339bfc48258c800" dependencies = [ "chrono", "rust_decimal", @@ -3745,22 +3753,23 @@ dependencies = [ [[package]] name = "sea-strum" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c77c6c6c8b3950fccb65edd5d04985b5377f4c8f669cb9a215553f0369ec001" +checksum = "391d06a6007842cfe79ac6f7f53911b76dfd69fc9a6769f1cf6569d12ce20e1b" dependencies = [ "sea-strum_macros", ] [[package]] name = "sea-strum_macros" -version = "0.21.2" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c247af6c2c4ffd372fe97e9afa579b4438e4c306c9aa3f11cbf72f1e845180" +checksum = "69b4397b825df6ccf1e98bcdabef3bbcfc47ff5853983467850eeab878384f21" dependencies = [ "heck", "proc-macro2", "quote", + "rustversion", "syn", ] @@ -4373,6 +4382,39 @@ dependencies = [ "vec1", ] +[[package]] +name = "tracing" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite 0.2.8", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +dependencies = [ + "lazy_static", +] + [[package]] name = "trust-dns-proto" version = "0.20.4" diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index 0dae04293..5b3fb1484 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -39,12 +39,13 @@ ts-rs = "6.1" rusqlite = "0.25.3" refinery = { version = "0.6.0", features = ["rusqlite"] } sqlx = { version = "0.5.7", features = ["sqlite"] } -sea-orm = { version = "^0.4.2", features = [ "sqlx-sqlite", "runtime-async-std-rustls", "macros", "debug-print"], default-features = false } +sea-orm = { version = "^0.6.0", features = [ "sqlx-sqlite", "runtime-async-std-rustls", "macros", "debug-print"], default-features = false } walkdir = "^2.3.2" bytesize = "1.1.0" env_logger = "0.9.0" libp2p = "0.43.0" config = {version = "0.12", features = ["toml"]} lazy_static = "1.4.0" +uuid = "0.8" tokio = {version = "1.15.0", features=["sync"]} \ No newline at end of file diff --git a/packages/core/lib/config/mod.rs b/packages/core/lib/config/mod.rs deleted file mode 100644 index 266c62acc..000000000 --- a/packages/core/lib/config/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod state; diff --git a/packages/core/lib/config/state.rs b/packages/core/lib/config/state.rs deleted file mode 100644 index ce8f0073e..000000000 --- a/packages/core/lib/config/state.rs +++ /dev/null @@ -1,72 +0,0 @@ -use anyhow::Result; -use config::{Config, File, FileFormat}; -use lazy_static::lazy_static; -use serde::Deserialize; -use std::sync::RwLock; - -#[derive(Debug, Deserialize)] -pub struct ClientState { - pub client_id: String, - pub client_name: String, - pub tcp_port: u32, - - #[serde(rename = "arr")] - pub libraries: Vec, -} - -#[derive(Debug, Deserialize)] -pub struct Library { - pub library_id: String, - pub data_folder_path: String, -} - -impl Default for ClientState { - fn default() -> Self { - Self { - client_id: "".to_string(), - client_name: "".to_string(), - tcp_port: 0, - libraries: vec![], - } - } -} - -lazy_static! { - static ref CONFIG: RwLock = RwLock::new(Config::default()); -} - -pub fn get() -> Result { - let rw_lock = CONFIG.read().unwrap(); - - let client_state: ClientState = rw_lock - .clone() - .try_deserialize() - .unwrap_or(ClientState::default()); - - println!("{:?}", client_state); - - Ok(client_state) -} - -pub fn make(path: &str) -> ClientState { - let config_file_uri = format!("{}/config.yml", path); - - println!("{}", config_file_uri); - - let config = Config::builder() - .add_source(File::new(&config_file_uri, FileFormat::Yaml)) - .set_default("client_id", "1") - .unwrap_or_default() - .build() - .unwrap_or_default(); - - println!("{:?}", config); - - { - let mut lock = CONFIG.write().unwrap(); - - *lock = config; - } - - get().unwrap() -} diff --git a/packages/core/lib/db/connection.rs b/packages/core/lib/db/connection.rs index e67f35236..479cb6fc7 100644 --- a/packages/core/lib/db/connection.rs +++ b/packages/core/lib/db/connection.rs @@ -1,4 +1,4 @@ -use crate::get_core_config; +use crate::state; use anyhow::Result; use once_cell::sync::OnceCell; use rusqlite::Connection; @@ -8,9 +8,9 @@ use sea_orm::{Database, DatabaseConnection, DbErr}; // use std::str::FromStr; pub async fn get_connection() -> Result { - let config = get_core_config(); + let config = state::client::get().unwrap(); - let db_url = format!("{}{}", "sqlite://", config.primary_db.to_str().unwrap()); + let db_url = format!("{}{}", "sqlite://", config.get_current_library_db_path()); let db = Database::connect(&db_url).await?; @@ -18,7 +18,7 @@ pub async fn get_connection() -> Result { } pub static DB_INSTANCE: OnceCell = OnceCell::new(); -pub async fn db_instance() -> Result<&'static DatabaseConnection, String> { +pub async fn db() -> Result<&'static DatabaseConnection, String> { if DB_INSTANCE.get().is_none() { let db = get_connection().await.map_err(|e| e.to_string())?; DB_INSTANCE.set(db).unwrap_or_default(); @@ -29,12 +29,12 @@ pub async fn db_instance() -> Result<&'static DatabaseConnection, String> { } pub async fn create_primary_db() -> Result<(), sqlx::Error> { - let config = get_core_config(); + let config = state::client::get().unwrap(); - let db_url = config.primary_db.to_str().unwrap(); + let db_url = config.get_current_library_db_path(); // establish connection, this is only used to create the db if missing // replace in future - let mut connection = Connection::open(db_url).unwrap(); + let mut connection = Connection::open(&db_url).unwrap(); println!("Primary database initialized: {}", &db_url); diff --git a/packages/core/lib/db/entity/library.rs b/packages/core/lib/db/entity/library.rs index d828b85f8..9547c7266 100644 --- a/packages/core/lib/db/entity/library.rs +++ b/packages/core/lib/db/entity/library.rs @@ -15,6 +15,7 @@ pub struct Model { // identity #[sea_orm(primary_key)] pub id: u32, + pub uuid: String, pub name: String, pub is_primary: bool, pub remote_id: Option, diff --git a/packages/core/lib/db/migrations/primary/V1__initial.sql b/packages/core/lib/db/migrations/primary/V1__initial.sql index 4cbf5715f..a6dfd3563 100644 --- a/packages/core/lib/db/migrations/primary/V1__initial.sql +++ b/packages/core/lib/db/migrations/primary/V1__initial.sql @@ -1,5 +1,6 @@ CREATE TABLE IF NOT EXISTS libraries ( id INTEGER PRIMARY KEY AUTOINCREMENT, + uuid TEXT NOT NULL, name TEXT NOT NULL, remote_id TEXT, is_primary BOOLEAN NOT NULL DEFAULT TRUE, diff --git a/packages/core/lib/file/client.rs b/packages/core/lib/file/client.rs deleted file mode 100644 index e06e6bd9f..000000000 --- a/packages/core/lib/file/client.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::io::Write; -use std::{collections::HashMap, env}; - -use anyhow::Result; -use once_cell::sync::OnceCell; -use sea_orm::EntityTrait; -use sea_orm::Set; - -use sea_orm::{ActiveModelTrait, QueryOrder}; -use serde::{Deserialize, Serialize}; - -use crate::{ - db::{ - connection::db_instance, - entity::client::{self, Platform}, - }, - get_core_config, -}; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash)] -pub enum DotClientKey { - ClientId { client_id: String }, - TCPPort { tcp_port: u64 }, -} - -// // client config file struct -// #[derive(Serialize, Deserialize, Debug)] -// pub struct DotClientData { -// pub client_id: u32, -// pub client_name: Option, -// pub tcp_port: Option, -// } - -// in memory storage for config file -pub static CLIENT_CONFIG: OnceCell> = OnceCell::new(); - -fn get_client_config() -> Result<&'static HashMap> { - let client = CLIENT_CONFIG.get().unwrap(); - Ok(client) -} - -// method to update client config -pub fn update_client_config(key: DotClientKey, json_value: String) -> Result<()> { - let core_config = get_core_config(); - // clone existing config from memory - let mut config = CLIENT_CONFIG.get().unwrap().clone(); - // insert new value - config.insert(key, json_value); - // set in memory - CLIENT_CONFIG.set(config).unwrap(); - // convert to json - let json = serde_json::to_string(&config)?; - // create fresh dot file - let mut dotfile = - std::fs::File::create(format!("{}/.client_data", core_config.data_dir.display()))?; - // write json to file - dotfile.write_all(json.as_bytes())?; - - Ok(()) -} - -pub async fn init_client() -> Result<()> { - let config = get_core_config(); - - // read .client_data file from config.data_dir using serde to sterilize into DotClientData - let client_data_path = format!("{}/.client_data", config.data_dir.display()); - let client_data_file = std::fs::File::open(&client_data_path); - - match client_data_file { - Ok(file) => { - let client_data: HashMap = serde_json::from_reader(file).unwrap(); - CLIENT_CONFIG.set(client_data); - - println!("loaded existing client: {:?}", CLIENT_CONFIG.get().unwrap()); - } - Err(_) => { - let client_data = create_client().await?; - - println!("created new client {:?}", CLIENT_CONFIG.get().unwrap()); - } - }; - - Ok(()) -} - -pub async fn create_client() -> Result> { - let db = db_instance().await.unwrap(); - let config = get_core_config(); - - // get highest location id from db - let next_client_id = match client::Entity::find() - .order_by_desc(client::Column::Id) - .one(db) - .await - { - Ok(client) => client.map_or(1, |client| client.id + 1), - Err(_) => 1, - }; - - let hostname = match hostname::get() { - Ok(hostname) => hostname.to_str().unwrap().to_owned(), - Err(_) => "unknown".to_owned(), - }; - - let platform = match env::consts::OS { - "windows" => Platform::Windows, - "macos" => Platform::MacOS, - "linux" => Platform::Linux, - _ => Platform::Unknown, - }; - - let client = client::ActiveModel { - // id: Set(next_client_id), - name: Set(hostname), - platform: Set(platform), - online: Set(true), - ..Default::default() - }; - - client.save(db).await.map_err(|e| { - println!("error saving client: {:?}", e); - e - })?; - - // write a file called .spacedrive to path containing the location id in JSON format - let mut dotfile = std::fs::File::create(format!("{}/.client_data", config.data_dir.display()))?; - - let json = serde_json::to_string(&data)?; - - dotfile.write_all(json.as_bytes())?; - - Ok(data) -} - -// fn update_client_config(key: String, value: String) -> Result<&'static DotClientData> { -// let mut client = client_config.get().unwrap(); -// -// let existing_value = client[key]; -// -// Ok(client) -// } diff --git a/packages/core/lib/file/icon.rs b/packages/core/lib/file/icon.rs index aa4f19483..37f47af5e 100644 --- a/packages/core/lib/file/icon.rs +++ b/packages/core/lib/file/icon.rs @@ -1,16 +1,16 @@ -use crate::{file::retrieve, get_core_config, native, ClientEvent}; +use crate::{file::retrieve, native, state, ClientEvent}; use futures::{ stream::{self, StreamExt}, Stream, }; -use std::fs; +use std::{fs, path::Path}; pub async fn get_thumbs_for_directory(path: &str) -> impl Stream { let dir = retrieve::get_dir_with_contents(&path).await.unwrap(); stream::iter(dir.contents.into_iter()).filter_map(|file| async { - let config = get_core_config(); + let config = state::client::get().unwrap(); let icon_name = format!( "{}.png", if file.is_dir { @@ -19,7 +19,9 @@ pub async fn get_thumbs_for_directory(path: &str) -> impl Stream Result Result<()> { - let db = db_instance().await.unwrap(); + let db = db().await.unwrap(); let library = get_primary_library(&db).await; // if no library create one now diff --git a/packages/core/lib/file/locations.rs b/packages/core/lib/file/locations.rs index 163355e74..bf0f0348d 100644 --- a/packages/core/lib/file/locations.rs +++ b/packages/core/lib/file/locations.rs @@ -1,9 +1,9 @@ use anyhow::{anyhow, Result}; use chrono::Utc; -use sea_orm::{ActiveModelTrait, QueryOrder}; -use sea_orm::{EntityTrait, QueryFilter}; use sea_orm::ColumnTrait; use sea_orm::Set; +use sea_orm::{ActiveModelTrait, QueryOrder}; +use sea_orm::{EntityTrait, QueryFilter}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; use std::io::Write; @@ -24,9 +24,7 @@ struct DotSpaceDrive { location_id: u32, } -pub async fn get_location( - location_id: u32, -) -> Result { +pub async fn get_location(location_id: u32) -> Result { let db = DB_INSTANCE.get().unwrap(); // get location by location_id from db and include location_paths diff --git a/packages/core/lib/file/retrieve.rs b/packages/core/lib/file/retrieve.rs index d279aa016..21672abcb 100644 --- a/packages/core/lib/file/retrieve.rs +++ b/packages/core/lib/file/retrieve.rs @@ -1,4 +1,4 @@ -use crate::db::connection::db_instance; +use crate::db::connection::db; use crate::db::entity::file; use anyhow::Result; use sea_orm::ColumnTrait; @@ -12,7 +12,7 @@ pub struct Directory { } pub async fn get_dir_with_contents(path: &str) -> Result { - let connection = db_instance().await?; + let connection = db().await?; println!("getting files... {:?}", &path); diff --git a/packages/core/lib/library/client.rs b/packages/core/lib/library/client.rs new file mode 100644 index 000000000..5a6b12357 --- /dev/null +++ b/packages/core/lib/library/client.rs @@ -0,0 +1,66 @@ +use std::{collections::HashMap, env}; + +use anyhow::Result; + +use sea_orm::EntityTrait; +use sea_orm::Set; + +use sea_orm::{ActiveModelTrait, QueryOrder}; + +use crate::{ + db::{ + connection::db, + entity::client::{self, Platform}, + }, + state, +}; + +pub async fn create() -> Result<()> { + let db = db().await.unwrap(); + let config = state::client::get().unwrap(); + + // get highest location id from db + let next_client_id = match client::Entity::find() + .order_by_desc(client::Column::Id) + .one(db) + .await + { + Ok(client) => client.map_or(1, |client| client.id + 1), + Err(_) => 1, + }; + + let hostname = match hostname::get() { + Ok(hostname) => hostname.to_str().unwrap().to_owned(), + Err(_) => "unknown".to_owned(), + }; + + let platform = match env::consts::OS { + "windows" => Platform::Windows, + "macos" => Platform::MacOS, + "linux" => Platform::Linux, + _ => Platform::Unknown, + }; + + let mut client = client::ActiveModel { + // id: Set(next_client_id), + name: Set(hostname), + platform: Set(platform), + online: Set(true), + ..Default::default() + }; + + client = client.save(db).await.map_err(|e| { + println!("error saving client: {:?}", e); + e + })?; + + Ok(()) +} + +// fn update_client_config(key: String, value: String) -> Result<&'static DotClientData> { +// let mut client = client_config.get().unwrap(); +// +// let existing_value = client[key]; +// +// Ok(client) +// } diff --git a/packages/core/lib/library/init.rs b/packages/core/lib/library/init.rs new file mode 100644 index 000000000..f1faa8e3d --- /dev/null +++ b/packages/core/lib/library/init.rs @@ -0,0 +1,38 @@ +use anyhow::Result; +use sea_orm::ActiveModelTrait; +use sea_orm::Set; +use uuid::Uuid; + +use crate::{ + db::{connection::db, entity::library}, + state, + state::client::LibraryState, +}; + +pub async fn init_library() -> Result<()> { + let mut client_config = state::client::get()?; + let db = db().await.unwrap(); + + if client_config.libraries.len() == 0 { + // create default library + let uuid = Uuid::new_v4().to_string(); + + let library = LibraryState { + library_id: uuid.clone(), + library_path: format!("{}/primary_library.db", client_config.data_path), + }; + + client_config.libraries.push(library); + client_config.save(); + + let library = library::ActiveModel { + uuid: Set(uuid), + name: Set(String::from("My Library")), + ..Default::default() + }; + + library.save(db).await?; + } + + Ok(()) +} diff --git a/packages/core/lib/library/mod.rs b/packages/core/lib/library/mod.rs new file mode 100644 index 000000000..4d041e67f --- /dev/null +++ b/packages/core/lib/library/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod init; diff --git a/packages/core/lib/main.rs b/packages/core/lib/main.rs index 2a5d28996..e9c4cd026 100644 --- a/packages/core/lib/main.rs +++ b/packages/core/lib/main.rs @@ -1,3 +1,4 @@ +use futures::executor::block_on; use futures::{stream::StreamExt, Stream}; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; @@ -5,22 +6,16 @@ use std::fs; use tokio::sync::mpsc; use ts_rs::TS; -pub mod config; pub mod crypto; pub mod db; pub mod file; +pub mod library; pub mod native; +pub mod state; // pub mod p2p; pub mod util; -use futures::executor::block_on; -// static configuration passed in by host application -#[derive(Serialize, Deserialize, Debug)] -pub struct CoreConfig { - pub data_dir: std::path::PathBuf, - pub primary_db: std::path::PathBuf, - pub file_type_thumb_dir: std::path::PathBuf, -} +use crate::state::client::ClientState; // represents an event this library can emit #[derive(Serialize, Deserialize, Debug, TS)] @@ -33,16 +28,19 @@ pub enum ClientEvent { } pub struct Core { - pub config: CoreConfig, pub event_channel_sender: mpsc::Sender, } -pub static CORE: OnceCell = OnceCell::new(); - -pub fn get_core_config() -> &'static CoreConfig { - &CORE.get().unwrap().config +// static configuration passed in by host application +#[derive(Serialize, Deserialize, Debug)] +pub struct CoreConfig { + pub data_dir: std::path::PathBuf, + pub primary_db: std::path::PathBuf, + pub file_type_thumb_dir: std::path::PathBuf, } +pub static CORE: OnceCell = OnceCell::new(); + pub async fn core_send(event: ClientEvent) { println!("Core Event: {:?}", event); CORE.get() @@ -66,27 +64,28 @@ pub fn configure(mut data_dir: std::path::PathBuf) -> mpsc::Receiver, + pub primary_library_id: String, +} + +impl Default for ClientState { + fn default() -> Self { + ClientState { + client_id: "".to_string(), + data_path: "".to_string(), + client_name: "".to_string(), + tcp_port: 0, + libraries: vec![], + primary_library_id: "".to_string(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct LibraryState { + pub library_id: String, + pub library_path: String, +} + +impl Default for LibraryState { + fn default() -> Self { + LibraryState { + library_id: "".to_string(), + library_path: "".to_string(), + } + } +} + +// global, thread-safe storage for client state +lazy_static! { + static ref CONFIG: RwLock> = RwLock::new(None); +} + +pub fn get() -> Result { + let client_state = CONFIG.read().unwrap().as_ref().unwrap().clone(); + Ok(client_state) +} + +impl ClientState { + pub fn new(data_path: &str, client_name: &str) -> Result { + // create struct and assign defaults + let config = Self { + data_path: data_path.to_string(), + client_name: client_name.to_string(), + ..Default::default() + }; + config.save(); + Ok(config) + } + + pub fn save(&self) { + self.write_global(); + // only write to disk if config path is set + if !&self.data_path.is_empty() { + let config_path = format!("{}/.client_state", &self.data_path); + let mut file = fs::File::create(config_path).unwrap(); + let json = serde_json::to_string(&self).unwrap(); + file.write_all(json.as_bytes()).unwrap(); + } + } + + fn write_global(&self) { + { + let mut writeable = CONFIG.write().unwrap(); + *writeable = Some(self.clone()); + } + } + + pub fn get_primary_library(&self) -> LibraryState { + match self + .libraries + .iter() + .find(|lib| lib.library_id == self.primary_library_id) + { + Some(lib) => lib.clone(), + None => LibraryState::default(), + } + } + + pub fn get_current_library_db_path(&self) -> String { + format!( + "{}/primary_library.db", + &self.get_primary_library().library_path + ) + } +} diff --git a/packages/core/lib/state/mod.rs b/packages/core/lib/state/mod.rs new file mode 100644 index 000000000..b9babe5bc --- /dev/null +++ b/packages/core/lib/state/mod.rs @@ -0,0 +1 @@ +pub mod client;