mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
use r2d2 pool, update rusqlite version
This commit is contained in:
parent
c3f63dfbdc
commit
33369e31ea
17 changed files with 171 additions and 197 deletions
|
|
@ -22,7 +22,7 @@ features = ["gnome_46"]
|
||||||
|
|
||||||
[dependencies.sqlite]
|
[dependencies.sqlite]
|
||||||
package = "rusqlite"
|
package = "rusqlite"
|
||||||
version = "0.32.1"
|
version = "0.34.0"
|
||||||
|
|
||||||
[dependencies.sourceview]
|
[dependencies.sourceview]
|
||||||
package = "sourceview5"
|
package = "sourceview5"
|
||||||
|
|
@ -38,6 +38,8 @@ itertools = "0.14.0"
|
||||||
libspelling = "0.3.0"
|
libspelling = "0.3.0"
|
||||||
openssl = "0.10.70"
|
openssl = "0.10.70"
|
||||||
plurify = "0.2.0"
|
plurify = "0.2.0"
|
||||||
|
r2d2 = "0.8.10"
|
||||||
|
r2d2_sqlite = "0.27.0"
|
||||||
syntect = "5.2.0"
|
syntect = "5.2.0"
|
||||||
|
|
||||||
# development
|
# development
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl App {
|
||||||
let profile = profile.clone();
|
let profile = profile.clone();
|
||||||
move |this| {
|
move |this| {
|
||||||
// Init readable connection
|
// Init readable connection
|
||||||
match profile.database.connection.read() {
|
match profile.database.pool.get() {
|
||||||
Ok(connection) => {
|
Ok(connection) => {
|
||||||
// Create transaction
|
// Create transaction
|
||||||
match connection.unchecked_transaction() {
|
match connection.unchecked_transaction() {
|
||||||
|
|
@ -77,7 +77,7 @@ impl App {
|
||||||
let profile = profile.clone();
|
let profile = profile.clone();
|
||||||
move |_| {
|
move |_| {
|
||||||
match profile.save() {
|
match profile.save() {
|
||||||
Ok(_) => match profile.database.connection.write() {
|
Ok(_) => match profile.database.pool.get() {
|
||||||
Ok(mut connection) => {
|
Ok(mut connection) => {
|
||||||
// Create transaction
|
// Create transaction
|
||||||
match connection.transaction() {
|
match connection.transaction() {
|
||||||
|
|
@ -266,7 +266,7 @@ impl App {
|
||||||
pub fn run(&self) -> Result<ExitCode> {
|
pub fn run(&self) -> Result<ExitCode> {
|
||||||
// Begin database migration @TODO
|
// Begin database migration @TODO
|
||||||
{
|
{
|
||||||
let mut connection = self.profile.database.connection.write().unwrap();
|
let mut connection = self.profile.database.pool.get()?;
|
||||||
let transaction = connection.transaction()?;
|
let transaction = connection.transaction()?;
|
||||||
migrate(&transaction)?;
|
migrate(&transaction)?;
|
||||||
transaction.commit()?;
|
transaction.commit()?;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ impl Save {
|
||||||
button.set_sensitive(false);
|
button.set_sensitive(false);
|
||||||
|
|
||||||
// Create PEM file based on option ID selected
|
// Create PEM file based on option ID selected
|
||||||
match Certificate::new(profile.clone(), profile_identity_id) {
|
match Certificate::build(profile.clone(), profile_identity_id) {
|
||||||
Ok(certificate) => {
|
Ok(certificate) => {
|
||||||
// Init file filters related with PEM extension
|
// Init file filters related with PEM extension
|
||||||
let filters = ListStore::new::<FileFilter>();
|
let filters = ListStore::new::<FileFilter>();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
mod error;
|
use anyhow::{bail, Result};
|
||||||
pub use error::Error;
|
|
||||||
|
|
||||||
use crate::profile::Profile;
|
use crate::profile::Profile;
|
||||||
use gtk::{gio::TlsCertificate, prelude::TlsCertificateExt};
|
use gtk::{gio::TlsCertificate, prelude::TlsCertificateExt};
|
||||||
|
|
@ -15,19 +14,17 @@ impl Certificate {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn new(profile: Rc<Profile>, profile_identity_id: i64) -> Result<Self, Error> {
|
pub fn build(profile: Rc<Profile>, profile_identity_id: i64) -> Result<Self> {
|
||||||
match profile.identity.database.record(profile_identity_id) {
|
let record = profile.identity.database.record(profile_identity_id)?;
|
||||||
Ok(record) => match record {
|
match record {
|
||||||
Some(identity) => match TlsCertificate::from_pem(&identity.pem) {
|
Some(identity) => Ok(Self {
|
||||||
Ok(certificate) => Ok(Self {
|
name: TlsCertificate::from_pem(&identity.pem)?
|
||||||
data: identity.pem,
|
.subject_name()
|
||||||
name: certificate.subject_name().unwrap().replace("CN=", ""),
|
.unwrap_or_default()
|
||||||
}),
|
.replace("CN=", ""),
|
||||||
Err(e) => Err(Error::TlsCertificate(e)),
|
data: identity.pem,
|
||||||
},
|
}),
|
||||||
None => Err(Error::NotFound(profile_identity_id)),
|
None => bail!("Identity not found!"),
|
||||||
},
|
|
||||||
Err(e) => Err(Error::Database(e)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
use gtk::glib;
|
|
||||||
use std::fmt::{Display, Formatter, Result};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
Database(sqlite::Error),
|
|
||||||
NotFound(i64),
|
|
||||||
TlsCertificate(glib::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
|
||||||
match self {
|
|
||||||
Self::Database(e) => {
|
|
||||||
write!(f, "Database error: {e}")
|
|
||||||
}
|
|
||||||
Self::NotFound(profile_identity_id) => {
|
|
||||||
write!(f, "Record for `{profile_identity_id}` not found")
|
|
||||||
}
|
|
||||||
Self::TlsCertificate(e) => {
|
|
||||||
write!(f, "TLS certificate error: {e}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,16 +4,17 @@ mod history;
|
||||||
mod identity;
|
mod identity;
|
||||||
mod search;
|
mod search;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use bookmark::Bookmark;
|
use bookmark::Bookmark;
|
||||||
use database::Database;
|
use database::Database;
|
||||||
|
use gtk::glib::{user_config_dir, DateTime};
|
||||||
use history::History;
|
use history::History;
|
||||||
use identity::Identity;
|
use identity::Identity;
|
||||||
|
use r2d2::Pool;
|
||||||
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
use search::Search;
|
use search::Search;
|
||||||
|
use sqlite::Transaction;
|
||||||
use anyhow::Result;
|
use std::{fs::create_dir_all, path::PathBuf};
|
||||||
use gtk::glib::{user_config_dir, DateTime};
|
|
||||||
use sqlite::{Connection, Transaction};
|
|
||||||
use std::{fs::create_dir_all, path::PathBuf, rc::Rc, sync::RwLock};
|
|
||||||
|
|
||||||
const VENDOR: &str = "YGGverse";
|
const VENDOR: &str = "YGGverse";
|
||||||
const APP_ID: &str = "Yoda";
|
const APP_ID: &str = "Yoda";
|
||||||
|
|
@ -53,23 +54,24 @@ impl Profile {
|
||||||
database_path.push(DB_NAME);
|
database_path.push(DB_NAME);
|
||||||
|
|
||||||
// Init database connection
|
// Init database connection
|
||||||
let connection = Rc::new(RwLock::new(Connection::open(database_path.as_path())?));
|
let database_pool =
|
||||||
|
Pool::new(SqliteConnectionManager::file(database_path.as_path())).unwrap();
|
||||||
|
|
||||||
// Init profile components
|
// Init profile components
|
||||||
{
|
{
|
||||||
// Init writable connection
|
// Init writable connection
|
||||||
let mut connection = connection.write().unwrap(); // @TODO handle
|
let mut connection = database_pool.get()?;
|
||||||
|
|
||||||
// Init new transaction
|
// Init new transaction
|
||||||
let transaction = connection.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
// Begin migration
|
// Begin migration
|
||||||
migrate(&transaction)?;
|
migrate(&tx)?;
|
||||||
transaction.commit()?;
|
tx.commit()?;
|
||||||
} // unlock database
|
} // unlock database
|
||||||
|
|
||||||
// Init model
|
// Init model
|
||||||
let database = Database::build(&connection);
|
let database = Database::build(&database_pool);
|
||||||
|
|
||||||
// Get active profile or create new one
|
// Get active profile or create new one
|
||||||
let profile_id = match database.active()? {
|
let profile_id = match database.active()? {
|
||||||
|
|
@ -78,10 +80,10 @@ impl Profile {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Init components
|
// Init components
|
||||||
let bookmark = Bookmark::build(&connection, profile_id)?;
|
let bookmark = Bookmark::build(&database_pool, profile_id)?;
|
||||||
let history = History::build(&connection, profile_id)?;
|
let history = History::build(&database_pool, profile_id)?;
|
||||||
let search = Search::build(&connection, profile_id)?;
|
let search = Search::build(&database_pool, profile_id)?;
|
||||||
let identity = Identity::build(&connection, profile_id)?;
|
let identity = Identity::build(&database_pool, profile_id)?;
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@ use database::Database;
|
||||||
use gtk::glib::DateTime;
|
use gtk::glib::DateTime;
|
||||||
use item::Item;
|
use item::Item;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
rc::Rc,
|
use sqlite::Transaction;
|
||||||
sync::{Arc, RwLock},
|
use std::sync::{Arc, RwLock};
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Bookmark {
|
pub struct Bookmark {
|
||||||
database: Database, // permanent storage
|
database: Database, // permanent storage
|
||||||
|
|
@ -22,9 +21,9 @@ impl Bookmark {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
|
pub fn build(database_pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
|
||||||
// Init children components
|
// Init children components
|
||||||
let database = Database::new(connection, profile_id);
|
let database = Database::new(database_pool, profile_id);
|
||||||
let memory = Arc::new(RwLock::new(Memory::new()));
|
let memory = Arc::new(RwLock::new(Memory::new()));
|
||||||
|
|
||||||
// Build initial index
|
// Build initial index
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use super::Item;
|
use super::Item;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gtk::glib::DateTime;
|
use gtk::glib::DateTime;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
connection: Rc<RwLock<Connection>>,
|
pool: Pool<SqliteConnectionManager>,
|
||||||
profile_id: i64,
|
profile_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13,9 +14,9 @@ impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn new(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Self {
|
pub fn new(pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
connection: connection.clone(),
|
pool: pool.clone(),
|
||||||
profile_id,
|
profile_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,9 +25,12 @@ impl Database {
|
||||||
|
|
||||||
/// Get bookmark records from database with optional filter by `request`
|
/// Get bookmark records from database with optional filter by `request`
|
||||||
pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result<Vec<Item>> {
|
pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result<Vec<Item>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO
|
select(
|
||||||
let tx = readable.unchecked_transaction()?;
|
&self.pool.get()?.unchecked_transaction()?,
|
||||||
select(&tx, self.profile_id, request, title)
|
self.profile_id,
|
||||||
|
request,
|
||||||
|
title,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
@ -34,8 +38,8 @@ impl Database {
|
||||||
/// Create new bookmark record in database
|
/// Create new bookmark record in database
|
||||||
/// * return last insert ID on success
|
/// * return last insert ID on success
|
||||||
pub fn add(&self, time: DateTime, request: &str, title: Option<&str>) -> Result<i64> {
|
pub fn add(&self, time: DateTime, request: &str, title: Option<&str>) -> Result<i64> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
let id = insert(&tx, self.profile_id, time, request, title)?;
|
let id = insert(&tx, self.profile_id, time, request, title)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(id)
|
Ok(id)
|
||||||
|
|
@ -43,8 +47,8 @@ impl Database {
|
||||||
|
|
||||||
/// Delete bookmark record from database
|
/// Delete bookmark record from database
|
||||||
pub fn delete(&self, id: i64) -> Result<usize> {
|
pub fn delete(&self, id: i64) -> Result<usize> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
let usize = delete(&tx, id)?;
|
let usize = delete(&tx, id)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(usize)
|
Ok(usize)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gtk::glib::DateTime;
|
use gtk::glib::DateTime;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|
@ -11,26 +12,22 @@ pub struct Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
pub connection: Rc<RwLock<Connection>>,
|
pub pool: Pool<SqliteConnectionManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>) -> Self {
|
pub fn build(pool: &Pool<SqliteConnectionManager>) -> Self {
|
||||||
Self {
|
Self { pool: pool.clone() }
|
||||||
connection: connection.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
/// Get all records
|
/// Get all records
|
||||||
pub fn records(&self) -> Result<Vec<Table>> {
|
pub fn records(&self) -> Result<Vec<Table>> {
|
||||||
let readable = self.connection.read().unwrap();
|
select(&self.pool.get()?.unchecked_transaction()?)
|
||||||
let tx = readable.unchecked_transaction()?;
|
|
||||||
select(&tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get active profile record if exist
|
/// Get active profile record if exist
|
||||||
|
|
@ -43,8 +40,8 @@ impl Database {
|
||||||
|
|
||||||
/// Create new record in `Self` database connected
|
/// Create new record in `Self` database connected
|
||||||
pub fn add(&self, is_active: bool, time: DateTime, name: Option<String>) -> Result<i64> {
|
pub fn add(&self, is_active: bool, time: DateTime, name: Option<String>) -> Result<i64> {
|
||||||
let mut writable = self.connection.write().unwrap();
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
if is_active {
|
if is_active {
|
||||||
for record in select(&tx)? {
|
for record in select(&tx)? {
|
||||||
update(&tx, record.id, false, record.time, record.name)?;
|
update(&tx, record.id, false, record.time, record.name)?;
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@ use database::Database;
|
||||||
use gtk::glib::GString;
|
use gtk::glib::GString;
|
||||||
use item::{Event, Item};
|
use item::{Event, Item};
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
rc::Rc,
|
use sqlite::Transaction;
|
||||||
sync::{Arc, RwLock},
|
use std::sync::{Arc, RwLock};
|
||||||
};
|
|
||||||
|
|
||||||
pub struct History {
|
pub struct History {
|
||||||
database: Database, // permanent storage
|
database: Database, // permanent storage
|
||||||
|
|
@ -22,9 +21,9 @@ impl History {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
|
pub fn build(database_pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
|
||||||
// Init children components
|
// Init children components
|
||||||
let database = Database::build(connection, profile_id);
|
let database = Database::build(database_pool, profile_id);
|
||||||
let memory = Arc::new(RwLock::new(Memory::new()));
|
let memory = Arc::new(RwLock::new(Memory::new()));
|
||||||
|
|
||||||
for item in database.records(None, None)? {
|
for item in database.records(None, None)? {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use super::{item::Event, Item};
|
use super::{item::Event, Item};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gtk::glib::DateTime;
|
use gtk::glib::DateTime;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
connection: Rc<RwLock<Connection>>,
|
pool: Pool<SqliteConnectionManager>,
|
||||||
profile_id: i64,
|
profile_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13,9 +14,9 @@ impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Self {
|
pub fn build(pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
connection: connection.clone(),
|
pool: pool.clone(),
|
||||||
profile_id,
|
profile_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -24,9 +25,12 @@ impl Database {
|
||||||
|
|
||||||
/// Get history records from database with optional filter by `request`
|
/// Get history records from database with optional filter by `request`
|
||||||
pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result<Vec<Item>> {
|
pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result<Vec<Item>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO
|
select(
|
||||||
let tx = readable.unchecked_transaction()?;
|
&self.pool.get()?.unchecked_transaction()?,
|
||||||
select(&tx, self.profile_id, request, title)
|
self.profile_id,
|
||||||
|
request,
|
||||||
|
title,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
@ -34,16 +38,16 @@ impl Database {
|
||||||
/// Create new history record in database
|
/// Create new history record in database
|
||||||
/// * return last insert ID on success
|
/// * return last insert ID on success
|
||||||
pub fn add(&self, item: &Item) -> Result<i64> {
|
pub fn add(&self, item: &Item) -> Result<i64> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
let id = insert(&tx, self.profile_id, item)?;
|
let id = insert(&tx, self.profile_id, item)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, item: &Item) -> Result<usize> {
|
pub fn update(&self, item: &Item) -> Result<usize> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
let affected = update(&tx, self.profile_id, item)?;
|
let affected = update(&tx, self.profile_id, item)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(affected)
|
Ok(affected)
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ use database::Database;
|
||||||
use gtk::glib::DateTime;
|
use gtk::glib::DateTime;
|
||||||
use item::Item;
|
use item::Item;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
/// Authorization wrapper for Gemini protocol
|
/// Authorization wrapper for Gemini protocol
|
||||||
///
|
///
|
||||||
|
|
@ -26,10 +27,13 @@ impl Identity {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_identity_id: i64) -> Result<Self> {
|
pub fn build(
|
||||||
|
database_pool: &Pool<SqliteConnectionManager>,
|
||||||
|
profile_identity_id: i64,
|
||||||
|
) -> Result<Self> {
|
||||||
// Init components
|
// Init components
|
||||||
let auth = Auth::build(connection)?;
|
let auth = Auth::build(database_pool)?;
|
||||||
let database = Database::build(connection, profile_identity_id);
|
let database = Database::build(database_pool, profile_identity_id);
|
||||||
let memory = Memory::new();
|
let memory = Memory::new();
|
||||||
|
|
||||||
// Init `Self`
|
// Init `Self`
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,25 @@ mod memory;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use database::Database;
|
use database::Database;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
/// Auth pair operations
|
/// Auth pair operations
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
database: Rc<Database>,
|
database: Database,
|
||||||
memory: Rc<Memory>,
|
memory: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Auth {
|
impl Auth {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>) -> Result<Self> {
|
pub fn build(database_pool: &Pool<SqliteConnectionManager>) -> Result<Self> {
|
||||||
// Init `Self`
|
// Init `Self`
|
||||||
let this = Self {
|
let this = Self {
|
||||||
database: Rc::new(Database::build(connection)),
|
database: Database::build(database_pool),
|
||||||
memory: Rc::new(Memory::new()),
|
memory: Memory::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build initial index
|
// Build initial index
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|
@ -10,25 +11,23 @@ pub struct Table {
|
||||||
|
|
||||||
/// Storage for `profile_identity_id` + `scope` auth pairs
|
/// Storage for `profile_identity_id` + `scope` auth pairs
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
connection: Rc<RwLock<Connection>>,
|
pool: Pool<SqliteConnectionManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>) -> Self {
|
pub fn build(pool: &Pool<SqliteConnectionManager>) -> Self {
|
||||||
Self {
|
Self { pool: pool.clone() }
|
||||||
connection: connection.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
/// Create new record in database
|
/// Create new record in database
|
||||||
pub fn add(&self, profile_identity_id: i64, scope: &str) -> Result<i64> {
|
pub fn add(&self, profile_identity_id: i64, scope: &str) -> Result<i64> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
let id = insert(&tx, profile_identity_id, scope)?;
|
let id = insert(&tx, profile_identity_id, scope)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(id)
|
Ok(id)
|
||||||
|
|
@ -36,8 +35,8 @@ impl Database {
|
||||||
|
|
||||||
/// Delete record with given `id` from database
|
/// Delete record with given `id` from database
|
||||||
pub fn delete(&self, id: i64) -> Result<()> {
|
pub fn delete(&self, id: i64) -> Result<()> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
delete(&tx, id)?;
|
delete(&tx, id)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -47,16 +46,15 @@ impl Database {
|
||||||
|
|
||||||
/// Get records from database match current `profile_id` optionally filtered by `scope`
|
/// Get records from database match current `profile_id` optionally filtered by `scope`
|
||||||
pub fn records_scope(&self, scope: Option<&str>) -> Result<Vec<Table>> {
|
pub fn records_scope(&self, scope: Option<&str>) -> Result<Vec<Table>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO
|
select_scope(&self.pool.get()?.unchecked_transaction()?, scope)
|
||||||
let tx = readable.unchecked_transaction()?;
|
|
||||||
select_scope(&tx, scope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get records from database match current `profile_id` optionally filtered by `scope`
|
/// Get records from database match current `profile_id` optionally filtered by `scope`
|
||||||
pub fn records_ref(&self, profile_identity_id: i64) -> Result<Vec<Table>> {
|
pub fn records_ref(&self, profile_identity_id: i64) -> Result<Vec<Table>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO
|
select_ref(
|
||||||
let tx = readable.unchecked_transaction()?;
|
&self.pool.get()?.unchecked_transaction()?,
|
||||||
select_ref(&tx, profile_identity_id)
|
profile_identity_id,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use sqlite::{Connection, Error, Transaction};
|
use anyhow::Result;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2::Pool;
|
||||||
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
|
@ -9,7 +11,7 @@ pub struct Table {
|
||||||
|
|
||||||
/// Storage for Gemini auth certificates
|
/// Storage for Gemini auth certificates
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
connection: Rc<RwLock<Connection>>,
|
pool: Pool<SqliteConnectionManager>,
|
||||||
profile_id: i64,
|
profile_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,9 +19,9 @@ impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Self {
|
pub fn build(pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
connection: connection.clone(),
|
pool: pool.clone(),
|
||||||
profile_id,
|
profile_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,10 +29,10 @@ impl Database {
|
||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
/// Create new record in database
|
/// Create new record in database
|
||||||
pub fn add(&self, pem: &str) -> Result<i64, Error> {
|
pub fn add(&self, pem: &str) -> Result<i64> {
|
||||||
// Begin new transaction
|
// Begin new transaction
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
// Create new record
|
// Create new record
|
||||||
insert(&tx, self.profile_id, pem)?;
|
insert(&tx, self.profile_id, pem)?;
|
||||||
|
|
@ -39,55 +41,45 @@ impl Database {
|
||||||
let id = last_insert_id(&tx);
|
let id = last_insert_id(&tx);
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
match tx.commit() {
|
tx.commit()?;
|
||||||
Ok(_) => Ok(id),
|
Ok(id)
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete record with given `id` from database
|
/// Delete record with given `id` from database
|
||||||
pub fn delete(&self, id: i64) -> Result<(), Error> {
|
pub fn delete(&self, id: i64) -> Result<()> {
|
||||||
// Begin new transaction
|
// Begin new transaction
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
// Create new record
|
// Create new record
|
||||||
delete(&tx, id)?;
|
delete(&tx, id)?;
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
match tx.commit() {
|
tx.commit()?;
|
||||||
Ok(_) => Ok(()),
|
Ok(())
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get single record match `id`
|
/// Get single record match `id`
|
||||||
pub fn record(&self, id: i64) -> Result<Option<Table>, Error> {
|
pub fn record(&self, id: i64) -> Result<Option<Table>> {
|
||||||
let readable = self.connection.read().unwrap();
|
let records = select(&self.pool.get()?.unchecked_transaction()?, self.profile_id)?; // @TODO single record query
|
||||||
let tx = readable.unchecked_transaction()?;
|
|
||||||
let records = select(&tx, self.profile_id)?; // @TODO single record query
|
|
||||||
|
|
||||||
for record in records {
|
for record in records {
|
||||||
if record.id == id {
|
if record.id == id {
|
||||||
return Ok(Some(record));
|
return Ok(Some(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all records match current `profile_id`
|
/// Get all records match current `profile_id`
|
||||||
pub fn records(&self) -> Result<Vec<Table>, Error> {
|
pub fn records(&self) -> Result<Vec<Table>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO
|
select(&self.pool.get()?.unchecked_transaction()?, self.profile_id)
|
||||||
let tx = readable.unchecked_transaction()?;
|
|
||||||
select(&tx, self.profile_id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low-level DB API
|
// Low-level DB API
|
||||||
|
|
||||||
pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
pub fn init(tx: &Transaction) -> Result<usize> {
|
||||||
tx.execute(
|
Ok(tx.execute(
|
||||||
"CREATE TABLE IF NOT EXISTS `profile_identity`
|
"CREATE TABLE IF NOT EXISTS `profile_identity`
|
||||||
(
|
(
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
|
@ -97,24 +89,24 @@ pub fn init(tx: &Transaction) -> Result<usize, Error> {
|
||||||
FOREIGN KEY (`profile_id`) REFERENCES `profile`(`id`)
|
FOREIGN KEY (`profile_id`) REFERENCES `profile`(`id`)
|
||||||
)",
|
)",
|
||||||
[],
|
[],
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(tx: &Transaction, profile_id: i64, pem: &str) -> Result<usize, Error> {
|
pub fn insert(tx: &Transaction, profile_id: i64, pem: &str) -> Result<usize> {
|
||||||
tx.execute(
|
Ok(tx.execute(
|
||||||
"INSERT INTO `profile_identity` (
|
"INSERT INTO `profile_identity` (
|
||||||
`profile_id`,
|
`profile_id`,
|
||||||
`pem`
|
`pem`
|
||||||
) VALUES (?, ?)",
|
) VALUES (?, ?)",
|
||||||
(profile_id, pem),
|
(profile_id, pem),
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(tx: &Transaction, id: i64) -> Result<usize, Error> {
|
pub fn delete(tx: &Transaction, id: i64) -> Result<usize> {
|
||||||
tx.execute("DELETE FROM `profile_identity` WHERE `id` = ?", [id])
|
Ok(tx.execute("DELETE FROM `profile_identity` WHERE `id` = ?", [id])?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(tx: &Transaction, profile_id: i64) -> Result<Vec<Table>, Error> {
|
pub fn select(tx: &Transaction, profile_id: i64) -> Result<Vec<Table>> {
|
||||||
let mut stmt = tx.prepare(
|
let mut stmt = tx.prepare(
|
||||||
"SELECT `id`,
|
"SELECT `id`,
|
||||||
`profile_id`,
|
`profile_id`,
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ use anyhow::Result;
|
||||||
use database::Database;
|
use database::Database;
|
||||||
use gtk::glib::Uri;
|
use gtk::glib::Uri;
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
pub struct Search {
|
pub struct Search {
|
||||||
database: Database, // permanent storage
|
database: Database, // permanent storage
|
||||||
|
|
@ -17,8 +18,8 @@ impl Search {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn build(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
|
pub fn build(database_pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
|
||||||
let database = Database::init(connection, profile_id)?;
|
let database = Database::init(database_pool, profile_id)?;
|
||||||
// Init fast search index
|
// Init fast search index
|
||||||
let memory = Memory::init();
|
let memory = Memory::init();
|
||||||
// Build initial index
|
// Build initial index
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use sqlite::{Connection, Transaction};
|
use r2d2::Pool;
|
||||||
use std::{rc::Rc, sync::RwLock};
|
use r2d2_sqlite::SqliteConnectionManager;
|
||||||
|
use sqlite::Transaction;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Row {
|
pub struct Row {
|
||||||
|
|
@ -11,7 +12,7 @@ pub struct Row {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
connection: Rc<RwLock<Connection>>,
|
pool: Pool<SqliteConnectionManager>,
|
||||||
profile_id: i64,
|
profile_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,9 +20,9 @@ impl Database {
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/// Create new `Self`
|
/// Create new `Self`
|
||||||
pub fn init(connection: &Rc<RwLock<Connection>>, profile_id: i64) -> Result<Self> {
|
pub fn init(pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
|
||||||
let mut writable = connection.write().unwrap(); // @TODO handle
|
let mut connection = pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
let records = select(&tx, profile_id)?;
|
let records = select(&tx, profile_id)?;
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
connection: connection.clone(),
|
pool: pool.clone(),
|
||||||
profile_id,
|
profile_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -40,9 +41,7 @@ impl Database {
|
||||||
|
|
||||||
/// Get records from database
|
/// Get records from database
|
||||||
pub fn records(&self) -> Result<Vec<Row>> {
|
pub fn records(&self) -> Result<Vec<Row>> {
|
||||||
let readable = self.connection.read().unwrap(); // @TODO handle
|
select(&self.pool.get()?.unchecked_transaction()?, self.profile_id)
|
||||||
let tx = readable.unchecked_transaction()?;
|
|
||||||
select(&tx, self.profile_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
@ -50,8 +49,8 @@ impl Database {
|
||||||
/// Create new record in database
|
/// Create new record in database
|
||||||
/// * return last insert ID on success
|
/// * return last insert ID on success
|
||||||
pub fn add(&self, query: String, is_default: bool) -> Result<i64> {
|
pub fn add(&self, query: String, is_default: bool) -> Result<i64> {
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO handle
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
if is_default {
|
if is_default {
|
||||||
reset(&tx, self.profile_id, !is_default)?;
|
reset(&tx, self.profile_id, !is_default)?;
|
||||||
}
|
}
|
||||||
|
|
@ -63,8 +62,8 @@ impl Database {
|
||||||
/// Delete record from database
|
/// Delete record from database
|
||||||
pub fn delete(&self, id: i64) -> Result<()> {
|
pub fn delete(&self, id: i64) -> Result<()> {
|
||||||
// Begin new transaction
|
// Begin new transaction
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
// Delete record by ID
|
// Delete record by ID
|
||||||
delete(&tx, id)?;
|
delete(&tx, id)?;
|
||||||
|
|
@ -97,8 +96,8 @@ impl Database {
|
||||||
/// Delete record from database
|
/// Delete record from database
|
||||||
pub fn set_default(&self, id: i64) -> Result<()> {
|
pub fn set_default(&self, id: i64) -> Result<()> {
|
||||||
// Begin new transaction
|
// Begin new transaction
|
||||||
let mut writable = self.connection.write().unwrap(); // @TODO
|
let mut connection = self.pool.get()?;
|
||||||
let tx = writable.transaction()?;
|
let tx = connection.transaction()?;
|
||||||
|
|
||||||
// Make sure only one default provider in set
|
// Make sure only one default provider in set
|
||||||
reset(&tx, self.profile_id, false)?;
|
reset(&tx, self.profile_id, false)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue