mirror of
https://github.com/terhechte/postsack
synced 2024-11-12 01:10:48 +00:00
Mail mostly works now. Although terrible and slow
This commit is contained in:
parent
ea94f44720
commit
6086f38a31
@ -50,10 +50,11 @@ pub enum Action {
|
|||||||
Select,
|
Select,
|
||||||
/// Load the mails for the current partition
|
/// Load the mails for the current partition
|
||||||
Mails,
|
Mails,
|
||||||
/// Waiting for the Partition query to finish
|
}
|
||||||
WaitPartition,
|
|
||||||
/// Waiting for the query to finish
|
enum LoadingState {
|
||||||
WaitMails,
|
Loaded(QueryRow),
|
||||||
|
Loading,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
@ -61,11 +62,10 @@ pub struct Engine {
|
|||||||
group_by_stack: Vec<Field>,
|
group_by_stack: Vec<Field>,
|
||||||
link: Link<Action>,
|
link: Link<Action>,
|
||||||
partitions: Vec<Partitions>,
|
partitions: Vec<Partitions>,
|
||||||
action: Option<Action>,
|
|
||||||
/// This is a very simple cache from ranges to rows.
|
/// This is a very simple cache from ranges to rows.
|
||||||
/// It doesn't account for overlapping ranges.
|
/// It doesn't account for overlapping ranges.
|
||||||
/// There's a lot of room for improvement here.
|
/// There's a lot of room for improvement here.
|
||||||
row_cache: SizedCache<usize, QueryRow>,
|
row_cache: SizedCache<usize, LoadingState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
@ -76,16 +76,13 @@ impl Engine {
|
|||||||
search_stack: Vec::new(),
|
search_stack: Vec::new(),
|
||||||
group_by_stack: vec![default_group_by_stack(0)],
|
group_by_stack: vec![default_group_by_stack(0)],
|
||||||
partitions: Vec::new(),
|
partitions: Vec::new(),
|
||||||
action: None,
|
|
||||||
row_cache: SizedCache::with_size(10000),
|
row_cache: SizedCache::with_size(10000),
|
||||||
};
|
};
|
||||||
Ok(engine)
|
Ok(engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<()> {
|
pub fn start(&mut self) -> Result<()> {
|
||||||
// Make the initial query
|
Ok(self.update((self.make_group_query()?, Action::Select))?)
|
||||||
self.action = Some(Action::Select);
|
|
||||||
self.update()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items_with_size(&mut self, rect: Rect) -> Option<&[Partition]> {
|
pub fn items_with_size(&mut self, rect: Rect) -> Option<&[Partition]> {
|
||||||
@ -158,10 +155,9 @@ impl Engine {
|
|||||||
self.group_by_stack
|
self.group_by_stack
|
||||||
.get_mut(grouping.index)
|
.get_mut(grouping.index)
|
||||||
.map(|e| *e = field.clone());
|
.map(|e| *e = field.clone());
|
||||||
self.action = Some(Action::Recalculate);
|
|
||||||
// Remove any rows that were cached for this partition
|
// Remove any rows that were cached for this partition
|
||||||
self.row_cache.cache_clear();
|
self.row_cache.cache_clear();
|
||||||
self.update()
|
self.update((self.make_group_query()?, Action::Recalculate))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_partition(&mut self, partition: Partition) -> Result<()> {
|
pub fn select_partition(&mut self, partition: Partition) -> Result<()> {
|
||||||
@ -186,8 +182,7 @@ impl Engine {
|
|||||||
self.group_by_stack.push(next);
|
self.group_by_stack.push(next);
|
||||||
|
|
||||||
// Block UI & Wait for updates
|
// Block UI & Wait for updates
|
||||||
self.action = Some(Action::Select);
|
self.update((self.make_group_query()?, Action::Select))
|
||||||
self.update()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn back(&mut self) {
|
pub fn back(&mut self) {
|
||||||
@ -217,15 +212,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the last action over the wire to be calculated
|
// Send the last action over the wire to be calculated
|
||||||
fn update(&mut self) -> Result<()> {
|
fn update(&mut self, payload: (Query, Action)) -> Result<()> {
|
||||||
let action = match self.action {
|
Ok(self.link.input_sender.send((payload.0, payload.1))?)
|
||||||
Some(n) => n,
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let request = self.make_group_query().ok_or(eyre!("Invalid State."))?;
|
|
||||||
self.link.input_sender.send((request, action))?;
|
|
||||||
self.action = Some(Action::WaitPartition);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the channels to see if there're any updates
|
/// Fetch the channels to see if there're any updates
|
||||||
@ -253,12 +241,12 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Response::Normal(Query::Normal { range, .. }, Action::Mails, r) => {
|
Response::Normal(Query::Normal { range, .. }, Action::Mails, r) => {
|
||||||
for (index, row) in range.zip(r) {
|
for (index, row) in range.zip(r) {
|
||||||
self.row_cache.cache_set(index, row.clone());
|
let entry = LoadingState::Loaded(row.clone());
|
||||||
|
self.row_cache.cache_set(index, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bail!("Invalid Query / Response combination"),
|
_ => bail!("Invalid Query / Response combination"),
|
||||||
}
|
}
|
||||||
self.action = None;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -282,13 +270,16 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_contents(&mut self, range: &Range<usize>) -> Result<()> {
|
pub fn request_contents(&mut self, range: &Range<usize>) -> Result<()> {
|
||||||
let request = self
|
// Mark the rows as being loaded
|
||||||
.make_normal_query(range.clone())
|
for index in range.clone() {
|
||||||
.ok_or(eyre!("Invalid State."))?;
|
if self.row_cache.cache_get(&index).is_none() {
|
||||||
|
self.row_cache.cache_set(index, LoadingState::Loading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let request = self.make_normal_query(range.clone());
|
||||||
self.link
|
self.link
|
||||||
.input_sender
|
.input_sender
|
||||||
.send((request.clone(), Action::Mails))?;
|
.send((request.clone(), Action::Mails))?;
|
||||||
self.action = Some(Action::WaitMails);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,10 +294,15 @@ impl Engine {
|
|||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
let mut data_missing = false;
|
let mut data_missing = false;
|
||||||
for index in range.clone() {
|
for index in range.clone() {
|
||||||
let entry = self.row_cache.cache_get(&index).map(|e| e.clone());
|
let entry = self.row_cache.cache_get(&index);
|
||||||
if entry.is_none() && !data_missing {
|
let entry = match entry {
|
||||||
|
Some(LoadingState::Loaded(n)) => Some((*n).clone()),
|
||||||
|
Some(LoadingState::Loading) => None,
|
||||||
|
None => {
|
||||||
data_missing = true;
|
data_missing = true;
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
};
|
||||||
rows.push(entry);
|
rows.push(entry);
|
||||||
}
|
}
|
||||||
Ok((rows, data_missing))
|
Ok((rows, data_missing))
|
||||||
@ -319,35 +315,39 @@ impl Engine {
|
|||||||
/// When we don't have partitions loaded yet, or
|
/// When we don't have partitions loaded yet, or
|
||||||
/// when we're currently querying / loading new partitions
|
/// when we're currently querying / loading new partitions
|
||||||
pub fn is_partitions_busy(&self) -> bool {
|
pub fn is_partitions_busy(&self) -> bool {
|
||||||
self.partitions.is_empty() || self.action == Some(Action::WaitPartition)
|
self.partitions.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If we're loading mails
|
/// If we're loading mails
|
||||||
pub fn is_mail_busy(&self) -> bool {
|
pub fn is_mail_busy(&self) -> bool {
|
||||||
self.action == Some(Action::WaitMails)
|
!self.link.input_sender.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_group_query(&self) -> Option<Query> {
|
fn make_group_query(&self) -> Result<Query> {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
for entry in &self.search_stack {
|
for entry in &self.search_stack {
|
||||||
filters.push(Filter::Like(entry.clone()));
|
filters.push(Filter::Like(entry.clone()));
|
||||||
}
|
}
|
||||||
Some(Query::Grouped {
|
let last = self
|
||||||
|
.group_by_stack
|
||||||
|
.last()
|
||||||
|
.ok_or(eyre!("Invalid partition state"))?;
|
||||||
|
Ok(Query::Grouped {
|
||||||
filters,
|
filters,
|
||||||
group_by: self.group_by_stack.last()?.clone(),
|
group_by: last.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_normal_query(&self, range: Range<usize>) -> Option<Query> {
|
fn make_normal_query(&self, range: Range<usize>) -> Query {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
for entry in &self.search_stack {
|
for entry in &self.search_stack {
|
||||||
filters.push(Filter::Like(entry.clone()));
|
filters.push(Filter::Like(entry.clone()));
|
||||||
}
|
}
|
||||||
Some(Query::Normal {
|
Query::Normal {
|
||||||
filters,
|
filters,
|
||||||
fields: vec![Field::SenderDomain, Field::SenderLocalPart, Field::Subject],
|
fields: vec![Field::SenderDomain, Field::SenderLocalPart, Field::Subject],
|
||||||
range,
|
range,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use crossbeam_channel::{unbounded, Receiver, Sender};
|
|||||||
use eyre::{Report, Result};
|
use eyre::{Report, Result};
|
||||||
|
|
||||||
use crate::database::{
|
use crate::database::{
|
||||||
query::{Field, Filter, Query, ValueField},
|
query::Query,
|
||||||
query_result::{QueryResult, QueryRow},
|
query_result::{QueryResult, QueryRow},
|
||||||
Database,
|
Database,
|
||||||
};
|
};
|
||||||
@ -25,6 +25,10 @@ use super::partitions::{Partition, Partitions};
|
|||||||
// - instead of hard-coding subject/sender-domain, have a "Detail" trait
|
// - instead of hard-coding subject/sender-domain, have a "Detail" trait
|
||||||
// - consider a better logic for the cache (by row id and just fetch the smallest range that contains all missing numbers)
|
// - consider a better logic for the cache (by row id and just fetch the smallest range that contains all missing numbers)
|
||||||
|
|
||||||
|
pub trait Payload<O> {
|
||||||
|
fn map_response<T>(self, response: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Response<Context: Send + 'static> {
|
pub enum Response<Context: Send + 'static> {
|
||||||
Grouped(Query, Context, Partitions),
|
Grouped(Query, Context, Partitions),
|
||||||
|
@ -4,10 +4,7 @@ use eframe::egui::Rect as EguiRect;
|
|||||||
use eyre::{Report, Result};
|
use eyre::{Report, Result};
|
||||||
use treemap::{Mappable, Rect, TreemapLayout};
|
use treemap::{Mappable, Rect, TreemapLayout};
|
||||||
|
|
||||||
use crate::database::{
|
use crate::database::{query::ValueField, query_result::QueryResult};
|
||||||
query::{Field, ValueField},
|
|
||||||
query_result::QueryResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Partition {
|
pub struct Partition {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::query::{Field, Value, ValueField};
|
use super::query::{Field, ValueField};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub type QueryRow = HashMap<Field, ValueField>;
|
pub type QueryRow = HashMap<Field, ValueField>;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::cluster_engine::Engine;
|
use crate::cluster_engine::Engine;
|
||||||
use crate::database::query::{Field, Value};
|
use crate::database::query::Field;
|
||||||
use eframe::egui::{self, Widget};
|
use eframe::egui::{self, Widget};
|
||||||
use eyre::Report;
|
use eyre::Report;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user