feat: new hey DDS event fires when static messages are restored from persistence (#3725)

This commit is contained in:
三咲雅 misaki masa 2026-02-28 13:01:03 +08:00 committed by GitHub
parent 884c265de1
commit 3cdc3ecb70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 95 additions and 85 deletions

View file

@ -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

44
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -18,16 +18,17 @@ impl Actor for AcceptPayload {
const NAME: &str = "accept_payload";
fn act(cx: &mut Ctx, payload: Payload) -> Result<Data> {
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 {

View file

@ -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<Id> = RoCell::new();
pub(super) static PEERS: RoCell<RwLock<HashMap<Id, Peer>>> = 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();
}
}

View file

@ -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<EmberBye> for Ember<'_> {
@ -15,7 +15,5 @@ impl From<EmberBye> for Ember<'_> {
}
impl IntoLua for EmberBye {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> {
Err("BodyBye cannot be converted to Lua").into_lua_err()
}
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { lua.create_table()?.into_lua(lua) }
}

View file

@ -8,17 +8,17 @@ use super::Ember;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberDuplicate<'a> {
pub items: Cow<'a, Vec<BodyDuplicateItem>>,
pub items: Cow<'a, Vec<EmberDuplicateItem>>,
}
impl<'a> EmberDuplicate<'a> {
pub fn borrowed(items: &'a Vec<BodyDuplicateItem>) -> Ember<'a> {
pub fn borrowed(items: &'a Vec<EmberDuplicateItem>) -> Ember<'a> {
Self { items: Cow::Borrowed(items) }.into()
}
}
impl EmberDuplicate<'static> {
pub fn owned(items: Vec<BodyDuplicateItem>) -> Ember<'static> {
pub fn owned(items: Vec<EmberDuplicateItem>) -> 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<Value> {
lua
.create_table_from([

View file

@ -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> {

View file

@ -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<EmberHey> for Ember<'_> {
}
impl IntoLua for EmberHey {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> {
Err("BodyHey cannot be converted to Lua").into_lua_err()
}
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { lua.create_table()?.into_lua(lua) }
}

View file

@ -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<EmberHi<'a>> for Ember<'a> {
}
impl IntoLua for EmberHi<'_> {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> {
Err("BodyHi cannot be converted to Lua").into_lua_err()
}
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { lua.create_table()?.into_lua(lua) }
}

View file

@ -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<EmberMount> for Ember<'_> {

View file

@ -8,17 +8,17 @@ use super::Ember;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EmberMove<'a> {
pub items: Cow<'a, Vec<BodyMoveItem>>,
pub items: Cow<'a, Vec<EmberMoveItem>>,
}
impl<'a> EmberMove<'a> {
pub fn borrowed(items: &'a Vec<BodyMoveItem>) -> Ember<'a> {
pub fn borrowed(items: &'a Vec<EmberMoveItem>) -> Ember<'a> {
Self { items: Cow::Borrowed(items) }.into()
}
}
impl EmberMove<'static> {
pub fn owned(items: Vec<BodyMoveItem>) -> Ember<'static> {
pub fn owned(items: Vec<EmberMoveItem>) -> 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<Value> {
lua
.create_table_from([

View file

@ -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<EmberTab> for Ember<'_> {

View file

@ -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(())
}
}

View file

@ -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<RwLock<HashMap<String, HashMap<String, Function>>>> = 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<UrlBufCov>), (cut, urls));
pub_after!(duplicate(items: Vec<BodyDuplicateItem>), (&items), (items));
pub_after!(duplicate(items: Vec<EmberDuplicateItem>), (&items), (items));
pub_after!(move(items: Vec<BodyMoveItem>), (&items), (items));
pub_after!(move(items: Vec<EmberMoveItem>), (&items), (items));
pub_after!(trash(urls: Vec<UrlBuf>), (&urls), (urls));

View file

@ -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<mpsc::UnboundedSender<BodyDuplicateItem>> = RoCell::new();
static MOVE_TX: RoCell<mpsc::UnboundedSender<BodyMoveItem>> = RoCell::new();
static DUPLICATE_TX: RoCell<mpsc::UnboundedSender<EmberDuplicateItem>> = RoCell::new();
static MOVE_TX: RoCell<mpsc::UnboundedSender<EmberMoveItem>> = RoCell::new();
static TRASH_TX: RoCell<mpsc::UnboundedSender<UrlBuf>> = RoCell::new();
static DELETE_TX: RoCell<mpsc::UnboundedSender<UrlBuf>> = RoCell::new();
static DOWNLOAD_TX: RoCell<mpsc::UnboundedSender<UrlBuf>> = RoCell::new();
@ -21,14 +21,14 @@ impl Pump {
where
U: Into<UrlBuf>,
{
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<U>(from: U, to: U)
where
U: Into<UrlBuf>,
{
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<U>(target: U)

View file

@ -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();