implement backend for the proxy misc configuration

This commit is contained in:
yggverse 2025-07-26 07:50:19 +03:00
parent d48bf91ffa
commit 8df429e98f
6 changed files with 265 additions and 1 deletions

View file

@ -1,9 +1,11 @@
mod ignore;
mod misc;
mod rule;
use anyhow::Result;
use gtk::gio::{ProxyResolver, SimpleProxyResolver};
use ignore::Ignore;
use misc::Misc;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use rule::Rule;
@ -11,6 +13,7 @@ use rule::Rule;
pub struct Proxy {
pub ignore: Ignore,
pub rule: Rule,
pub misc: Misc,
}
impl Proxy {
@ -19,6 +22,7 @@ impl Proxy {
pub fn init(database_pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
Ok(Self {
ignore: Ignore::init(database_pool, profile_id)?,
misc: Misc::init(database_pool, profile_id)?,
rule: Rule::init(database_pool, profile_id)?,
})
}
@ -26,8 +30,9 @@ impl Proxy {
// Actions
pub fn save(&self) -> Result<()> {
self.rule.save()?;
self.ignore.save()?;
self.misc.save()?;
self.rule.save()?;
Ok(())
}
@ -63,6 +68,7 @@ pub fn migrate(tx: &sqlite::Transaction) -> Result<()> {
// Delegate migration to childs
ignore::migrate(tx)?;
misc::migrate(tx)?;
rule::migrate(tx)?;
Ok(())

81
src/profile/proxy/misc.rs Normal file
View file

@ -0,0 +1,81 @@
mod database;
mod memory;
use anyhow::Result;
use database::Database;
use memory::Memory;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use std::{cell::RefCell, collections::HashSet};
pub struct Misc {
database: Database,
memory: RefCell<HashSet<Memory>>,
}
impl Misc {
// Constructors
pub fn init(database_pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Result<Self> {
let database = Database::init(database_pool, profile_id);
let rows = database.rows()?;
let memory = RefCell::new(HashSet::with_capacity(rows.len()));
{
// build in-memory index...
let mut m = memory.borrow_mut();
// create initial preset (populate index with the default values)
assert!(m.insert(Memory::highlight_request_entry(true)));
// update values from the DB (if exists)
for row in rows {
assert!(!m.insert(Memory::from_db_row(&row.key, row.value.as_deref()).unwrap()))
// * panics if the DB was malformed or changed unexpectedly
}
}
Ok(Self { database, memory })
}
// Setters
pub fn save(&self) -> Result<()> {
for k in self.memory.take() {
self.database.set(k.into_db_row())?;
}
Ok(())
}
pub fn set_highlight_request_entry(&self, value: bool) {
assert!(
self.memory
.borrow_mut()
.insert(Memory::highlight_request_entry(value)),
)
}
// Getters
pub fn is_highlight_request_entry(&self) -> bool {
if let Some(k) = self.memory.borrow().iter().next() {
match k {
Memory::HighlightRequestEntry(v) => return v.is_true(),
}
}
false
}
}
// Tools
pub fn migrate(tx: &sqlite::Transaction) -> Result<()> {
// Migrate self components
database::init(tx)?;
// Delegate migration to childs
// nothing yet...
// Success
Ok(())
}

View file

@ -0,0 +1,99 @@
mod row;
use anyhow::Result;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use row::Row;
use sqlite::Transaction;
pub struct Database {
pool: Pool<SqliteConnectionManager>,
profile_id: i64,
}
impl Database {
// Constructors
pub fn init(pool: &Pool<SqliteConnectionManager>, profile_id: i64) -> Self {
Self {
pool: pool.clone(),
profile_id,
}
}
// Getters
pub fn rows(&self) -> Result<Vec<Row>> {
rows(&self.pool.get()?.unchecked_transaction()?, self.profile_id)
}
// Setters
pub fn set(&self, (key, value): (String, String)) -> Result<i64> {
let mut c = self.pool.get()?;
let tx = c.transaction()?;
let id = set(&tx, self.profile_id, key, value)?;
tx.commit()?;
Ok(id)
}
}
// Low-level DB API
pub fn init(tx: &Transaction) -> Result<usize> {
Ok(tx.execute(
"CREATE TABLE IF NOT EXISTS `profile_proxy_misc`
(
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`profile_id` INTEGER NOT NULL,
`key` VARCHAR(255) NOT NULL,
`value` TEXT NULL,
FOREIGN KEY (`profile_id`) REFERENCES `profile` (`id`),
UNIQUE (`key`)
)",
[],
)?)
}
fn set(tx: &Transaction, profile_id: i64, key: String, value: String) -> Result<i64> {
tx.execute(
"INSERT INTO `profile_proxy_misc` (
`profile_id`,
`key`,
`value`
) VALUES (?, ?, ?) ON CONFLICT (`key`) DO UPDATE SET `value` = `excluded`.`value`",
(profile_id, key, value),
)?;
Ok(tx.last_insert_rowid())
}
fn rows(tx: &Transaction, profile_id: i64) -> Result<Vec<Row>> {
let mut stmt = tx.prepare(
"SELECT `id`,
`profile_id`,
`key`,
`value`
FROM `profile_proxy_misc`
WHERE `profile_id` = ?",
)?;
let result = stmt.query_map([profile_id], |row| {
Ok(Row {
//id: row.get(0)?,
//profile_id: row.get(1)?,
key: row.get(2)?,
value: row.get(3)?,
})
})?;
let mut rows = Vec::new();
for r in result {
let row = r?;
rows.push(row);
}
Ok(rows)
}

View file

@ -0,0 +1,6 @@
pub struct Row {
//pub id: i64,
//pub profile_id: i64,
pub key: String,
pub value: Option<String>,
}

View file

@ -0,0 +1,37 @@
mod bool;
use bool::Bool;
// Shared values
const HIGHLIGHT_REQUEST_ENTRY: &str = "highlight_request_entry";
#[derive(Eq, Hash, PartialEq)]
pub enum Memory {
HighlightRequestEntry(Bool),
}
impl Memory {
// Constructors
pub fn from_db_row(key: &str, value: Option<&str>) -> Option<Self> {
if key == HIGHLIGHT_REQUEST_ENTRY {
Some(Self::HighlightRequestEntry(Bool::from_db_value(value)))
} else {
None
}
}
pub fn highlight_request_entry(value: bool) -> Self {
Memory::HighlightRequestEntry(Bool::from(value))
}
// Actions
pub fn into_db_row(self) -> (String, String) {
match self {
Self::HighlightRequestEntry(value) => {
(HIGHLIGHT_REQUEST_ENTRY.to_string(), value.into_db_value())
}
}
}
}

View file

@ -0,0 +1,35 @@
const TRUE: &str = "1";
const FALSE: &str = "0";
#[derive(Eq, Hash, PartialEq, Default)]
pub enum Bool {
True,
#[default]
False,
}
impl Bool {
pub fn from(value: bool) -> Self {
if value { Self::True } else { Self::False }
}
pub fn from_db_value(key: Option<&str>) -> Self {
if key.is_some_and(|k| k == TRUE) {
Self::True
} else {
Self::False
}
}
pub fn into_db_value(self) -> String {
match self {
Self::True => TRUE,
Self::False => FALSE,
}
.to_string()
}
pub fn is_true(&self) -> bool {
matches!(self, Self::True)
}
}