diff --git a/gitbutler-app/src/app.rs b/gitbutler-app/src/app.rs index 8ea18350c..b52910d33 100644 --- a/gitbutler-app/src/app.rs +++ b/gitbutler-app/src/app.rs @@ -12,6 +12,7 @@ use crate::{ users, watcher, }; +#[derive(Clone)] pub struct App { local_data_dir: path::PathBuf, projects: projects::Controller, @@ -36,21 +37,39 @@ impl TryFrom<&AppHandle> for App { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - watchers: value.state::().inner().clone(), - sessions_database: sessions::Database::from(value), - }) + if let Some(app) = value.try_state::() { + Ok(app.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let watchers = watcher::Watchers::try_from(value)?; + let sessions_database = sessions::Database::try_from(value)?; + let app = App::new(app_data_dir, projects, users, watchers, sessions_database); + value.manage(app.clone()); + Ok(app) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl App { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + watchers: watcher::Watchers, + sessions_database: sessions::Database, + ) -> Self { + Self { + local_data_dir, + projects, + users, + watchers, + sessions_database, + } + } + pub fn init_project(&self, project: &projects::Project) -> Result<()> { self.watchers.watch(project).context(format!( "failed to start watcher for project {}", diff --git a/gitbutler-app/src/assets.rs b/gitbutler-app/src/assets.rs index 3dbec8684..b0d40e7a6 100644 --- a/gitbutler-app/src/assets.rs +++ b/gitbutler-app/src/assets.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, fs, path, sync}; use anyhow::{Context, Result}; use futures::future::join_all; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Semaphore; use url::Url; @@ -20,33 +20,34 @@ pub struct Proxy { semaphores: sync::Arc>>, } -impl From<&path::PathBuf> for Proxy { - fn from(value: &path::PathBuf) -> Self { - Self { - cache_dir: value.clone(), - semaphores: sync::Arc::new(tokio::sync::Mutex::new(HashMap::new())), - } - } -} - impl TryFrom<&AppHandle> for Proxy { type Error = anyhow::Error; - fn try_from(handle: &AppHandle) -> Result { - let app_cache_dir = handle - .path_resolver() - .app_cache_dir() - .context("failed to get cache dir")?; - fs::create_dir_all(&app_cache_dir).context("failed to create cache dir")?; - let cache_dir = app_cache_dir.join("images"); - - Ok(Self::from(&cache_dir)) + fn try_from(value: &AppHandle) -> Result { + if let Some(proxy) = value.try_state::() { + Ok(proxy.inner().clone()) + } else if let Some(app_cache_dir) = value.path_resolver().app_cache_dir() { + fs::create_dir_all(&app_cache_dir).context("failed to create cache dir")?; + let cache_dir = app_cache_dir.join("images"); + let proxy = Self::new(cache_dir); + value.manage(proxy.clone()); + Ok(proxy) + } else { + Err(anyhow::anyhow!("failed to get app cache dir")) + } } } const ASSET_SCHEME: &str = "asset"; impl Proxy { + fn new(cache_dir: path::PathBuf) -> Self { + Proxy { + cache_dir, + semaphores: sync::Arc::new(tokio::sync::Mutex::new(HashMap::new())), + } + } + pub async fn proxy_user(&self, user: users::User) -> users::User { match Url::parse(&user.picture) { Ok(picture) => users::User { diff --git a/gitbutler-app/src/bin.rs b/gitbutler-app/src/bin.rs index 38e597b16..6fe4efb13 100644 --- a/gitbutler-app/src/bin.rs +++ b/gitbutler-app/src/bin.rs @@ -103,7 +103,7 @@ fn main() { .expect("failed to initialize zipc controller "); tauri_app.manage(zipper); - let deltas_controller = deltas::Controller::from(&app_handle); + let deltas_controller = deltas::Controller::try_from(&app_handle).expect("failed to initialize deltas controller"); app_handle.manage(deltas_controller); let sessions_controller = sessions::Controller::try_from(&app_handle) @@ -119,10 +119,10 @@ fn main() { .expect("failed to initialize virtual branches controller"); app_handle.manage(vbranch_contoller); - let keys_controller = keys::Controller::from(&app_handle); + let keys_controller = keys::Controller::try_from(&app_handle).expect("failed to initialize keys controller"); app_handle.manage(keys_controller); - let users_controller = users::Controller::from(&app_handle); + let users_controller = users::Controller::try_from(&app_handle).expect("failed to initialize users controller"); let stores = tauri_app.state::>(); if let Some(path) = app_handle.path_resolver().app_config_dir().map(|path| path.join(PathBuf::from("settings.json"))) { diff --git a/gitbutler-app/src/database.rs b/gitbutler-app/src/database.rs index 31fd1ac3c..b0e4fef87 100644 --- a/gitbutler-app/src/database.rs +++ b/gitbutler-app/src/database.rs @@ -6,7 +6,7 @@ use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; use refinery::config::Config; use rusqlite::Transaction; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; mod embedded { use refinery::embed_migrations; @@ -18,24 +18,18 @@ pub struct Database { pool: Arc>, } -impl TryFrom<&path::PathBuf> for Database { - type Error = anyhow::Error; - - fn try_from(path: &path::PathBuf) -> Result { - fs::create_dir_all(path).context("Failed to create local data dir")?; - Self::open(path.join("database.sqlite3")) - } -} - impl TryFrom<&AppHandle> for Database { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Self::try_from(&path) + if let Some(database) = value.try_state::() { + Ok(database.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + fs::create_dir_all(&app_data_dir).context("failed to create local data dir")?; + Self::open(app_data_dir.join("database.sqlite3")) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } diff --git a/gitbutler-app/src/deltas/controller.rs b/gitbutler-app/src/deltas/controller.rs index f1dde9406..eca9236b3 100644 --- a/gitbutler-app/src/deltas/controller.rs +++ b/gitbutler-app/src/deltas/controller.rs @@ -1,19 +1,27 @@ use std::collections::HashMap; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{projects::ProjectId, sessions::SessionId}; use super::{database, Delta}; +#[derive(Clone)] pub struct Controller { database: database::Database, } -impl From<&AppHandle> for Controller { - fn from(handle: &AppHandle) -> Self { - Self { - database: database::Database::from(handle), +impl TryFrom<&AppHandle> for Controller { + type Error = anyhow::Error; + + fn try_from(value: &AppHandle) -> Result { + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else { + let database = database::Database::try_from(value)?; + let controller = Controller::new(database); + value.manage(controller.clone()); + Ok(controller) } } } @@ -25,6 +33,10 @@ pub enum ListError { } impl Controller { + fn new(database: database::Database) -> Controller { + Controller { database } + } + pub fn list_by_session_id( &self, project_id: &ProjectId, diff --git a/gitbutler-app/src/deltas/database.rs b/gitbutler-app/src/deltas/database.rs index c69edffc7..174cc0ad3 100644 --- a/gitbutler-app/src/deltas/database.rs +++ b/gitbutler-app/src/deltas/database.rs @@ -12,19 +12,25 @@ pub struct Database { database: database::Database, } -impl From for Database { - fn from(database: database::Database) -> Self { - Self { database } - } -} +impl TryFrom<&AppHandle> for Database { + type Error = anyhow::Error; -impl From<&AppHandle> for Database { - fn from(value: &AppHandle) -> Self { - Self::from(value.state::().inner().clone()) + fn try_from(value: &AppHandle) -> Result { + if let Some(database) = value.try_state::() { + Ok(database.inner().clone()) + } else { + let database = Database::new(database::Database::try_from(value)?); + value.manage(database.clone()); + Ok(database) + } } } impl Database { + fn new(database: database::Database) -> Database { + Database { database } + } + pub fn insert( &self, project_id: &ProjectId, @@ -108,8 +114,8 @@ fn list_by_project_id_session_id_stmt<'conn>( ) -> Result> { Ok(tx.prepare_cached( " - SELECT `file_path`, `timestamp_ms`, `operations` - FROM `deltas` + SELECT `file_path`, `timestamp_ms`, `operations` + FROM `deltas` WHERE `session_id` = :session_id AND `project_id` = :project_id ORDER BY `timestamp_ms` ASC", )?) diff --git a/gitbutler-app/src/events.rs b/gitbutler-app/src/events.rs index 96cd7fcaa..c788373df 100644 --- a/gitbutler-app/src/events.rs +++ b/gitbutler-app/src/events.rs @@ -14,15 +14,25 @@ pub struct Sender { app_handle: tauri::AppHandle, } -impl From<&AppHandle> for Sender { - fn from(value: &AppHandle) -> Self { - Self { - app_handle: value.clone(), +impl TryFrom<&AppHandle> for Sender { + type Error = anyhow::Error; + + fn try_from(value: &AppHandle) -> Result { + if let Some(sender) = value.try_state::() { + Ok(sender.inner().clone()) + } else { + let sender = Sender::new(value.clone()); + value.manage(sender.clone()); + Ok(sender) } } } impl Sender { + fn new(app_handle: AppHandle) -> Sender { + Sender { app_handle } + } + pub fn send(&self, event: &Event) -> Result<()> { self.app_handle .emit_all(&event.name, Some(&event.payload)) diff --git a/gitbutler-app/src/git/credentials.rs b/gitbutler-app/src/git/credentials.rs index 0ee617c77..2ba6ebd60 100644 --- a/gitbutler-app/src/git/credentials.rs +++ b/gitbutler-app/src/git/credentials.rs @@ -1,6 +1,6 @@ use std::{env, path}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{keys, project_repository, projects, users}; @@ -76,19 +76,20 @@ pub struct Helper { home_dir: Option, } -impl From<&AppHandle> for Helper { - fn from(value: &AppHandle) -> Self { - let keys = keys::Controller::from(value); - let users = users::Controller::from(value); - Self::new(keys, users, env::var_os("HOME").map(path::PathBuf::from)) - } -} +impl TryFrom<&AppHandle> for Helper { + type Error = anyhow::Error; -impl From<&path::PathBuf> for Helper { - fn from(value: &path::PathBuf) -> Self { - let keys = keys::Controller::from(value); - let users = users::Controller::from(value); - Self::new(keys, users, env::var_os("HOME").map(path::PathBuf::from)) + fn try_from(value: &AppHandle) -> Result { + if let Some(helper) = value.try_state::() { + Ok(helper.inner().clone()) + } else { + let keys = keys::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let home_dir = env::var_os("HOME").map(path::PathBuf::from); + let helper = Helper::new(keys, users, home_dir); + value.manage(helper.clone()); + Ok(helper) + } } } diff --git a/gitbutler-app/src/keys/controller.rs b/gitbutler-app/src/keys/controller.rs index 260688876..912824988 100644 --- a/gitbutler-app/src/keys/controller.rs +++ b/gitbutler-app/src/keys/controller.rs @@ -1,9 +1,5 @@ -use std::path; - use anyhow::Context; -use tauri::AppHandle; - -use crate::storage; +use tauri::{AppHandle, Manager}; use super::{storage::Storage, PrivateKey}; @@ -12,35 +8,23 @@ pub struct Controller { storage: Storage, } -impl From<&path::PathBuf> for Controller { - fn from(value: &path::PathBuf) -> Self { - Self { - storage: Storage::from(value), - } - } -} +impl TryFrom<&AppHandle> for Controller { + type Error = anyhow::Error; -impl From<&storage::Storage> for Controller { - fn from(value: &storage::Storage) -> Self { - Self { - storage: Storage::from(value), - } - } -} - -impl From<&AppHandle> for Controller { - fn from(value: &AppHandle) -> Self { - Self { - storage: Storage::from(value), + fn try_from(value: &AppHandle) -> Result { + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else { + let controller = Controller::new(Storage::try_from(value)?); + value.manage(controller.clone()); + Ok(controller) } } } impl Controller { - pub fn new(storage: &Storage) -> Self { - Self { - storage: storage.clone(), - } + fn new(storage: Storage) -> Self { + Self { storage } } pub fn get_or_create(&self) -> Result { diff --git a/gitbutler-app/src/keys/storage.rs b/gitbutler-app/src/keys/storage.rs index f682b47d3..8cc223ec4 100644 --- a/gitbutler-app/src/keys/storage.rs +++ b/gitbutler-app/src/keys/storage.rs @@ -1,5 +1,3 @@ -use std::path; - use tauri::{AppHandle, Manager}; use crate::storage; @@ -19,27 +17,25 @@ pub enum Error { SSHKey(#[from] ssh_key::Error), } -impl From<&storage::Storage> for Storage { - fn from(storage: &storage::Storage) -> Self { - Self { - storage: storage.clone(), +impl TryFrom<&AppHandle> for Storage { + type Error = anyhow::Error; + + fn try_from(value: &AppHandle) -> Result { + if let Some(storage) = value.try_state::() { + Ok(storage.inner().clone()) + } else { + let storage = Storage::new(storage::Storage::try_from(value)?); + value.manage(storage.clone()); + Ok(storage) } } } -impl From<&AppHandle> for Storage { - fn from(handle: &AppHandle) -> Self { - Self::from(handle.state::().inner()) - } -} - -impl From<&path::PathBuf> for Storage { - fn from(value: &path::PathBuf) -> Self { - Self::from(&storage::Storage::from(value)) - } -} - impl Storage { + fn new(storage: storage::Storage) -> Storage { + Storage { storage } + } + pub fn get(&self) -> Result, Error> { self.storage .read("keys/ed25519") diff --git a/gitbutler-app/src/projects/controller.rs b/gitbutler-app/src/projects/controller.rs index 7454cfddb..9473e30fd 100644 --- a/gitbutler-app/src/projects/controller.rs +++ b/gitbutler-app/src/projects/controller.rs @@ -19,26 +19,17 @@ impl TryFrom<&AppHandle> for Controller { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects_storage: storage::Storage::from(value), - users: users::Controller::from(value), - watchers: Some(value.state::().inner().clone()), - }) - } -} - -impl From<&path::PathBuf> for Controller { - fn from(value: &path::PathBuf) -> Self { - Self { - local_data_dir: value.clone(), - projects_storage: storage::Storage::from(value), - users: users::Controller::from(value), - watchers: None, + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + Ok(Self { + local_data_dir: app_data_dir, + projects_storage: storage::Storage::try_from(value)?, + users: users::Controller::try_from(value)?, + watchers: Some(watcher::Watchers::try_from(value)?), + }) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) } } } diff --git a/gitbutler-app/src/projects/storage.rs b/gitbutler-app/src/projects/storage.rs index 53f6cc4cc..a14f3e6d7 100644 --- a/gitbutler-app/src/projects/storage.rs +++ b/gitbutler-app/src/projects/storage.rs @@ -1,5 +1,3 @@ -use std::path; - use serde::{Deserialize, Serialize}; use tauri::{AppHandle, Manager}; @@ -15,26 +13,20 @@ pub struct Storage { storage: storage::Storage, } -impl From<&storage::Storage> for Storage { - fn from(storage: &storage::Storage) -> Self { - Storage { - storage: storage.clone(), +impl TryFrom<&AppHandle> for Storage { + type Error = anyhow::Error; + + fn try_from(value: &AppHandle) -> Result { + if let Some(storage) = value.try_state::() { + Ok(storage.inner().clone()) + } else { + let storage = Storage::new(storage::Storage::try_from(value)?); + value.manage(storage.clone()); + Ok(storage) } } } -impl From<&path::PathBuf> for Storage { - fn from(value: &path::PathBuf) -> Self { - Self::from(&storage::Storage::from(value)) - } -} - -impl From<&AppHandle> for Storage { - fn from(value: &AppHandle) -> Self { - Self::from(value.state::().inner()) - } -} - #[derive(Debug, Serialize, Deserialize, Default)] pub struct UpdateRequest { pub id: ProjectId, @@ -60,6 +52,10 @@ pub enum Error { } impl Storage { + fn new(storage: storage::Storage) -> Storage { + Storage { storage } + } + pub fn list(&self) -> Result, Error> { match self.storage.read(PROJECTS_FILE)? { Some(projects) => { diff --git a/gitbutler-app/src/sessions/controller.rs b/gitbutler-app/src/sessions/controller.rs index b8fe47716..be68d9419 100644 --- a/gitbutler-app/src/sessions/controller.rs +++ b/gitbutler-app/src/sessions/controller.rs @@ -1,7 +1,7 @@ use std::path; use anyhow::Context; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{ gb_repository, project_repository, @@ -11,6 +11,7 @@ use crate::{ use super::{Database, Session}; +#[derive(Clone)] pub struct Controller { local_data_dir: path::PathBuf, sessions_database: Database, @@ -23,16 +24,18 @@ impl TryFrom<&AppHandle> for Controller { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - sessions_database: Database::from(value), - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + Ok(Self { + local_data_dir: app_data_dir, + sessions_database: Database::try_from(value)?, + projects: projects::Controller::try_from(value)?, + users: users::Controller::try_from(value)?, + }) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } diff --git a/gitbutler-app/src/sessions/database.rs b/gitbutler-app/src/sessions/database.rs index 09d4caa4e..c2687e180 100644 --- a/gitbutler-app/src/sessions/database.rs +++ b/gitbutler-app/src/sessions/database.rs @@ -10,21 +10,25 @@ pub struct Database { database: database::Database, } -impl From for Database { - fn from(database: database::Database) -> Self { - Self { database } - } -} +impl TryFrom<&AppHandle> for Database { + type Error = anyhow::Error; -impl From<&AppHandle> for Database { - fn from(value: &AppHandle) -> Self { - Self { - database: value.state::().inner().clone(), + fn try_from(value: &AppHandle) -> Result { + if let Some(database) = value.try_state::() { + Ok(database.inner().clone()) + } else { + let database = Database::new(database::Database::try_from(value)?); + value.manage(database.clone()); + Ok(database) } } } impl Database { + fn new(database: database::Database) -> Database { + Database { database } + } + pub fn insert(&self, project_id: &ProjectId, sessions: &[&session::Session]) -> Result<()> { self.database.transaction(|tx| -> Result<()> { let mut stmt = insert_stmt(tx).context("Failed to prepare insert statement")?; diff --git a/gitbutler-app/src/storage.rs b/gitbutler-app/src/storage.rs index cf954f5eb..4e8bfbaf0 100644 --- a/gitbutler-app/src/storage.rs +++ b/gitbutler-app/src/storage.rs @@ -1,13 +1,13 @@ use std::{ fs, - path::{self, Path, PathBuf}, + path::{Path, PathBuf}, sync::{Arc, RwLock}, }; #[cfg(target_family = "unix")] use std::os::unix::prelude::*; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; #[derive(Debug, Default, Clone)] pub struct Storage { @@ -24,25 +24,25 @@ impl TryFrom<&AppHandle> for Storage { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value.path_resolver().app_data_dir(); - match path { - Some(path) => Ok(Self::from(&path)), - // None => Error::new("failed to get app data dir"), - None => Err(anyhow::anyhow!("failed to get app data dir")), - // None => Ok(Self::default()), - } - } -} - -impl From<&path::PathBuf> for Storage { - fn from(value: &path::PathBuf) -> Self { - Storage { - local_data_dir: Arc::new(RwLock::new(value.clone())), + if let Some(storage) = value.try_state::() { + Ok(storage.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let storage = Storage::new(app_data_dir); + value.manage(storage.clone()); + Ok(storage) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) } } } impl Storage { + fn new>(local_data_dir: P) -> Storage { + Storage { + local_data_dir: Arc::new(RwLock::new(local_data_dir.as_ref().to_path_buf())), + } + } + pub fn read>(&self, path: P) -> Result, Error> { let local_data_dir = self.local_data_dir.read().unwrap(); let file_path = local_data_dir.join(path); diff --git a/gitbutler-app/src/users/controller.rs b/gitbutler-app/src/users/controller.rs index f99108d85..67219888e 100644 --- a/gitbutler-app/src/users/controller.rs +++ b/gitbutler-app/src/users/controller.rs @@ -1,9 +1,5 @@ -use std::path; - use anyhow::Context; -use tauri::AppHandle; - -use crate::storage; +use tauri::{AppHandle, Manager}; use super::{storage::Storage, User}; @@ -12,31 +8,25 @@ pub struct Controller { storage: Storage, } -impl From<&path::PathBuf> for Controller { - fn from(value: &path::PathBuf) -> Self { - Self { - storage: Storage::from(value), - } - } -} +impl TryFrom<&AppHandle> for Controller { + type Error = anyhow::Error; -impl From<&storage::Storage> for Controller { - fn from(storage: &storage::Storage) -> Self { - Self { - storage: Storage::from(storage), - } - } -} - -impl From<&AppHandle> for Controller { - fn from(app: &AppHandle) -> Self { - Self { - storage: Storage::from(app), + fn try_from(value: &AppHandle) -> Result { + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else { + let controller = Controller::new(Storage::try_from(value)?); + value.manage(controller.clone()); + Ok(controller) } } } impl Controller { + fn new(storage: Storage) -> Controller { + Controller { storage } + } + pub fn get_user(&self) -> Result, GetError> { self.storage .get() diff --git a/gitbutler-app/src/users/storage.rs b/gitbutler-app/src/users/storage.rs index a0be9dd12..6a25d0980 100644 --- a/gitbutler-app/src/users/storage.rs +++ b/gitbutler-app/src/users/storage.rs @@ -1,5 +1,3 @@ -use std::path; - use anyhow::Result; use tauri::{AppHandle, Manager}; @@ -20,27 +18,25 @@ pub enum Error { Json(#[from] serde_json::Error), } -impl From<&storage::Storage> for Storage { - fn from(storage: &storage::Storage) -> Self { - Self { - storage: storage.clone(), +impl TryFrom<&AppHandle> for Storage { + type Error = anyhow::Error; + + fn try_from(value: &AppHandle) -> Result { + if let Some(storage) = value.try_state::() { + Ok(storage.inner().clone()) + } else { + let storage = Storage::new(storage::Storage::try_from(value)?); + value.manage(storage.clone()); + Ok(storage) } } } -impl From<&AppHandle> for Storage { - fn from(value: &AppHandle) -> Self { - Self::from(value.state::().inner()) - } -} - -impl From<&path::PathBuf> for Storage { - fn from(value: &path::PathBuf) -> Self { - Self::from(&storage::Storage::from(value)) - } -} - impl Storage { + fn new(storage: storage::Storage) -> Storage { + Storage { storage } + } + pub fn get(&self) -> Result, Error> { match self.storage.read(USER_FILE)? { Some(data) => Ok(Some(serde_json::from_str(&data)?)), diff --git a/gitbutler-app/src/virtual_branches/controller.rs b/gitbutler-app/src/virtual_branches/controller.rs index f923569c3..07c31afcd 100644 --- a/gitbutler-app/src/virtual_branches/controller.rs +++ b/gitbutler-app/src/virtual_branches/controller.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, path, sync::Arc}; use anyhow::Context; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Semaphore; use crate::{ @@ -35,36 +35,38 @@ impl TryFrom<&AppHandle> for Controller { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let data_dir = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self::new( - &data_dir, - &projects::Controller::from(&data_dir), - &users::Controller::from(&data_dir), - &keys::Controller::from(&data_dir), - &git::credentials::Helper::from(&data_dir), - )) + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + Ok(Self::new( + app_data_dir, + projects::Controller::try_from(value)?, + users::Controller::try_from(value)?, + keys::Controller::try_from(value)?, + git::credentials::Helper::try_from(value)?, + )) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Controller { pub fn new( - data_dir: &path::Path, - projects: &projects::Controller, - users: &users::Controller, - keys: &keys::Controller, - helper: &git::credentials::Helper, + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + keys: keys::Controller, + helper: git::credentials::Helper, ) -> Self { Self { by_project_id: Arc::new(tokio::sync::Mutex::new(HashMap::new())), - local_data_dir: data_dir.to_path_buf(), - projects: projects.clone(), - users: users.clone(), - keys: keys.clone(), - helper: helper.clone(), + local_data_dir, + projects, + users, + keys, + helper, } } @@ -385,18 +387,6 @@ where Other(#[from] anyhow::Error), } -impl From<&path::PathBuf> for ControllerInner { - fn from(value: &path::PathBuf) -> Self { - Self::new( - value, - &projects::Controller::from(value), - &users::Controller::from(value), - &keys::Controller::from(value), - &git::credentials::Helper::from(value), - ) - } -} - impl ControllerInner { pub fn new( data_dir: &path::Path, diff --git a/gitbutler-app/src/watcher.rs b/gitbutler-app/src/watcher.rs index 86690cb2d..7728f2914 100644 --- a/gitbutler-app/src/watcher.rs +++ b/gitbutler-app/src/watcher.rs @@ -7,7 +7,7 @@ use std::{collections::HashMap, path, sync::Arc, time}; pub use events::Event; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::{ sync::{ mpsc::{unbounded_channel, UnboundedSender}, @@ -28,15 +28,25 @@ pub struct Watchers { impl TryFrom<&AppHandle> for Watchers { type Error = anyhow::Error; - fn try_from(value: &AppHandle) -> std::result::Result { - Ok(Self { - app_handle: value.clone(), - watchers: Arc::new(Mutex::new(HashMap::new())), - }) + fn try_from(value: &AppHandle) -> Result { + if let Some(watchers) = value.try_state::() { + Ok(watchers.inner().clone()) + } else { + let watchers = Watchers::new(value.clone()); + value.manage(watchers.clone()); + Ok(watchers) + } } } impl Watchers { + fn new(app_handle: AppHandle) -> Self { + Self { + app_handle, + watchers: Arc::new(Mutex::new(HashMap::new())), + } + } + pub fn watch(&self, project: &projects::Project) -> Result<()> { let watcher = Watcher::try_from(&self.app_handle)?; diff --git a/gitbutler-app/src/watcher/handlers.rs b/gitbutler-app/src/watcher/handlers.rs index 219de8798..a72cbae46 100644 --- a/gitbutler-app/src/watcher/handlers.rs +++ b/gitbutler-app/src/watcher/handlers.rs @@ -13,7 +13,7 @@ mod tick_handler; use std::time; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tracing::instrument; use crate::events as app_events; @@ -41,26 +41,60 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - Ok(Self { - events_sender: app_events::Sender::from(value), - tick_handler: tick_handler::Handler::try_from(value)?, - git_file_change_handler: git_file_change::Handler::try_from(value)?, - index_handler: index_handler::Handler::try_from(value)?, - flush_session_handler: flush_session::Handler::try_from(value)?, - push_gitbutler_handler: push_gitbutler_data::Handler::try_from(value)?, - fetch_project_handler: fetch_project_data::Handler::try_from(value)?, - fetch_gitbutler_handler: fetch_gitbutler_data::Handler::try_from(value)?, - analytics_handler: analytics_handler::Handler::from(value), - push_project_to_gitbutler: push_project_to_gitbutler::Handler::try_from(value)?, - calculate_vbranches_handler: caltulate_virtual_branches_handler::Handler::try_from( - value, - )?, - calculate_deltas_handler: calculate_deltas_handler::Handler::try_from(value)?, - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else { + let handler = Handler::new( + git_file_change::Handler::try_from(value)?, + tick_handler::Handler::try_from(value)?, + flush_session::Handler::try_from(value)?, + fetch_project_data::Handler::try_from(value)?, + fetch_gitbutler_data::Handler::try_from(value)?, + push_gitbutler_data::Handler::try_from(value)?, + analytics_handler::Handler::try_from(value)?, + index_handler::Handler::try_from(value)?, + push_project_to_gitbutler::Handler::try_from(value)?, + caltulate_virtual_branches_handler::Handler::try_from(value)?, + calculate_deltas_handler::Handler::try_from(value)?, + app_events::Sender::try_from(value)?, + ); + value.manage(handler.clone()); + Ok(handler) + } } } impl Handler { + fn new( + git_file_change_handler: git_file_change::Handler, + tick_handler: tick_handler::Handler, + flush_session_handler: flush_session::Handler, + fetch_project_handler: fetch_project_data::Handler, + fetch_gitbutler_handler: fetch_gitbutler_data::Handler, + push_gitbutler_handler: push_gitbutler_data::Handler, + analytics_handler: analytics_handler::Handler, + index_handler: index_handler::Handler, + push_project_to_gitbutler: push_project_to_gitbutler::Handler, + calculate_vbranches_handler: caltulate_virtual_branches_handler::Handler, + calculate_deltas_handler: calculate_deltas_handler::Handler, + events_sender: app_events::Sender, + ) -> Self { + Self { + git_file_change_handler, + tick_handler, + flush_session_handler, + fetch_project_handler, + fetch_gitbutler_handler, + push_gitbutler_handler, + analytics_handler, + index_handler, + push_project_to_gitbutler, + calculate_vbranches_handler, + calculate_deltas_handler, + events_sender, + } + } + #[instrument(skip(self), fields(event = %event), level = "debug")] pub async fn handle( &self, diff --git a/gitbutler-app/src/watcher/handlers/analytics_handler.rs b/gitbutler-app/src/watcher/handlers/analytics_handler.rs index c49a60259..5f29e9b95 100644 --- a/gitbutler-app/src/watcher/handlers/analytics_handler.rs +++ b/gitbutler-app/src/watcher/handlers/analytics_handler.rs @@ -11,22 +11,31 @@ pub struct Handler { client: analytics::Client, } -impl From<&AppHandle> for Handler { - fn from(value: &AppHandle) -> Self { - let client = value - .try_state::() - .map_or(analytics::Client::default(), |client| { - client.inner().clone() - }); +impl TryFrom<&AppHandle> for Handler { + type Error = anyhow::Error; - Self { - client, - users: users::Controller::from(value), + fn try_from(value: &AppHandle) -> Result { + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else { + let client = value + .try_state::() + .map_or(analytics::Client::default(), |client| { + client.inner().clone() + }); + let users = users::Controller::try_from(value)?; + let handler = Handler::new(users, client); + value.manage(handler.clone()); + Ok(handler) } } } impl Handler { + fn new(users: users::Controller, client: analytics::Client) -> Handler { + Handler { users, client } + } + pub async fn handle(&self, event: &analytics::Event) -> Result> { if let Some(user) = self.users.get_user().context("failed to get user")? { self.client.send(&user, event).await; diff --git a/gitbutler-app/src/watcher/handlers/calculate_deltas_handler.rs b/gitbutler-app/src/watcher/handlers/calculate_deltas_handler.rs index 597b67e09..4e0e87586 100644 --- a/gitbutler-app/src/watcher/handlers/calculate_deltas_handler.rs +++ b/gitbutler-app/src/watcher/handlers/calculate_deltas_handler.rs @@ -1,7 +1,7 @@ use std::{path, vec}; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{ deltas, gb_repository, project_repository, @@ -18,33 +18,39 @@ pub struct Handler { users: users::Controller, } -impl From<&path::PathBuf> for Handler { - fn from(value: &path::PathBuf) -> Self { - Self { - local_data_dir: value.clone(), - projects: projects::Controller::from(value), - users: users::Controller::from(value), - } - } -} - impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let handler = Self::new( + app_data_dir, + projects::Controller::try_from(value)?, + users::Controller::try_from(value)?, + ); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + ) -> Self { + Self { + local_data_dir, + projects, + users, + } + } + // Returns Some(file_content) or None if the file is ignored. fn get_current_file( project_repository: &project_repository::Repository, diff --git a/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs b/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs index a7cb9a626..8052ba3a8 100644 --- a/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs +++ b/gitbutler-app/src/watcher/handlers/caltulate_virtual_branches_handler.rs @@ -19,23 +19,36 @@ use super::events; #[derive(Clone)] pub struct Handler { - inner: Arc>, + inner: Arc>, limit: Arc>, } impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; + fn try_from(value: &AppHandle) -> std::result::Result { - let inner = HandlerInner::try_from(value)?; - let quota = Quota::with_period(Duration::from_millis(100)).expect("valid quota"); - Ok(Self { - inner: Arc::new(Mutex::new(inner)), - limit: Arc::new(RateLimiter::direct(quota)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else { + let vbranches = virtual_branches::Controller::try_from(value)?; + let proxy = assets::Proxy::try_from(value)?; + let inner = InnerHandler::new(vbranches, proxy); + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } } } impl Handler { + fn new(inner: InnerHandler) -> Self { + let quota = Quota::with_period(Duration::from_millis(100)).expect("valid quota"); + Self { + inner: Arc::new(Mutex::new(inner)), + limit: Arc::new(RateLimiter::direct(quota)), + } + } + pub async fn handle(&self, project_id: &ProjectId) -> Result> { if self.limit.check().is_err() { Ok(vec![]) @@ -47,25 +60,19 @@ impl Handler { } } -struct HandlerInner { +struct InnerHandler { vbranch_controller: virtual_branches::Controller, assets_proxy: assets::Proxy, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - fn try_from(value: &AppHandle) -> std::result::Result { - Ok(Self { - vbranch_controller: value - .state::() - .inner() - .clone(), - assets_proxy: value.state::().inner().clone(), - }) +impl InnerHandler { + fn new(vbranch_controller: virtual_branches::Controller, assets_proxy: assets::Proxy) -> Self { + Self { + vbranch_controller, + assets_proxy, + } } -} -impl HandlerInner { pub async fn handle(&self, project_id: &ProjectId) -> Result> { match self .vbranch_controller diff --git a/gitbutler-app/src/watcher/handlers/fetch_gitbutler_data.rs b/gitbutler-app/src/watcher/handlers/fetch_gitbutler_data.rs index 75ea60cca..b0c4fc573 100644 --- a/gitbutler-app/src/watcher/handlers/fetch_gitbutler_data.rs +++ b/gitbutler-app/src/watcher/handlers/fetch_gitbutler_data.rs @@ -1,7 +1,7 @@ use std::{path, sync::Arc, time}; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Mutex; use crate::{gb_repository, project_repository, projects, projects::ProjectId, users}; @@ -10,21 +10,35 @@ use super::events; #[derive(Clone)] pub struct Handler { - inner: Arc>, + inner: Arc>, } impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let inner = HandlerInner::try_from(value)?; - Ok(Self { - inner: Arc::new(Mutex::new(inner)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let inner = InnerHandler::new(app_data_dir, projects, users); + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new(inner: InnerHandler) -> Self { + Self { + inner: Arc::new(Mutex::new(inner)), + } + } + pub async fn handle( &self, project_id: &ProjectId, @@ -38,29 +52,25 @@ impl Handler { } } -struct HandlerInner { +struct InnerHandler { local_data_dir: path::PathBuf, projects: projects::Controller, users: users::Controller, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - - fn try_from(value: &AppHandle) -> std::result::Result { - let local_data_dir = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { +impl InnerHandler { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + ) -> Self { + Self { local_data_dir, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) + projects, + users, + } } -} -impl HandlerInner { pub async fn handle( &self, project_id: &ProjectId, @@ -189,7 +199,7 @@ mod test { }) .await?; - let listener = HandlerInner { + let listener = InnerHandler { local_data_dir: suite.local_app_data, projects: suite.projects, users: suite.users, @@ -208,7 +218,7 @@ mod test { let suite = Suite::default(); let Case { project, .. } = suite.new_case(); - let listener = HandlerInner { + let listener = InnerHandler { local_data_dir: suite.local_app_data, projects: suite.projects, users: suite.users, diff --git a/gitbutler-app/src/watcher/handlers/fetch_project_data.rs b/gitbutler-app/src/watcher/handlers/fetch_project_data.rs index c578d0835..993747c4c 100644 --- a/gitbutler-app/src/watcher/handlers/fetch_project_data.rs +++ b/gitbutler-app/src/watcher/handlers/fetch_project_data.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Mutex; use crate::{ @@ -19,14 +19,25 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let inner = HandlerInner::try_from(value)?; - Ok(Self { - inner: Arc::new(Mutex::new(inner)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else { + let vbranches = virtual_branches::Controller::try_from(value)?; + let inner = HandlerInner::new(vbranches); + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } } } impl Handler { + fn new(inner: HandlerInner) -> Handler { + Handler { + inner: Arc::new(Mutex::new(inner)), + } + } + pub async fn handle(&self, project_id: &ProjectId) -> Result> { if let Ok(inner) = self.inner.try_lock() { inner.handle(project_id).await @@ -40,17 +51,11 @@ struct HandlerInner { vbranches: virtual_branches::Controller, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - - fn try_from(value: &AppHandle) -> std::result::Result { - Ok(Self { - vbranches: virtual_branches::Controller::try_from(value)?, - }) - } -} - impl HandlerInner { + fn new(vbranches: virtual_branches::Controller) -> HandlerInner { + HandlerInner { vbranches } + } + pub async fn handle(&self, project_id: &ProjectId) -> Result> { match self.vbranches.fetch_from_target(project_id).await { Ok(_) diff --git a/gitbutler-app/src/watcher/handlers/flush_session.rs b/gitbutler-app/src/watcher/handlers/flush_session.rs index d3a63bf9c..08c3fe88e 100644 --- a/gitbutler-app/src/watcher/handlers/flush_session.rs +++ b/gitbutler-app/src/watcher/handlers/flush_session.rs @@ -1,7 +1,7 @@ use std::{path, sync::Arc}; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Mutex; use crate::{gb_repository, project_repository, projects, projects::ProjectId, sessions, users}; @@ -17,14 +17,29 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let inner = HandlerInner::try_from(value)?; - Ok(Self { - inner: Arc::new(Mutex::new(inner)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let inner = HandlerInner::new(app_data_dir, projects, users); + + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new(inner: HandlerInner) -> Handler { + Handler { + inner: Arc::new(Mutex::new(inner)), + } + } + pub fn handle( &self, project_id: &ProjectId, @@ -44,23 +59,19 @@ struct HandlerInner { users: users::Controller, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - - fn try_from(value: &AppHandle) -> std::result::Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - project_store: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) - } -} - impl HandlerInner { + fn new( + local_data_dir: path::PathBuf, + project_store: projects::Controller, + users: users::Controller, + ) -> HandlerInner { + HandlerInner { + local_data_dir, + project_store, + users, + } + } + pub fn handle( &self, project_id: &ProjectId, diff --git a/gitbutler-app/src/watcher/handlers/git_file_change.rs b/gitbutler-app/src/watcher/handlers/git_file_change.rs index 9484cf3e6..09e9a0538 100644 --- a/gitbutler-app/src/watcher/handlers/git_file_change.rs +++ b/gitbutler-app/src/watcher/handlers/git_file_change.rs @@ -1,7 +1,7 @@ use std::path; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{ analytics, events as app_events, gb_repository, project_repository, @@ -22,19 +22,33 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let handler = Handler::new(app_data_dir, projects, users); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + ) -> Self { + Self { + local_data_dir, + projects, + users, + } + } + pub fn handle>( &self, path: P, diff --git a/gitbutler-app/src/watcher/handlers/index_handler.rs b/gitbutler-app/src/watcher/handlers/index_handler.rs index 94054b44f..532d10835 100644 --- a/gitbutler-app/src/watcher/handlers/index_handler.rs +++ b/gitbutler-app/src/watcher/handlers/index_handler.rs @@ -1,7 +1,7 @@ use std::path; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{ deltas, events as app_events, gb_repository, project_repository, @@ -25,21 +25,45 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - sessions_database: sessions::Database::from(value), - deltas_database: deltas::Database::from(value), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let sessions_database = sessions::Database::try_from(value)?; + let deltas_database = deltas::Database::try_from(value)?; + let handler = Handler::new( + app_data_dir, + projects, + users, + sessions_database, + deltas_database, + ); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + sessions_database: sessions::Database, + deltas_database: deltas::Database, + ) -> Handler { + Handler { + local_data_dir, + projects, + users, + sessions_database, + deltas_database, + } + } + pub fn index_deltas( &self, project_id: &ProjectId, diff --git a/gitbutler-app/src/watcher/handlers/push_gitbutler_data.rs b/gitbutler-app/src/watcher/handlers/push_gitbutler_data.rs index 5d6913c32..7ea7dc10c 100644 --- a/gitbutler-app/src/watcher/handlers/push_gitbutler_data.rs +++ b/gitbutler-app/src/watcher/handlers/push_gitbutler_data.rs @@ -2,7 +2,7 @@ use std::path; use std::sync::{Arc, Mutex, TryLockError}; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::gb_repository::RemoteError; use crate::projects::ProjectId; @@ -19,13 +19,28 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - Ok(Self { - inner: Arc::new(Mutex::new(HandlerInner::try_from(value)?)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let inner = HandlerInner::new(app_data_dir, projects, users); + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new(inner: HandlerInner) -> Self { + Self { + inner: Arc::new(Mutex::new(inner)), + } + } + pub fn handle(&self, project_id: &ProjectId) -> Result> { match self.inner.try_lock() { Ok(inner) => inner.handle(project_id), @@ -41,22 +56,6 @@ struct HandlerInner { users: users::Controller, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - - fn try_from(value: &AppHandle) -> std::result::Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self::new( - path, - projects::Controller::try_from(value)?, - users::Controller::from(value), - )) - } -} - impl HandlerInner { fn new( local_data_dir: path::PathBuf, diff --git a/gitbutler-app/src/watcher/handlers/push_project_to_gitbutler.rs b/gitbutler-app/src/watcher/handlers/push_project_to_gitbutler.rs index bb134f769..3aafd6f8d 100644 --- a/gitbutler-app/src/watcher/handlers/push_project_to_gitbutler.rs +++ b/gitbutler-app/src/watcher/handlers/push_project_to_gitbutler.rs @@ -2,7 +2,7 @@ use std::{path, sync::Arc, time}; use anyhow::{Context, Result}; use itertools::Itertools; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use tokio::sync::Mutex; use crate::{ @@ -24,14 +24,28 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let inner = HandlerInner::try_from(value)?; - Ok(Self { - inner: Arc::new(Mutex::new(inner)), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let projects = projects::Controller::try_from(value)?; + let users = users::Controller::try_from(value)?; + let inner = HandlerInner::new(app_data_dir, projects, users); + let handler = Handler::new(inner); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } impl Handler { + fn new(inner: HandlerInner) -> Self { + Self { + inner: Arc::new(Mutex::new(inner)), + } + } + pub async fn handle(&self, project_id: &ProjectId) -> Result> { if let Ok(inner) = self.inner.try_lock() { inner.handle(project_id).await @@ -48,24 +62,20 @@ pub struct HandlerInner { batch_size: usize, } -impl TryFrom<&AppHandle> for HandlerInner { - type Error = anyhow::Error; - - fn try_from(value: &AppHandle) -> std::result::Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - batch_size: 1000, - local_data_dir: path, - project_store: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) - } -} - impl HandlerInner { + fn new( + local_data_dir: path::PathBuf, + project_store: projects::Controller, + users: users::Controller, + ) -> Self { + Self { + local_data_dir, + project_store, + users, + batch_size: 1000, + } + } + pub async fn handle(&self, project_id: &ProjectId) -> Result> { let project = self .project_store diff --git a/gitbutler-app/src/watcher/handlers/tick_handler.rs b/gitbutler-app/src/watcher/handlers/tick_handler.rs index 391b259df..1dccb3478 100644 --- a/gitbutler-app/src/watcher/handlers/tick_handler.rs +++ b/gitbutler-app/src/watcher/handlers/tick_handler.rs @@ -1,7 +1,7 @@ use std::{path, time}; use anyhow::{Context, Result}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::{ gb_repository, project_repository, @@ -22,15 +22,19 @@ impl TryFrom<&AppHandle> for Handler { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> std::result::Result { - let path = value - .path_resolver() - .app_data_dir() - .context("failed to get app data dir")?; - Ok(Self { - local_data_dir: path, - projects: projects::Controller::try_from(value)?, - users: users::Controller::from(value), - }) + if let Some(handler) = value.try_state::() { + Ok(handler.inner().clone()) + } else if let Some(app_data_dir) = value.path_resolver().app_data_dir() { + let handler = Handler::new( + app_data_dir, + projects::Controller::try_from(value)?, + users::Controller::try_from(value)?, + ); + value.manage(handler.clone()); + Ok(handler) + } else { + Err(anyhow::anyhow!("failed to get app data dir")) + } } } @@ -39,6 +43,18 @@ const PROJECT_FETCH_INTERVAL: time::Duration = time::Duration::new(15 * 60, 0); const PROJECT_PUSH_INTERVAL: time::Duration = time::Duration::new(15 * 60, 0); impl Handler { + fn new( + local_data_dir: path::PathBuf, + projects: projects::Controller, + users: users::Controller, + ) -> Self { + Self { + local_data_dir, + projects, + users, + } + } + pub fn handle( &self, project_id: &ProjectId, diff --git a/gitbutler-app/src/zip.rs b/gitbutler-app/src/zip.rs index c505d3ff5..49f616fa2 100644 --- a/gitbutler-app/src/zip.rs +++ b/gitbutler-app/src/zip.rs @@ -10,37 +10,39 @@ use std::{ use anyhow::{Context, Result}; use sha2::{Digest, Sha256}; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use walkdir::{DirEntry, WalkDir}; use zip::{result::ZipError, write, CompressionMethod, ZipWriter}; +#[derive(Clone)] pub struct Zipper { cache: path::PathBuf, } -impl From<&path::PathBuf> for Zipper { - fn from(value: &path::PathBuf) -> Self { - Self { - cache: value.clone(), - } - } -} - impl TryFrom<&AppHandle> for Zipper { type Error = anyhow::Error; fn try_from(handle: &AppHandle) -> Result { - let cache_dir = handle - .path_resolver() - .app_cache_dir() - .context("failed to get cache dir")?; - fs::create_dir_all(&cache_dir).context("failed to create cache dir")?; - let cache = cache_dir.join("archives"); - Ok(Self::from(&cache)) + if let Some(zipper) = handle.try_state::() { + Ok(zipper.inner().clone()) + } else { + let app_cache_dir = handle + .path_resolver() + .app_cache_dir() + .context("failed to get app cache dir")?; + Self::new(app_cache_dir) + } } } impl Zipper { + fn new>(cache_dir: P) -> Result { + let cache_dir = cache_dir.as_ref().to_path_buf(); + fs::create_dir_all(&cache_dir).context("failed to create cache dir")?; + let cache = cache_dir.join("archives"); + Ok(Self { cache }) + } + // takes a path to create zip of, returns path of a created archive. pub fn zip>(&self, path: P) -> Result { let path = path.as_ref(); diff --git a/gitbutler-app/src/zip/controller.rs b/gitbutler-app/src/zip/controller.rs index fa0cf5193..e255e8455 100644 --- a/gitbutler-app/src/zip/controller.rs +++ b/gitbutler-app/src/zip/controller.rs @@ -1,11 +1,12 @@ use std::path; -use tauri::AppHandle; +use tauri::{AppHandle, Manager}; use crate::projects::{self, ProjectId}; use super::Zipper; +#[derive(Clone)] pub struct Controller { local_data_dir: path::PathBuf, logs_dir: path::PathBuf, @@ -17,24 +18,41 @@ impl TryFrom<&AppHandle> for Controller { type Error = anyhow::Error; fn try_from(value: &AppHandle) -> Result { - let local_data_dir = value - .path_resolver() - .app_data_dir() - .ok_or_else(|| anyhow::anyhow!("failed to get local data dir"))?; - let logs_dir = value - .path_resolver() - .app_log_dir() - .ok_or_else(|| anyhow::anyhow!("failed to get logs dir"))?; - Ok(Self { - local_data_dir, - logs_dir, - zipper: Zipper::try_from(value)?, - projects_controller: projects::Controller::try_from(value)?, - }) + if let Some(controller) = value.try_state::() { + Ok(controller.inner().clone()) + } else { + let local_data_dir = value + .path_resolver() + .app_data_dir() + .ok_or_else(|| anyhow::anyhow!("failed to get local data dir"))?; + let logs_dir = value + .path_resolver() + .app_log_dir() + .ok_or_else(|| anyhow::anyhow!("failed to get logs dir"))?; + let zipper = Zipper::try_from(value)?; + let projects = projects::Controller::try_from(value)?; + let controller = Controller::new(local_data_dir, logs_dir, zipper, projects); + value.manage(controller.clone()); + Ok(controller) + } } } impl Controller { + fn new( + local_data_dir: path::PathBuf, + logs_dir: path::PathBuf, + zipper: Zipper, + projects_controller: projects::Controller, + ) -> Self { + Self { + local_data_dir, + logs_dir, + zipper, + projects_controller, + } + } + pub fn archive(&self, project_id: &ProjectId) -> Result { let project = self.projects_controller.get(project_id)?; self.zipper.zip(project.path).map_err(Into::into)