commit badf3070c8b5008ba3ad9f20ae9bafee916393ca
parent 5cdf3698d2f64c75332894307ce8f93d57bcbfaa
Author: kernelkind <kernelkind@gmail.com>
Date: Sat, 8 Mar 2025 20:45:00 -0500
introduce JobsCache
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
3 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs
@@ -13,7 +13,7 @@ use crate::{
};
use notedeck::{Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, UnknownIds};
-use notedeck_ui::NoteOptions;
+use notedeck_ui::{jobs::JobsCache, NoteOptions};
use enostr::{ClientMessage, Keypair, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
use uuid::Uuid;
@@ -42,6 +42,7 @@ pub struct Damus {
pub timeline_cache: TimelineCache,
pub subscriptions: Subscriptions,
pub support: Support,
+ pub jobs: JobsCache,
//frame_history: crate::frame_history::FrameHistory,
@@ -430,6 +431,8 @@ impl Damus {
note_options.set_scramble_text(parsed_args.scramble);
note_options.set_hide_media(parsed_args.no_media);
+ let jobs = JobsCache::default();
+
Self {
subscriptions: Subscriptions::default(),
since_optimize: parsed_args.since_optimize,
@@ -444,6 +447,7 @@ impl Damus {
decks_cache,
debug,
unrecognized_args,
+ jobs,
}
}
@@ -487,6 +491,7 @@ impl Damus {
support,
decks_cache,
unrecognized_args: BTreeSet::default(),
+ jobs: JobsCache::default(),
}
}
diff --git a/crates/notedeck_ui/src/jobs.rs b/crates/notedeck_ui/src/jobs.rs
@@ -0,0 +1,153 @@
+use egui::TextureHandle;
+use hashbrown::{hash_map::RawEntryMut, HashMap};
+use notedeck::JobPool;
+use poll_promise::Promise;
+
+#[derive(Default)]
+pub struct JobsCache {
+ jobs: HashMap<JobIdOwned, JobState>,
+}
+
+pub enum JobState {
+ Pending(Promise<Option<Result<Job, JobError>>>),
+ Error(JobError),
+ Completed(Job),
+}
+
+pub enum JobError {
+ InvalidParameters,
+}
+
+#[derive(Debug)]
+pub enum JobParams<'a> {
+ Blurhash(BlurhashParams<'a>),
+}
+
+#[derive(Debug)]
+pub enum JobParamsOwned {
+ Blurhash(BlurhashParamsOwned),
+}
+
+impl<'a> From<BlurhashParams<'a>> for BlurhashParamsOwned {
+ fn from(params: BlurhashParams<'a>) -> Self {
+ BlurhashParamsOwned {
+ blurhash: params.blurhash.to_owned(),
+ url: params.url.to_owned(),
+ ctx: params.ctx.clone(),
+ }
+ }
+}
+
+impl<'a> From<JobParams<'a>> for JobParamsOwned {
+ fn from(params: JobParams<'a>) -> Self {
+ match params {
+ JobParams::Blurhash(bp) => JobParamsOwned::Blurhash(bp.into()),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct BlurhashParams<'a> {
+ pub blurhash: &'a str,
+ pub url: &'a str,
+ pub ctx: &'a egui::Context,
+}
+
+#[derive(Debug)]
+pub struct BlurhashParamsOwned {
+ pub blurhash: String,
+ pub url: String,
+ pub ctx: egui::Context,
+}
+
+impl JobsCache {
+ pub fn get_or_insert_with<
+ 'a,
+ F: FnOnce(Option<JobParamsOwned>) -> Result<Job, JobError> + Send + 'static,
+ >(
+ &'a mut self,
+ job_pool: &mut JobPool,
+ jobid: &JobId,
+ params: Option<JobParams>,
+ run_job: F,
+ ) -> &'a mut JobState {
+ match self.jobs.raw_entry_mut().from_key(jobid) {
+ RawEntryMut::Occupied(entry) => 's: {
+ let mut state = entry.into_mut();
+
+ let JobState::Pending(promise) = &mut state else {
+ break 's state;
+ };
+
+ let Some(res) = promise.ready_mut() else {
+ break 's state;
+ };
+
+ let Some(res) = res.take() else {
+ tracing::error!("Failed to take the promise for job: {:?}", jobid);
+ break 's state;
+ };
+
+ *state = match res {
+ Ok(j) => JobState::Completed(j),
+ Err(e) => JobState::Error(e),
+ };
+
+ state
+ }
+ RawEntryMut::Vacant(entry) => {
+ let owned_params = params.map(JobParams::into);
+ let wrapped: Box<dyn FnOnce() -> Option<Result<Job, JobError>> + Send + 'static> =
+ Box::new(move || Some(run_job(owned_params)));
+
+ let promise = Promise::spawn_async(job_pool.schedule(wrapped));
+
+ let (_, state) = entry.insert(jobid.into(), JobState::Pending(promise));
+
+ state
+ }
+ }
+ }
+
+ pub fn get(&self, jobid: &JobId) -> Option<&JobState> {
+ self.jobs.get(jobid)
+ }
+}
+
+impl<'a> From<&JobId<'a>> for JobIdOwned {
+ fn from(jobid: &JobId<'a>) -> Self {
+ match jobid {
+ JobId::Blurhash(s) => JobIdOwned::Blurhash(s.to_string()),
+ }
+ }
+}
+
+impl hashbrown::Equivalent<JobIdOwned> for JobId<'_> {
+ fn equivalent(&self, key: &JobIdOwned) -> bool {
+ match (self, key) {
+ (JobId::Blurhash(a), JobIdOwned::Blurhash(b)) => *a == b.as_str(),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+enum JobIdOwned {
+ Blurhash(String), // image URL
+}
+
+#[derive(Debug, Hash)]
+pub enum JobId<'a> {
+ Blurhash(&'a str), // image URL
+}
+
+pub enum Job {
+ Blurhash(Option<TextureHandle>),
+}
+
+impl std::fmt::Debug for Job {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Job::Blurhash(_) => write!(f, "Blurhash"),
+ }
+ }
+}
diff --git a/crates/notedeck_ui/src/lib.rs b/crates/notedeck_ui/src/lib.rs
@@ -5,6 +5,7 @@ pub mod contacts;
pub mod gif;
pub mod icons;
pub mod images;
+pub mod jobs;
pub mod mention;
pub mod note;
pub mod profile;