/ src / profile.rs
profile.rs
  1  mod bookmark;
  2  mod database;
  3  mod history;
  4  mod identity;
  5  mod proxy;
  6  mod search;
  7  mod tofu;
  8  
  9  use anyhow::Result;
 10  use bookmark::Bookmark;
 11  use database::Database;
 12  use gtk::glib::{DateTime, user_config_dir};
 13  use history::History;
 14  use identity::Identity;
 15  use proxy::Proxy;
 16  use r2d2::Pool;
 17  use r2d2_sqlite::SqliteConnectionManager;
 18  use search::Search;
 19  use sqlite::Transaction;
 20  use std::{fs::create_dir_all, path::PathBuf};
 21  use tofu::Tofu;
 22  
 23  const VENDOR: &str = "YGGverse";
 24  const APP_ID: &str = "Yoda";
 25  const BRANCH: &str = "master";
 26  
 27  const DB_NAME: &str = "database.sqlite3";
 28  
 29  pub struct Profile {
 30      pub bookmark: Bookmark,
 31      pub config_path: PathBuf,
 32      pub database: Database,
 33      pub history: History,
 34      pub identity: Identity,
 35      pub proxy: Proxy,
 36      pub search: Search,
 37      pub tofu: Tofu,
 38  }
 39  
 40  impl Profile {
 41      // Constructors
 42  
 43      pub fn init() -> Result<Self> {
 44          // Init profile path
 45          let mut config_path = user_config_dir();
 46  
 47          config_path.push(VENDOR);
 48          config_path.push(APP_ID);
 49          config_path.push(BRANCH);
 50          config_path.push(format!(
 51              "{}.{}",
 52              env!("CARGO_PKG_VERSION_MAJOR"),
 53              env!("CARGO_PKG_VERSION_MINOR")
 54          )); // @TODO remove after auto-migrate feature implementation
 55  
 56          create_dir_all(&config_path)?;
 57  
 58          // Init database path
 59          let mut database_path = config_path.clone();
 60          database_path.push(DB_NAME);
 61  
 62          // Init database connection
 63          let database_pool =
 64              Pool::new(SqliteConnectionManager::file(database_path.as_path())).unwrap();
 65  
 66          // Init profile components
 67          {
 68              // Init writable connection
 69              let mut connection = database_pool.get()?;
 70  
 71              // Init new transaction
 72              let tx = connection.transaction()?;
 73  
 74              // Begin migration
 75              migrate(&tx)?;
 76              tx.commit()?;
 77          } // unlock database
 78  
 79          // Init model
 80          let database = Database::build(&database_pool);
 81  
 82          // Get active profile or create new one
 83          let profile_id = match database.active()? {
 84              Some(profile) => profile.id,
 85              None => database.add(true, DateTime::now_local()?, None)?,
 86          };
 87  
 88          // Init components
 89          let bookmark = Bookmark::build(&database_pool, profile_id)?;
 90          let history = History::build(&database_pool, profile_id)?;
 91          let identity = Identity::build(&database_pool, profile_id)?;
 92          let proxy = Proxy::init(&database_pool, profile_id)?;
 93          let search = Search::build(&database_pool, profile_id)?;
 94          let tofu = Tofu::init(&database_pool, profile_id)?;
 95  
 96          // Result
 97          Ok(Self {
 98              bookmark,
 99              config_path,
100              database,
101              history,
102              identity,
103              proxy,
104              search,
105              tofu,
106          })
107      }
108  
109      // Actions
110  
111      pub fn save(&self) -> Result<()> {
112          self.history.save()?;
113          self.proxy.save()?;
114          self.tofu.save()?;
115          Ok(())
116      }
117  }
118  
119  pub fn migrate(tx: &Transaction) -> Result<()> {
120      // Migrate self components
121      database::init(tx)?;
122  
123      // Delegate migration to children components
124      bookmark::migrate(tx)?;
125      history::migrate(tx)?;
126      identity::migrate(tx)?;
127      proxy::migrate(tx)?;
128      search::migrate(tx)?;
129      tofu::migrate(tx)?;
130  
131      // Success
132      Ok(())
133  }