From 72794dcbdc8ece0e8ccb0f98a2b18d558920b65b Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Sun, 25 Oct 2026 10:31:53 +0700 Subject: [PATCH] Replace flume Selector with futures select for wasm compatibility --- Cargo.lock | 1 + crates/assets/Cargo.toml | 5 +++ crates/person/Cargo.toml | 1 + crates/person/src/lib.rs | 51 +++++++++++++++------- crates/workspace/src/sidebar/onboarding.rs | 9 +--- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2cceff40..8a8cfa52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5719,6 +5719,7 @@ dependencies = [ "anyhow", "common", "flume 0.11.1", + "futures", "gpui-pre", "instant", "log", diff --git a/crates/assets/Cargo.toml b/crates/assets/Cargo.toml index 21b3f8ad..97af1380 100644 --- a/crates/assets/Cargo.toml +++ b/crates/assets/Cargo.toml @@ -9,3 +9,8 @@ gpui.workspace = true anyhow.workspace = true rust-embed.workspace = true gpui-kit.workspace = true + +# On wasm there is no filesystem to read from, so rust-embed's debug-mode +# disk loading returns nothing; embed the assets even in debug builds. +[target.'cfg(target_arch = "wasm32")'.dependencies] +rust-embed = { workspace = true, features = ["debug-embed"] } diff --git a/crates/person/Cargo.toml b/crates/person/Cargo.toml index c1385580..aa4221b2 100644 --- a/crates/person/Cargo.toml +++ b/crates/person/Cargo.toml @@ -8,6 +8,7 @@ publish.workspace = true common = { path = "../common" } state = { path = "../state" } +futures.workspace = true gpui.workspace = true nostr-sdk.workspace = true instant.workspace = true diff --git a/crates/person/src/lib.rs b/crates/person/src/lib.rs index d885e079..39a04cc5 100644 --- a/crates/person/src/lib.rs +++ b/crates/person/src/lib.rs @@ -3,7 +3,10 @@ use std::sync::RwLock; use anyhow::{Error, anyhow}; use common::emojis_from_tags; -use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task}; +use futures::{FutureExt, pin_mut}; +use gpui::{ + App, AppContext, BackgroundExecutor, Context, Entity, EventEmitter, Global, Subscription, Task, +}; use instant::Duration; use nostr_sdk::prelude::*; use smallvec::{SmallVec, smallvec}; @@ -98,8 +101,9 @@ impl PersonRegistry { })); let client3 = client.clone(); + let executor = cx.background_executor().clone(); tasks.push(cx.background_spawn(async move { - Self::handle_requests(&client3, &metadata_rx).await; + Self::handle_requests(&client3, &metadata_rx, executor).await; })); tasks.push(cx.spawn(async move |this, cx| { @@ -193,30 +197,45 @@ impl PersonRegistry { } /// Handle request for metadata - async fn handle_requests(client: &Client, rx: &flume::Receiver) { + async fn handle_requests( + client: &Client, + rx: &flume::Receiver, + executor: BackgroundExecutor, + ) { let mut batch: HashSet = HashSet::new(); loop { - match flume::Selector::new() - .recv(rx, |result| result.ok()) - .wait_timeout(Duration::from_secs(TIMEOUT)) - { - Ok(Some(public_key)) => { - batch.insert(public_key); - // Process the batch if it's full - if batch.len() >= 20 - && let Err(e) = get_metadata(client, std::mem::take(&mut batch)).await - { - log::warn!("Failed to get metadata batch: {e}"); + let timer = executor.timer(Duration::from_secs(TIMEOUT)).fuse(); + pin_mut!(timer); + + let request = futures::select! { + result = rx.recv_async().fuse() => match result { + Ok(public_key) => public_key, + Err(_) => { + if !batch.is_empty() + && let Err(e) = get_metadata(client, std::mem::take(&mut batch)).await + { + log::warn!("Failed to get metadata batch: {e}"); + } + return; } - } - _ => { + }, + () = timer => { if !batch.is_empty() && let Err(e) = get_metadata(client, std::mem::take(&mut batch)).await { log::warn!("Failed to get metadata batch: {e}"); } + continue; } + }; + + batch.insert(request); + // Process the batch if it's full + if batch.len() >= 20 + && let Err(e) = get_metadata(client, std::mem::take(&mut batch)).await + { + log::warn!("Failed to get metadata batch: {e}"); } } } diff --git a/crates/workspace/src/sidebar/onboarding.rs b/crates/workspace/src/sidebar/onboarding.rs index 15fc4b54..8a178a3e 100644 --- a/crates/workspace/src/sidebar/onboarding.rs +++ b/crates/workspace/src/sidebar/onboarding.rs @@ -1,8 +1,7 @@ -use std::time::{SystemTime, UNIX_EPOCH}; - use gpui::{AnyElement, App, IntoElement, ParentElement, SharedString, Styled, Window, img}; use gpui_kit::component::button::{Button, ButtonVariants}; use gpui_kit::component::v_flex; +use instant::Instant; use crate::dialogs::import; @@ -11,12 +10,8 @@ const SIGNED_OUT_BANNERS: [&str; 2] = ["brand/bg1.jpg", "brand/bg2.jpg"]; /// Pick one of the signed-out backgrounds at random. pub(super) fn pick_banner() -> SharedString { - let nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map(|elapsed| elapsed.subsec_nanos()) - .unwrap_or_default(); + let nanos = Instant::now().elapsed().subsec_nanos(); let index = nanos as usize % SIGNED_OUT_BANNERS.len(); - SIGNED_OUT_BANNERS[index].into() }