From b15e4a5fc1decd48bbab3339b0d3d23bb121139a Mon Sep 17 00:00:00 2001 From: yggverse Date: Sat, 26 Jul 2025 04:26:20 +0300 Subject: [PATCH] separate children proxy components --- src/app/browser/proxy.rs | 4 +- src/app/browser/proxy/rules.rs | 2 +- src/profile/proxy.rs | 116 +++-------------- src/profile/proxy/ignore.rs | 68 +++++++++- src/profile/proxy/ignore/database.rs | 79 ++++++++++++ .../ignore.rs => ignore/database/row.rs} | 2 +- src/profile/proxy/ignore/memory.rs | 5 + src/profile/proxy/rule.rs | 119 ++++++++++++++++-- src/profile/proxy/{ => rule}/database.rs | 97 +++----------- .../rule.rs => rule/database/row.rs} | 2 +- src/profile/proxy/rule/memory.rs | 9 ++ 11 files changed, 310 insertions(+), 193 deletions(-) create mode 100644 src/profile/proxy/ignore/database.rs rename src/profile/proxy/{database/ignore.rs => ignore/database/row.rs} (71%) create mode 100644 src/profile/proxy/ignore/memory.rs rename src/profile/proxy/{ => rule}/database.rs (64%) rename src/profile/proxy/{database/rule.rs => rule/database/row.rs} (89%) create mode 100644 src/profile/proxy/rule/memory.rs diff --git a/src/app/browser/proxy.rs b/src/app/browser/proxy.rs index 0ed3d6af..afd3753b 100644 --- a/src/app/browser/proxy.rs +++ b/src/app/browser/proxy.rs @@ -60,10 +60,10 @@ impl Proxy for adw::PreferencesDialog { d.connect_closed({ let profile = profile.clone(); move |_| { - profile.proxy.clear(); + profile.proxy.rule.clear(); for rule in rules.take() { if rule.validate() { - profile.proxy.add_rule( + profile.proxy.rule.add( rule.id, rule.is_enabled(), rule.priority(), diff --git a/src/app/browser/proxy/rules.rs b/src/app/browser/proxy/rules.rs index 52d0acd9..d8cbb9ab 100644 --- a/src/app/browser/proxy/rules.rs +++ b/src/app/browser/proxy/rules.rs @@ -17,7 +17,7 @@ pub struct Rules { impl Rules { pub fn build(profile: &Rc) -> Self { - let config = profile.proxy.rules(); + let config = profile.proxy.rule.all(); let rules: Rc>> = Rc::new(RefCell::new(HashMap::with_capacity(config.len()))); diff --git a/src/profile/proxy.rs b/src/profile/proxy.rs index 6ffac347..5feb5e9b 100644 --- a/src/profile/proxy.rs +++ b/src/profile/proxy.rs @@ -1,122 +1,40 @@ -mod database; mod ignore; mod rule; use anyhow::Result; -use database::Database; -use gtk::{ - gio::{ProxyResolver, SimpleProxyResolver}, - glib::DateTime, -}; +use gtk::gio::{ProxyResolver, SimpleProxyResolver}; use ignore::Ignore; use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; use rule::Rule; -use std::cell::RefCell; pub struct Proxy { - database: Database, - ignore: RefCell>, - rule: RefCell>, + pub ignore: Ignore, + pub rule: Rule, } impl Proxy { // Constructors pub fn init(database_pool: &Pool, profile_id: i64) -> Result { - let database = Database::init(database_pool, profile_id); - - let ignores = database.ignores()?; - let ignore = RefCell::new(Vec::with_capacity(ignores.len())); - - { - // build in-memory index... - let mut b = ignore.borrow_mut(); - for i in ignores { - b.push(Ignore { - is_enabled: i.is_enabled, - host: i.host, - }); - } - } - - let rules = database.rules()?; - let rule = RefCell::new(Vec::with_capacity(rules.len())); - - { - // build in-memory index... - let mut b = rule.borrow_mut(); - for r in rules { - b.push(Rule { - id: Some(r.id), - time: r.time, - is_enabled: r.is_enabled, - priority: r.priority, - request: r.request, - url: r.url, - }); - } - } - Ok(Self { - database, - ignore, - rule, + ignore: Ignore::init(database_pool, profile_id)?, + rule: Rule::init(database_pool, profile_id)?, }) } // Actions - pub fn add_rule( - &self, - id: Option, - is_enabled: bool, - priority: i32, - request: String, - url: String, - time: DateTime, - ) { - let mut rules = self.rule.borrow_mut(); - rules.push(Rule { - id, - time, - is_enabled, - priority, - request, - url, - }) // @TODO validate? - } - - pub fn clear(&self) { - self.ignore.borrow_mut().clear(); - self.rule.borrow_mut().clear(); - } - pub fn save(&self) -> Result<()> { - let rules = self.rule.take(); - let mut keep_id = Vec::with_capacity(rules.len()); - for rule in rules { - keep_id.push(self.database.persist_rule( - rule.id, - rule.time, - rule.is_enabled, - rule.priority, - rule.request, - rule.url, - )?); - } - self.database.clean_rules(keep_id)?; + self.rule.save()?; + //self.ignore.save()?; Ok(()) } // Getters - pub fn rules(&self) -> Vec { - self.rule.borrow().iter().cloned().collect() - } - pub fn matches(&self, request: &str) -> Option { - for rule in self.rule.borrow().iter().filter(|r| r.is_enabled) { + for rule in self.rule.enabled() { if gtk::glib::Regex::match_simple( &rule.request, request, @@ -126,15 +44,9 @@ impl Proxy { return Some(SimpleProxyResolver::new( Some(&rule.url), self.ignore - .borrow() - .iter() - .filter_map(|i| { - if i.is_enabled { - Some(i.host.clone()) - } else { - None - } - }) + .enabled() + .into_iter() + .map(|i| i.host) .collect::>(), )); } @@ -147,11 +59,11 @@ impl Proxy { pub fn migrate(tx: &sqlite::Transaction) -> Result<()> { // Migrate self components - database::init(tx)?; + // nothing yet.. // Delegate migration to childs - // nothing yet... + ignore::migrate(tx)?; + rule::migrate(tx)?; - // Success Ok(()) } diff --git a/src/profile/proxy/ignore.rs b/src/profile/proxy/ignore.rs index 91981d89..33d78b85 100644 --- a/src/profile/proxy/ignore.rs +++ b/src/profile/proxy/ignore.rs @@ -1,4 +1,68 @@ +mod database; +mod memory; + +use anyhow::Result; +use database::Database; +use memory::Memory; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use std::cell::RefCell; + pub struct Ignore { - pub is_enabled: bool, - pub host: String, + database: Database, + memory: RefCell>, +} + +impl Ignore { + // Constructors + + pub fn init(database_pool: &Pool, profile_id: i64) -> Result { + let database = Database::init(database_pool, profile_id); + + let rows = database.rows()?; + let memory = RefCell::new(Vec::with_capacity(rows.len())); + + { + // build in-memory index... + let mut m = memory.borrow_mut(); + for i in rows { + m.push(Memory { + is_enabled: i.is_enabled, + host: i.host, + }); + } + } + + Ok(Self { database, memory }) + } + + // Actions + + // Getters + + pub fn all(&self) -> Vec { + self.memory.borrow().iter().cloned().collect() + } + + pub fn enabled(&self) -> Vec { + self.memory + .borrow() + .iter() + .filter(|r| r.is_enabled) + .cloned() + .collect() + } +} + +// Tools + +pub fn migrate(tx: &sqlite::Transaction) -> Result<()> { + // Migrate self components + database::init(tx)?; + + // Delegate migration to childs + // nothing yet... + + // Success + Ok(()) } diff --git a/src/profile/proxy/ignore/database.rs b/src/profile/proxy/ignore/database.rs new file mode 100644 index 00000000..190d98e7 --- /dev/null +++ b/src/profile/proxy/ignore/database.rs @@ -0,0 +1,79 @@ +mod row; + +use anyhow::Result; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use row::Row; +use sqlite::Transaction; + +pub struct Database { + pool: Pool, + profile_id: i64, +} + +impl Database { + // Constructors + + pub fn init(pool: &Pool, profile_id: i64) -> Self { + Self { + pool: pool.clone(), + profile_id, + } + } + + // Getters + + pub fn rows(&self) -> Result> { + rows(&self.pool.get()?.unchecked_transaction()?, self.profile_id) + } +} + +// Low-level DB API + +pub fn init(tx: &Transaction) -> Result { + Ok(tx.execute( + "CREATE TABLE IF NOT EXISTS `profile_proxy_ignore` + ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `profile_id` INTEGER NOT NULL, + `time` INTEGER NOT NULL, + `is_enabled` INTEGER NOT NULL, + `host` VARCHAR(255) NOT NULL, + + FOREIGN KEY (`profile_id`) REFERENCES `profile` (`id`) + )", + [], + )?) +} + +fn rows(tx: &Transaction, profile_id: i64) -> Result> { + let mut stmt = tx.prepare( + "SELECT `id`, + `profile_id`, + `time`, + `host`, + `is_enabled` + + FROM `profile_proxy_ignore` + WHERE `profile_id` = ?", + )?; + + let result = stmt.query_map([profile_id], |row| { + Ok(Row { + //id: row.get(0)?, + //profile_id: row.get(1)?, + //time: DateTime::from_unix_local(row.get(2)?).unwrap(), + host: row.get(3)?, + is_enabled: row.get(4)?, + }) + })?; + + let mut rows = Vec::new(); + + for r in result { + let row = r?; + rows.push(row); + } + + Ok(rows) +} diff --git a/src/profile/proxy/database/ignore.rs b/src/profile/proxy/ignore/database/row.rs similarity index 71% rename from src/profile/proxy/database/ignore.rs rename to src/profile/proxy/ignore/database/row.rs index bb7746a1..f43ab22b 100644 --- a/src/profile/proxy/database/ignore.rs +++ b/src/profile/proxy/ignore/database/row.rs @@ -1,4 +1,4 @@ -pub struct Ignore { +pub struct Row { pub host: String, pub is_enabled: bool, } diff --git a/src/profile/proxy/ignore/memory.rs b/src/profile/proxy/ignore/memory.rs new file mode 100644 index 00000000..c95ed3d0 --- /dev/null +++ b/src/profile/proxy/ignore/memory.rs @@ -0,0 +1,5 @@ +#[derive(Clone)] +pub struct Memory { + pub host: String, + pub is_enabled: bool, +} diff --git a/src/profile/proxy/rule.rs b/src/profile/proxy/rule.rs index 78004b18..14a012b8 100644 --- a/src/profile/proxy/rule.rs +++ b/src/profile/proxy/rule.rs @@ -1,9 +1,114 @@ -#[derive(Clone)] +mod database; +mod memory; + +use anyhow::Result; +use database::Database; +use gtk::glib::DateTime; +use memory::Memory; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use std::cell::RefCell; + pub struct Rule { - pub id: Option, - pub is_enabled: bool, - pub priority: i32, - pub request: String, - pub time: gtk::glib::DateTime, - pub url: String, + database: Database, + memory: RefCell>, +} + +impl Rule { + // Constructors + + pub fn init(database_pool: &Pool, profile_id: i64) -> Result { + let database = Database::init(database_pool, profile_id); + + let rows = database.rows()?; + let memory = RefCell::new(Vec::with_capacity(rows.len())); + + { + // build in-memory index... + let mut m = memory.borrow_mut(); + for row in rows { + m.push(Memory { + id: Some(row.id), + time: row.time, + is_enabled: row.is_enabled, + priority: row.priority, + request: row.request, + url: row.url, + }); + } + } + + Ok(Self { database, memory }) + } + + // Setters + + pub fn add( + &self, + id: Option, + is_enabled: bool, + priority: i32, + request: String, + url: String, + time: DateTime, + ) { + let mut rules = self.memory.borrow_mut(); + rules.push(Memory { + id, + time, + is_enabled, + priority, + request, + url, + }) // @TODO validate? + } + + pub fn clear(&self) { + self.memory.borrow_mut().clear(); + } + + pub fn save(&self) -> Result<()> { + let rules = self.memory.take(); + let mut keep_id = Vec::with_capacity(rules.len()); + for rule in rules { + keep_id.push(self.database.persist( + rule.id, + rule.time, + rule.is_enabled, + rule.priority, + rule.request, + rule.url, + )?); + } + self.database.clean(keep_id)?; + Ok(()) + } + + // Getters + + pub fn all(&self) -> Vec { + self.memory.borrow().iter().cloned().collect() + } + + pub fn enabled(&self) -> Vec { + self.memory + .borrow() + .iter() + .filter(|r| r.is_enabled) + .cloned() + .collect() + } +} + +// Tools + +pub fn migrate(tx: &sqlite::Transaction) -> Result<()> { + // Migrate self components + database::init(tx)?; + + // Delegate migration to childs + // nothing yet... + + // Success + Ok(()) } diff --git a/src/profile/proxy/database.rs b/src/profile/proxy/rule/database.rs similarity index 64% rename from src/profile/proxy/database.rs rename to src/profile/proxy/rule/database.rs index bc3769ac..e84899fb 100644 --- a/src/profile/proxy/database.rs +++ b/src/profile/proxy/rule/database.rs @@ -1,12 +1,10 @@ -mod ignore; -mod rule; +mod row; use anyhow::Result; use gtk::glib::DateTime; -use ignore::Ignore; use r2d2::Pool; use r2d2_sqlite::SqliteConnectionManager; -use rule::Rule; +use row::Row; use sqlite::Transaction; pub struct Database { @@ -26,25 +24,21 @@ impl Database { // Getters - pub fn rules(&self) -> Result> { - rules(&self.pool.get()?.unchecked_transaction()?, self.profile_id) - } - - pub fn ignores(&self) -> Result> { - ignores(&self.pool.get()?.unchecked_transaction()?, self.profile_id) + pub fn rows(&self) -> Result> { + rows(&self.pool.get()?.unchecked_transaction()?, self.profile_id) } // Setters - pub fn clean_rules(&self, keep_id: Vec) -> Result<()> { + pub fn clean(&self, keep_id: Vec) -> Result<()> { let mut c = self.pool.get()?; let tx = c.transaction()?; - clean_rules(&tx, keep_id)?; + clean(&tx, keep_id)?; tx.commit()?; Ok(()) } - pub fn persist_rule( + pub fn persist( &self, id: Option, time: DateTime, @@ -57,10 +51,10 @@ impl Database { let tx = c.transaction()?; let id = match id { Some(id) => { - update_rule(&tx, id, time, is_enabled, priority, request, url)?; + update(&tx, id, time, is_enabled, priority, request, url)?; id } - None => insert_rule( + None => insert( &tx, self.profile_id, time, @@ -78,23 +72,7 @@ impl Database { // Low-level DB API pub fn init(tx: &Transaction) -> Result { - let mut s = 0; - - s += tx.execute( - "CREATE TABLE IF NOT EXISTS `profile_proxy_ignore` - ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - `profile_id` INTEGER NOT NULL, - `time` INTEGER NOT NULL, - `is_enabled` INTEGER NOT NULL, - `host` VARCHAR(255) NOT NULL, - - FOREIGN KEY (`profile_id`) REFERENCES `profile` (`id`) - )", - [], - )?; - - s += tx.execute( + Ok(tx.execute( "CREATE TABLE IF NOT EXISTS `profile_proxy_rule` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -108,12 +86,10 @@ pub fn init(tx: &Transaction) -> Result { FOREIGN KEY (`profile_id`) REFERENCES `profile` (`id`) )", [], - )?; - - Ok(s) + )?) } -pub fn clean_rules(tx: &Transaction, keep_id: Vec) -> Result { +fn clean(tx: &Transaction, keep_id: Vec) -> Result { if keep_id.is_empty() { return Ok(0); } @@ -130,7 +106,7 @@ pub fn clean_rules(tx: &Transaction, keep_id: Vec) -> Result { )?) } -pub fn insert_rule( +fn insert( tx: &Transaction, profile_id: i64, time: DateTime, @@ -160,7 +136,7 @@ pub fn insert_rule( Ok(tx.last_insert_rowid()) } -pub fn update_rule( +fn update( tx: &Transaction, id: i64, time: DateTime, @@ -182,39 +158,7 @@ pub fn update_rule( )?) } -pub fn ignores(tx: &Transaction, profile_id: i64) -> Result> { - let mut stmt = tx.prepare( - "SELECT `id`, - `profile_id`, - `time`, - `host`, - `is_enabled` - - FROM `profile_proxy_ignore` - WHERE `profile_id` = ?", - )?; - - let result = stmt.query_map([profile_id], |row| { - Ok(Ignore { - //id: row.get(0)?, - //profile_id: row.get(1)?, - //time: DateTime::from_unix_local(row.get(2)?).unwrap(), - host: row.get(3)?, - is_enabled: row.get(4)?, - }) - })?; - - let mut records = Vec::new(); - - for record in result { - let table = record?; - records.push(table); - } - - Ok(records) -} - -pub fn rules(tx: &Transaction, profile_id: i64) -> Result> { +fn rows(tx: &Transaction, profile_id: i64) -> Result> { let mut stmt = tx.prepare( "SELECT `id`, `profile_id`, @@ -230,7 +174,7 @@ pub fn rules(tx: &Transaction, profile_id: i64) -> Result> { )?; let result = stmt.query_map([profile_id], |row| { - Ok(Rule { + Ok(Row { id: row.get(0)?, //profile_id: row.get(1)?, time: DateTime::from_unix_local(row.get(2)?).unwrap(), @@ -241,12 +185,11 @@ pub fn rules(tx: &Transaction, profile_id: i64) -> Result> { }) })?; - let mut records = Vec::new(); + let mut rows = Vec::new(); - for record in result { - let table = record?; - records.push(table); + for r in result { + rows.push(r?); } - Ok(records) + Ok(rows) } diff --git a/src/profile/proxy/database/rule.rs b/src/profile/proxy/rule/database/row.rs similarity index 89% rename from src/profile/proxy/database/rule.rs rename to src/profile/proxy/rule/database/row.rs index b786660b..7b3ea34c 100644 --- a/src/profile/proxy/database/rule.rs +++ b/src/profile/proxy/rule/database/row.rs @@ -1,4 +1,4 @@ -pub struct Rule { +pub struct Row { pub id: i64, pub is_enabled: bool, pub priority: i32, diff --git a/src/profile/proxy/rule/memory.rs b/src/profile/proxy/rule/memory.rs new file mode 100644 index 00000000..83da080b --- /dev/null +++ b/src/profile/proxy/rule/memory.rs @@ -0,0 +1,9 @@ +#[derive(Clone)] +pub struct Memory { + pub id: Option, + pub is_enabled: bool, + pub priority: i32, + pub request: String, + pub time: gtk::glib::DateTime, + pub url: String, +}