From 3cdc3ecb70c13da9325b8333dca8514a53bcbdc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Sat, 28 Feb 2026 13:01:03 +0800 Subject: [PATCH] feat: new `hey` DDS event fires when static messages are restored from persistence (#3725) --- CHANGELOG.md | 4 ++- Cargo.lock | 44 ++++++++++++++-------------- Cargo.toml | 2 +- yazi-actor/src/app/accept_payload.rs | 5 ++-- yazi-dds/src/client.rs | 37 +++++++++++++++-------- yazi-dds/src/ember/bye.rs | 8 ++--- yazi-dds/src/ember/duplicate.rs | 10 +++---- yazi-dds/src/ember/ember.rs | 2 -- yazi-dds/src/ember/hey.rs | 6 ++-- yazi-dds/src/ember/hi.rs | 6 ++-- yazi-dds/src/ember/mount.rs | 4 +-- yazi-dds/src/ember/move.rs | 10 +++---- yazi-dds/src/ember/tab.rs | 4 +-- yazi-dds/src/payload.rs | 4 +-- yazi-dds/src/pubsub.rs | 13 +++++--- yazi-dds/src/pump.rs | 10 +++---- yazi-dds/src/server.rs | 11 ++++--- 17 files changed, 95 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1547ddd9..e388e351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,8 +24,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - New `marker_symbol` option to specify the symbol used for marking files ([#3689]) - New `fs.unique()` creates a unique file or directory ([#3677]) - New `download` DDS event fires when remote files are downloaded ([#3687]) -- New `cx.which` API to access the which component state ([#3617]) - New `ind-which-activate` DDS event to change the which component behavior ([#3608]) +- New `hey` DDS event fires when static messages are restored from persistence ([#3725]) +- New `cx.which` API to access the which component state ([#3617]) ### Changed @@ -1668,3 +1669,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3689]: https://github.com/sxyazi/yazi/pull/3689 [#3696]: https://github.com/sxyazi/yazi/pull/3696 [#3708]: https://github.com/sxyazi/yazi/pull/3708 +[#3725]: https://github.com/sxyazi/yazi/pull/3725 diff --git a/Cargo.lock b/Cargo.lock index 101a1a78..d07fc345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2163,9 +2163,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.90" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -2752,9 +2752,9 @@ checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] @@ -3123,9 +3123,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -5029,9 +5029,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -5042,9 +5042,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.63" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a89f4650b770e4521aa6573724e2aed4704372151bd0de9d16a3bbabb87441a" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", "futures-util", @@ -5056,9 +5056,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5066,9 +5066,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -5079,9 +5079,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] @@ -5122,9 +5122,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.90" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705eceb4ce901230f8625bd1d665128056ccbe4b7408faa625eec1ba80f59a97" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -6294,18 +6294,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c0ebd87a..e66ec0fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ indexmap = { version = "2.13.0", features = [ "serde" ] } libc = "0.2.182" lru = "0.16.3" mlua = { version = "0.11.6", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] } -objc2 = "0.6.3" +objc2 = "0.6.4" ordered-float = { version = "5.1.0", features = [ "serde" ] } parking_lot = "0.12.5" paste = "1.0.15" diff --git a/yazi-actor/src/app/accept_payload.rs b/yazi-actor/src/app/accept_payload.rs index 1384fabc..d125d046 100644 --- a/yazi-actor/src/app/accept_payload.rs +++ b/yazi-actor/src/app/accept_payload.rs @@ -18,16 +18,17 @@ impl Actor for AcceptPayload { const NAME: &str = "accept_payload"; fn act(cx: &mut Ctx, payload: Payload) -> Result { - let kind = payload.body.kind().to_owned(); + let kind = payload.body.kind(); let lock = if payload.receiver == 0 || payload.receiver != payload.sender { REMOTE.read() } else { LOCAL.read() }; - let Some(handlers) = lock.get(&kind).filter(|&m| !m.is_empty()).cloned() else { succ!() }; + let Some(handlers) = lock.get(kind).filter(|&m| !m.is_empty()).cloned() else { succ!() }; drop(lock); + let kind = kind.to_owned(); succ!(Lives::scope(&cx.core, || { let body = payload.body.into_lua(&LUA)?; for (id, cb) in handlers { diff --git a/yazi-dds/src/client.rs b/yazi-dds/src/client.rs index 84f40b13..8fdffec3 100644 --- a/yazi-dds/src/client.rs +++ b/yazi-dds/src/client.rs @@ -9,7 +9,7 @@ use tracing::error; use yazi_macro::try_format; use yazi_shared::{Id, RoCell}; -use crate::{ClientReader, ClientWriter, Payload, Pubsub, Server, Stream, ember::{Ember, EmberBye, EmberHi}}; +use crate::{ClientReader, ClientWriter, Payload, Pubsub, Server, Stream, ember::{Ember, EmberBye, EmberHey, EmberHi}}; pub static ID: RoCell = RoCell::new(); pub(super) static PEERS: RoCell>> = RoCell::new(); @@ -54,12 +54,23 @@ impl Client { }; if line.is_empty() { - continue; - } else if line.starts_with("hey,") { - Self::handle_hey(&line); - } else if let Err(e) = Payload::from_str(&line).and_then(|p| p.emit()) { - error!("Could not parse payload:\n{line}\n\nError:\n{e}"); + continue; // Heartbeat, ignore } + + let payload = match Payload::from_str(&line) { + Ok(p) => p, + Err(e) => { + error!("Failed to parse DDS payload:\n{line}\n\nError:\n{e}"); + continue; + } + }; + + if let Ember::Hey(hey) = &payload.body { + Self::handle_hey(hey); + } + + payload.try_flush().ok(); + payload.emit(); } } } @@ -73,7 +84,7 @@ impl Client { let payload = try_format!( "{}\n{kind},{receiver},{ID},{body}\n{}\n", Payload::new(EmberHi::borrowed(iter::empty())), - Payload::new(EmberBye::owned()) + Payload::new(EmberBye::borrowed()) )?; let (mut lines, mut writer) = Stream::connect().await?; @@ -197,11 +208,13 @@ impl Client { Self::connect(server).await } - fn handle_hey(s: &str) { - if let Ok(Ember::Hey(mut hey)) = Payload::from_str(s).map(|p| p.body) { - hey.peers.retain(|&id, _| id != *ID); - *PEERS.write() = hey.peers; - } + fn handle_hey(body: &EmberHey) { + *PEERS.write() = body + .peers + .iter() + .filter(|&(id, _)| *id != *ID) + .map(|(&id, peer)| (id, peer.clone())) + .collect(); } } diff --git a/yazi-dds/src/ember/bye.rs b/yazi-dds/src/ember/bye.rs index 6f2440dd..fa8d1462 100644 --- a/yazi-dds/src/ember/bye.rs +++ b/yazi-dds/src/ember/bye.rs @@ -1,4 +1,4 @@ -use mlua::{ExternalResult, IntoLua, Lua, Value}; +use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; use super::Ember; @@ -7,7 +7,7 @@ use super::Ember; pub struct EmberBye; impl EmberBye { - pub fn owned() -> Ember<'static> { Self.into() } + pub fn borrowed() -> Ember<'static> { Self.into() } } impl From for Ember<'_> { @@ -15,7 +15,5 @@ impl From for Ember<'_> { } impl IntoLua for EmberBye { - fn into_lua(self, _: &Lua) -> mlua::Result { - Err("BodyBye cannot be converted to Lua").into_lua_err() - } + fn into_lua(self, lua: &Lua) -> mlua::Result { lua.create_table()?.into_lua(lua) } } diff --git a/yazi-dds/src/ember/duplicate.rs b/yazi-dds/src/ember/duplicate.rs index cb024124..b6468144 100644 --- a/yazi-dds/src/ember/duplicate.rs +++ b/yazi-dds/src/ember/duplicate.rs @@ -8,17 +8,17 @@ use super::Ember; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct EmberDuplicate<'a> { - pub items: Cow<'a, Vec>, + pub items: Cow<'a, Vec>, } impl<'a> EmberDuplicate<'a> { - pub fn borrowed(items: &'a Vec) -> Ember<'a> { + pub fn borrowed(items: &'a Vec) -> Ember<'a> { Self { items: Cow::Borrowed(items) }.into() } } impl EmberDuplicate<'static> { - pub fn owned(items: Vec) -> Ember<'static> { + pub fn owned(items: Vec) -> Ember<'static> { Self { items: Cow::Owned(items) }.into() } } @@ -35,12 +35,12 @@ impl IntoLua for EmberDuplicate<'_> { // --- Item #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct BodyDuplicateItem { +pub struct EmberDuplicateItem { pub from: UrlBuf, pub to: UrlBuf, } -impl IntoLua for BodyDuplicateItem { +impl IntoLua for EmberDuplicateItem { fn into_lua(self, lua: &Lua) -> mlua::Result { lua .create_table_from([ diff --git a/yazi-dds/src/ember/ember.rs b/yazi-dds/src/ember/ember.rs index e37a9066..b2325752 100644 --- a/yazi-dds/src/ember/ember.rs +++ b/yazi-dds/src/ember/ember.rs @@ -119,8 +119,6 @@ impl<'a> Ember<'a> { pub fn with_receiver(self, receiver: Id) -> Payload<'a> { Payload::new(self).with_receiver(receiver) } - - pub fn with_sender(self, sender: Id) -> Payload<'a> { Payload::new(self).with_sender(sender) } } impl<'a> IntoLua for Ember<'a> { diff --git a/yazi-dds/src/ember/hey.rs b/yazi-dds/src/ember/hey.rs index a0b591b7..299cbcd6 100644 --- a/yazi-dds/src/ember/hey.rs +++ b/yazi-dds/src/ember/hey.rs @@ -1,5 +1,5 @@ use hashbrown::HashMap; -use mlua::{ExternalResult, IntoLua, Lua, Value}; +use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; use yazi_shared::{Id, SStr}; @@ -24,7 +24,5 @@ impl From for Ember<'_> { } impl IntoLua for EmberHey { - fn into_lua(self, _: &Lua) -> mlua::Result { - Err("BodyHey cannot be converted to Lua").into_lua_err() - } + fn into_lua(self, lua: &Lua) -> mlua::Result { lua.create_table()?.into_lua(lua) } } diff --git a/yazi-dds/src/ember/hi.rs b/yazi-dds/src/ember/hi.rs index baa102f4..d94d804b 100644 --- a/yazi-dds/src/ember/hi.rs +++ b/yazi-dds/src/ember/hi.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use hashbrown::HashSet; -use mlua::{ExternalResult, IntoLua, Lua, Value}; +use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; use yazi_shared::SStr; @@ -33,7 +33,5 @@ impl<'a> From> for Ember<'a> { } impl IntoLua for EmberHi<'_> { - fn into_lua(self, _: &Lua) -> mlua::Result { - Err("BodyHi cannot be converted to Lua").into_lua_err() - } + fn into_lua(self, lua: &Lua) -> mlua::Result { lua.create_table()?.into_lua(lua) } } diff --git a/yazi-dds/src/ember/mount.rs b/yazi-dds/src/ember/mount.rs index 834ae7a2..98ee446b 100644 --- a/yazi-dds/src/ember/mount.rs +++ b/yazi-dds/src/ember/mount.rs @@ -7,9 +7,9 @@ use super::Ember; pub struct EmberMount; impl EmberMount { - pub fn owned() -> Ember<'static> { Self.into() } + pub fn borrowed() -> Ember<'static> { Self.into() } - pub fn borrowed() -> Ember<'static> { Self::owned() } + pub fn owned() -> Ember<'static> { Self::borrowed() } } impl From for Ember<'_> { diff --git a/yazi-dds/src/ember/move.rs b/yazi-dds/src/ember/move.rs index 363836cb..3b5102d1 100644 --- a/yazi-dds/src/ember/move.rs +++ b/yazi-dds/src/ember/move.rs @@ -8,17 +8,17 @@ use super::Ember; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct EmberMove<'a> { - pub items: Cow<'a, Vec>, + pub items: Cow<'a, Vec>, } impl<'a> EmberMove<'a> { - pub fn borrowed(items: &'a Vec) -> Ember<'a> { + pub fn borrowed(items: &'a Vec) -> Ember<'a> { Self { items: Cow::Borrowed(items) }.into() } } impl EmberMove<'static> { - pub fn owned(items: Vec) -> Ember<'static> { + pub fn owned(items: Vec) -> Ember<'static> { Self { items: Cow::Owned(items) }.into() } } @@ -35,12 +35,12 @@ impl IntoLua for EmberMove<'_> { // --- Item #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct BodyMoveItem { +pub struct EmberMoveItem { pub from: UrlBuf, pub to: UrlBuf, } -impl IntoLua for BodyMoveItem { +impl IntoLua for EmberMoveItem { fn into_lua(self, lua: &Lua) -> mlua::Result { lua .create_table_from([ diff --git a/yazi-dds/src/ember/tab.rs b/yazi-dds/src/ember/tab.rs index 371023c7..bca60015 100644 --- a/yazi-dds/src/ember/tab.rs +++ b/yazi-dds/src/ember/tab.rs @@ -10,9 +10,9 @@ pub struct EmberTab { } impl EmberTab { - pub fn owned(id: Id) -> Ember<'static> { Self { id }.into() } + pub fn borrowed(id: Id) -> Ember<'static> { Self { id }.into() } - pub fn borrowed(id: Id) -> Ember<'static> { Self::owned(id) } + pub fn owned(id: Id) -> Ember<'static> { Self::borrowed(id) } } impl From for Ember<'_> { diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index 7bedd083..f1dd3d59 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -46,10 +46,8 @@ impl<'a> Payload<'a> { } impl Payload<'static> { - pub(super) fn emit(self) -> Result<()> { - self.try_flush()?; + pub(super) fn emit(self) { emit!(Call(relay!(app:accept_payload).with_any("payload", self))); - Ok(()) } } diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index f25297f9..7e4efdc1 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -6,7 +6,7 @@ use yazi_boot::BOOT; use yazi_fs::FolderStage; use yazi_shared::{Id, RoCell, url::{Url, UrlBuf, UrlBufCov}}; -use crate::{Client, ID, PEERS, ember::{BodyDuplicateItem, BodyMoveItem, Ember, EmberBulk, EmberHi}}; +use crate::{Client, ID, PEERS, ember::{Ember, EmberBulk, EmberDuplicateItem, EmberHi, EmberMoveItem}}; pub static LOCAL: RoCell>>> = RoCell::new(); @@ -96,7 +96,12 @@ impl Pubsub { unsub!(REMOTE)(plugin, kind) && Self::pub_inner_hi() } - pub fn r#pub(body: Ember<'static>) -> Result<()> { body.with_receiver(*ID).emit() } + pub fn r#pub(body: Ember<'static>) -> Result<()> { + let payload = body.with_receiver(*ID); + payload.try_flush()?; + payload.emit(); + Ok(()) + } pub fn pub_to(receiver: Id, body: Ember<'static>) -> Result<()> { if receiver == *ID { @@ -157,9 +162,9 @@ impl Pubsub { pub_after!(@yank(cut: bool, urls: &HashSet), (cut, urls)); - pub_after!(duplicate(items: Vec), (&items), (items)); + pub_after!(duplicate(items: Vec), (&items), (items)); - pub_after!(move(items: Vec), (&items), (items)); + pub_after!(move(items: Vec), (&items), (items)); pub_after!(trash(urls: Vec), (&urls), (urls)); diff --git a/yazi-dds/src/pump.rs b/yazi-dds/src/pump.rs index 0948a826..3d0524a1 100644 --- a/yazi-dds/src/pump.rs +++ b/yazi-dds/src/pump.rs @@ -5,10 +5,10 @@ use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_macro::err; use yazi_shared::{RoCell, url::UrlBuf}; -use crate::{Pubsub, ember::{BodyDuplicateItem, BodyMoveItem}}; +use crate::{Pubsub, ember::{EmberDuplicateItem, EmberMoveItem}}; -static DUPLICATE_TX: RoCell> = RoCell::new(); -static MOVE_TX: RoCell> = RoCell::new(); +static DUPLICATE_TX: RoCell> = RoCell::new(); +static MOVE_TX: RoCell> = RoCell::new(); static TRASH_TX: RoCell> = RoCell::new(); static DELETE_TX: RoCell> = RoCell::new(); static DOWNLOAD_TX: RoCell> = RoCell::new(); @@ -21,14 +21,14 @@ impl Pump { where U: Into, { - DUPLICATE_TX.send(BodyDuplicateItem { from: from.into(), to: to.into() }).ok(); + DUPLICATE_TX.send(EmberDuplicateItem { from: from.into(), to: to.into() }).ok(); } pub fn push_move(from: U, to: U) where U: Into, { - MOVE_TX.send(BodyMoveItem { from: from.into(), to: to.into() }).ok(); + MOVE_TX.send(EmberMoveItem { from: from.into(), to: to.into() }).ok(); } pub fn push_trash(target: U) diff --git a/yazi-dds/src/server.rs b/yazi-dds/src/server.rs index 2abd461e..1d845063 100644 --- a/yazi-dds/src/server.rs +++ b/yazi-dds/src/server.rs @@ -93,14 +93,13 @@ impl Server { let Ok(payload) = Payload::from_str(&s) else { return }; let Ember::Hi(hi) = payload.body else { return }; - if id.is_none() - && let Some(ref state) = *STATE.read() - { + let mut clients = CLIENTS.write(); + if let Some(old_id) = id.replace(payload.sender) { + clients.remove(&old_id); + } else if let Some(state) = &*STATE.read() { state.values().for_each(|s| _ = tx.send(s.clone())); } - let mut clients = CLIENTS.write(); - id.replace(payload.sender).and_then(|id| clients.remove(&id)); clients.insert(payload.sender, Client { id: payload.sender, tx, @@ -126,7 +125,7 @@ impl Server { } } - let bye = EmberBye::owned().with_receiver(id).with_sender(Id(0)); + let bye = EmberBye::borrowed().with_receiver(id).with_sender(Id(0)); if let Ok(s) = try_format!("{bye}") { writer.write_all(s.as_bytes()).await.ok(); writer.flush().await.ok();