From 366c5fad8e6749f1c0f029d036b8385ad4706932 Mon Sep 17 00:00:00 2001 From: yggverse Date: Mon, 7 Oct 2024 19:54:28 +0300 Subject: [PATCH] resolve deadlock issue, draft migration features --- src/app.rs | 79 +++++++++++++------- src/app/browser.rs | 63 +++++++--------- src/app/browser/database.rs | 10 ++- src/app/browser/widget.rs | 47 +++++------- src/app/browser/widget/database.rs | 10 ++- src/app/browser/window.rs | 46 +++++------- src/app/browser/window/database.rs | 10 ++- src/app/browser/window/tab.rs | 61 +++++++-------- src/app/browser/window/tab/database.rs | 10 ++- src/app/browser/window/tab/label.rs | 50 +++++-------- src/app/browser/window/tab/label/database.rs | 6 +- src/app/database.rs | 10 ++- 12 files changed, 192 insertions(+), 210 deletions(-) diff --git a/src/app.rs b/src/app.rs index eab2e9ff..d0ee9941 100644 --- a/src/app.rs +++ b/src/app.rs @@ -11,7 +11,7 @@ use gtk::{ prelude::{ActionExt, ApplicationExt, ApplicationExtManual, GtkApplicationExt, GtkWindowExt}, Application, }; -use sqlite::Connection; +use sqlite::{Connection, Transaction}; use std::{ path::PathBuf, @@ -21,12 +21,12 @@ use std::{ const APPLICATION_ID: &str = "io.github.yggverse.Yoda"; pub struct App { + profile_database_connection: Arc>, + // database: Arc, // Actions // action_update: Arc, // Components // browser: Arc, - // Extras - // database: Arc, // GTK gobject: Application, } @@ -38,28 +38,7 @@ impl App { profile_path: PathBuf, ) -> Self { // Init database - let database = { - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } - }; + let database = Arc::new(Database::new()); // Init actions let action_tool_debug = Action::new("win", true); @@ -106,7 +85,6 @@ impl App { // Init components let browser = Arc::new(Browser::new( - profile_database_connection.clone(), profile_path, action_tool_debug.simple(), action_tool_profile_directory.simple(), @@ -170,6 +148,7 @@ impl App { // let browser = browser.clone(); let profile_database_connection = profile_database_connection.clone(); let database = database.clone(); + let browser = browser.clone(); move |_| { // Init writable connection match profile_database_connection.write() { @@ -220,12 +199,12 @@ impl App { // Return activated App struct Self { + // database, + profile_database_connection, // Actions (SimpleAction) // action_update: action_update.simple(), // Components // browser, - // Extras - // database, // GTK gobject, } @@ -233,6 +212,50 @@ impl App { // Actions pub fn run(&self) -> ExitCode { + // Begin database migration @TODO + { + // Init writable connection + let mut connection = match self.profile_database_connection.try_write() { + Ok(connection) => connection, + Err(e) => todo!("{e}"), + }; + + // Init new transaction + let transaction = match connection.transaction() { + Ok(transaction) => transaction, + Err(e) => todo!("{e}"), + }; + + // Begin migration + match App::migrate(&transaction) { + Ok(_) => { + // Confirm changes + match transaction.commit() { + Ok(_) => {} // @TODO + Err(e) => todo!("{e}"), + } + } + Err(e) => todo!("{e}"), + } + } // unlock database + + // Start application self.gobject.run() } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + if let Err(e) = Browser::migrate(&tx) { + return Err(e.to_string()); + } + + // Success + Ok(()) + } } diff --git a/src/app/browser.rs b/src/app/browser.rs index c972bc09..124b463a 100644 --- a/src/app/browser.rs +++ b/src/app/browser.rs @@ -13,11 +13,8 @@ use gtk::{ prelude::{ActionMapExt, GtkWindowExt}, ApplicationWindow, }; -use sqlite::{Connection, Transaction}; -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, -}; +use sqlite::Transaction; +use std::{path::PathBuf, sync::Arc}; pub struct Browser { // Extras @@ -32,7 +29,6 @@ impl Browser { // Construct pub fn new( // Extras - profile_database_connection: Arc>, profile_path: PathBuf, // Actions action_tool_debug: Arc, @@ -49,28 +45,7 @@ impl Browser { action_tab_pin: Arc, ) -> Browser { // Init database - let database = { - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } - }; + let database = Arc::new(Database::new()); // Init components let header = Arc::new(Header::new( @@ -88,7 +63,6 @@ impl Browser { )); let window = Arc::new(Window::new( - profile_database_connection.clone(), action_tab_page_navigation_base.clone(), action_tab_page_navigation_history_back.clone(), action_tab_page_navigation_history_forward.clone(), @@ -97,11 +71,7 @@ impl Browser { )); // Init widget - let widget = Arc::new(Widget::new( - profile_database_connection.clone(), - header.gobject(), - window.gobject(), - )); + let widget = Arc::new(Widget::new(header.gobject(), window.gobject())); // Assign actions widget.gobject().add_action(action_tool_debug.as_ref()); @@ -281,4 +251,29 @@ impl Browser { pub fn gobject(&self) -> &ApplicationWindow { &self.widget.gobject() } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + /* @TODO + if let Err(e) = Header::migrate(&tx) { + return Err(e.to_string()); + } */ + + if let Err(e) = Window::migrate(&tx) { + return Err(e.to_string()); + } + + if let Err(e) = Widget::migrate(&tx) { + return Err(e.to_string()); + } + + // Success + Ok(()) + } } diff --git a/src/app/browser/database.rs b/src/app/browser/database.rs index 2385517e..a20b986a 100644 --- a/src/app/browser/database.rs +++ b/src/app/browser/database.rs @@ -10,7 +10,11 @@ pub struct Database { } impl Database { - pub fn init(tx: &Transaction) -> Result { + pub fn new() -> Self { + Self {} + } + + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app_browser` ( @@ -18,9 +22,7 @@ impl Database { `app_id` INTEGER NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add(&self, tx: &Transaction, app_id: &i64) -> Result { diff --git a/src/app/browser/widget.rs b/src/app/browser/widget.rs index 3e8f6754..059e2ae0 100644 --- a/src/app/browser/widget.rs +++ b/src/app/browser/widget.rs @@ -3,8 +3,8 @@ mod database; use database::Database; use gtk::{prelude::GtkWindowExt, ApplicationWindow, Box, HeaderBar}; -use sqlite::{Connection, Transaction}; -use std::sync::{Arc, RwLock}; +use sqlite::Transaction; +use std::sync::Arc; // Default options const DEFAULT_HEIGHT: i32 = 480; @@ -18,34 +18,9 @@ pub struct Widget { impl Widget { // Construct - pub fn new( - profile_database_connection: Arc>, - titlebar: &HeaderBar, - child: &Box, - ) -> Self { + pub fn new(titlebar: &HeaderBar, child: &Box) -> Self { // Init database - let database = { - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } - }; + let database = Arc::new(Database::new()); // Init GTK let gobject = ApplicationWindow::builder() @@ -116,4 +91,18 @@ impl Widget { pub fn gobject(&self) -> &ApplicationWindow { &self.gobject } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + // nothing yet.. + + // Success + Ok(()) + } } diff --git a/src/app/browser/widget/database.rs b/src/app/browser/widget/database.rs index 69b36e2b..0ed91b4b 100644 --- a/src/app/browser/widget/database.rs +++ b/src/app/browser/widget/database.rs @@ -13,7 +13,11 @@ pub struct Database { } impl Database { - pub fn init(tx: &Transaction) -> Result { + pub fn new() -> Self { + Self {} + } + + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app_browser_widget` ( @@ -24,9 +28,7 @@ impl Database { `is_maximized` INTEGER NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add( diff --git a/src/app/browser/window.rs b/src/app/browser/window.rs index 98843fb1..cf309d93 100644 --- a/src/app/browser/window.rs +++ b/src/app/browser/window.rs @@ -3,11 +3,11 @@ mod tab; mod widget; use database::Database; -use sqlite::{Connection, Transaction}; +use sqlite::Transaction; use tab::Tab; use widget::Widget; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; use gtk::{gio::SimpleAction, glib::GString, Box}; @@ -20,8 +20,6 @@ pub struct Window { impl Window { // Construct pub fn new( - // Extras - profile_database_connection: Arc>, // Actions action_tab_page_navigation_base: Arc, action_tab_page_navigation_history_back: Arc, @@ -30,32 +28,10 @@ impl Window { action_update: Arc, ) -> Self { // Init database - let database = { - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } - }; + let database = Arc::new(Database::new()); // Init components let tab = Arc::new(Tab::new( - profile_database_connection, action_tab_page_navigation_base, action_tab_page_navigation_history_back, action_tab_page_navigation_history_forward, @@ -163,4 +139,20 @@ impl Window { pub fn gobject(&self) -> &Box { &self.widget.gobject() } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + if let Err(e) = Tab::migrate(&tx) { + return Err(e.to_string()); + } + + // Success + Ok(()) + } } diff --git a/src/app/browser/window/database.rs b/src/app/browser/window/database.rs index 141fe6a5..c6d461e1 100644 --- a/src/app/browser/window/database.rs +++ b/src/app/browser/window/database.rs @@ -10,7 +10,11 @@ pub struct Database { } impl Database { - pub fn init(tx: &Transaction) -> Result { + pub fn new() -> Self { + Self {} + } + + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app_browser_window` ( @@ -18,9 +22,7 @@ impl Database { `app_browser_id` INTEGER NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add(&self, tx: &Transaction, app_browser_id: &i64) -> Result { diff --git a/src/app/browser/window/tab.rs b/src/app/browser/window/tab.rs index 1f246f50..20d4f3d5 100644 --- a/src/app/browser/window/tab.rs +++ b/src/app/browser/window/tab.rs @@ -6,7 +6,7 @@ mod widget; use database::Database; use label::Label; use page::Page; -use sqlite::{Connection, Transaction}; +use sqlite::Transaction; use widget::Widget; use gtk::{ @@ -16,11 +16,7 @@ use gtk::{ GestureClick, Notebook, }; -use std::{ - cell::RefCell, - collections::HashMap, - sync::{Arc, RwLock}, -}; +use std::{cell::RefCell, collections::HashMap, sync::Arc}; // Common struct for HashMap index pub struct TabItem { @@ -30,7 +26,6 @@ pub struct TabItem { // Main pub struct Tab { - profile_database_connection: Arc>, database: Arc, // Actions action_tab_page_navigation_base: Arc, @@ -47,7 +42,6 @@ pub struct Tab { impl Tab { // Construct pub fn new( - profile_database_connection: Arc>, // Actions action_tab_page_navigation_base: Arc, action_tab_page_navigation_history_back: Arc, @@ -56,28 +50,7 @@ impl Tab { action_update: Arc, ) -> Self { // Init database - let database = { - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } - }; + let database = Arc::new(Database::new()); // Init empty HashMap index as no tabs appended yet let index = RefCell::new(HashMap::new()); @@ -87,7 +60,6 @@ impl Tab { // Return non activated struct Self { - profile_database_connection, database, // Define action links action_tab_page_navigation_base, @@ -135,11 +107,7 @@ impl Tab { let id = uuid_string_random(); // Init new tab components - let label = Arc::new(Label::new( - self.profile_database_connection.clone(), - id.clone(), - false, - )); + let label = Arc::new(Label::new(id.clone(), false)); let page = Arc::new(Page::new( id.clone(), @@ -335,4 +303,25 @@ impl Tab { pub fn gobject(&self) -> &Notebook { self.widget.gobject() } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + if let Err(e) = Label::migrate(&tx) { + return Err(e.to_string()); + } + + /* @TODO + if let Err(e) = Page::migrate(&tx) { + return Err(e.to_string()); + } */ + + // Success + Ok(()) + } } diff --git a/src/app/browser/window/tab/database.rs b/src/app/browser/window/tab/database.rs index a945ffce..5124a850 100644 --- a/src/app/browser/window/tab/database.rs +++ b/src/app/browser/window/tab/database.rs @@ -11,7 +11,11 @@ pub struct Database { } impl Database { - pub fn init(tx: &Transaction) -> Result { + pub fn new() -> Self { + Self {} + } + + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app_browser_window_tab` ( @@ -20,9 +24,7 @@ impl Database { `is_current` INTEGER NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add( diff --git a/src/app/browser/window/tab/label.rs b/src/app/browser/window/tab/label.rs index 23fb11d2..7506d8a0 100644 --- a/src/app/browser/window/tab/label.rs +++ b/src/app/browser/window/tab/label.rs @@ -5,12 +5,12 @@ mod widget; use database::Database; use pin::Pin; -use sqlite::{Connection, Transaction}; +use sqlite::Transaction; use title::Title; use widget::Widget; use gtk::{glib::GString, Box}; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; pub struct Label { database: Arc, @@ -23,37 +23,9 @@ pub struct Label { impl Label { // Construct - pub fn new( - profile_database_connection: Arc>, - name: GString, - is_pinned: bool, - ) -> Label { + pub fn new(name: GString, is_pinned: bool) -> Label { // Init database - let database = { - /* @TODO init outside - // Init writable database connection - let mut connection = match profile_database_connection.write() { - Ok(connection) => connection, - Err(e) => todo!("{e}"), - }; - - // Init new transaction - let transaction = match connection.transaction() { - Ok(transaction) => transaction, - Err(e) => todo!("{e}"), - }; - - // Init database structure - match Database::init(&transaction) { - Ok(database) => match transaction.commit() { - Ok(_) => Arc::new(database), - Err(e) => todo!("{e}"), - }, - Err(e) => todo!("{e}"), - } */ - - Arc::new(Database::new()) - }; + let database = Arc::new(Database::new()); // Components let pin = Arc::new(Pin::new(is_pinned)); @@ -135,4 +107,18 @@ impl Label { pub fn gobject(&self) -> &Box { &self.widget.gobject() } + + // Tools + pub fn migrate(tx: &Transaction) -> Result<(), String> { + // Migrate self components + if let Err(e) = Database::init(&tx) { + return Err(e.to_string()); + } + + // Delegate migration to childs + // nothing yet.. + + // Success + Ok(()) + } } diff --git a/src/app/browser/window/tab/label/database.rs b/src/app/browser/window/tab/label/database.rs index 57ba4722..7cce0401 100644 --- a/src/app/browser/window/tab/label/database.rs +++ b/src/app/browser/window/tab/label/database.rs @@ -15,7 +15,7 @@ impl Database { Self {} } - pub fn init(tx: &Transaction) -> Result { + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app_browser_window_tab_label` ( @@ -24,9 +24,7 @@ impl Database { `is_pinned` INTEGER NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add( diff --git a/src/app/database.rs b/src/app/database.rs index 170971ab..dd6a0405 100644 --- a/src/app/database.rs +++ b/src/app/database.rs @@ -9,16 +9,18 @@ pub struct Database { } impl Database { - pub fn init(tx: &Transaction) -> Result { + pub fn new() -> Self { + Self {} + } + + pub fn init(tx: &Transaction) -> Result { tx.execute( "CREATE TABLE IF NOT EXISTS `app` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL )", [], - )?; - - Ok(Self {}) + ) } pub fn add(&self, tx: &Transaction) -> Result {