diff --git a/yazi-dds/src/body/body.rs b/yazi-dds/src/body/body.rs index 1d35d271..cdfaff87 100644 --- a/yazi-dds/src/body/body.rs +++ b/yazi-dds/src/body/body.rs @@ -8,7 +8,7 @@ use crate::Payload; #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] pub enum Body<'a> { - Hi(BodyHi), + Hi(BodyHi<'a>), Hey(BodyHey), Tabs(BodyTabs<'a>), Cd(BodyCd<'a>), diff --git a/yazi-dds/src/body/bulk.rs b/yazi-dds/src/body/bulk.rs index d762842b..4e35f1cc 100644 --- a/yazi-dds/src/body/bulk.rs +++ b/yazi-dds/src/body/bulk.rs @@ -32,12 +32,7 @@ impl<'a> From> for Body<'a> { impl IntoLua<'_> for BodyBulk<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result { - lua - .create_any_userdata(BodyBulkIter { - tab: self.tab, - inner: self.changes.into_owned().into_iter(), - })? - .into_lua(lua) + BodyBulkIter { tab: self.tab, inner: self.changes.into_owned().into_iter() }.into_lua(lua) } } diff --git a/yazi-dds/src/body/cd.rs b/yazi-dds/src/body/cd.rs index 5c8fa761..587a6f1b 100644 --- a/yazi-dds/src/body/cd.rs +++ b/yazi-dds/src/body/cd.rs @@ -8,22 +8,23 @@ use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyCd<'a> { - pub owned: bool, - pub tab: usize, - pub url: Cow<'a, Url>, + pub tab: usize, + pub url: Cow<'a, Url>, + #[serde(skip)] + dummy: bool, } impl<'a> BodyCd<'a> { #[inline] pub fn borrowed(tab: usize, url: &'a Url) -> Body<'a> { - Self { owned: false, tab, url: Cow::Borrowed(url) }.into() + Self { tab, url: Cow::Borrowed(url), dummy: false }.into() } } impl BodyCd<'static> { #[inline] - pub fn owned(tab: usize) -> Body<'static> { - Self { owned: false, tab, url: Default::default() }.into() + pub fn dummy(tab: usize) -> Body<'static> { + Self { tab, url: Default::default(), dummy: true }.into() } } @@ -33,10 +34,10 @@ impl<'a> From> for Body<'a> { impl IntoLua<'_> for BodyCd<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result { - if self.owned { + if let Some(Cow::Owned(url)) = Some(self.url).filter(|_| !self.dummy) { lua.create_table_from([ ("tab", self.tab.into_lua(lua)?), - ("url", lua.create_any_userdata(self.url.into_owned())?.into_lua(lua)?), + ("url", lua.create_any_userdata(url)?.into_lua(lua)?), ])? } else { lua.create_table_from([("tab", self.tab)])? diff --git a/yazi-dds/src/body/hi.rs b/yazi-dds/src/body/hi.rs index ba32c051..b536b55d 100644 --- a/yazi-dds/src/body/hi.rs +++ b/yazi-dds/src/body/hi.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::{borrow::Cow, collections::HashSet}; use mlua::{ExternalResult, IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; @@ -6,16 +6,22 @@ use serde::{Deserialize, Serialize}; use super::Body; #[derive(Debug, Serialize, Deserialize)] -pub struct BodyHi { - pub id: u64, - pub abilities: HashSet, +pub struct BodyHi<'a> { + pub abilities: HashSet>, } -impl From for Body<'_> { - fn from(value: BodyHi) -> Self { Self::Hi(value) } +impl<'a> BodyHi<'a> { + #[inline] + pub fn borrowed(abilities: HashSet<&'a String>) -> Body<'a> { + Self { abilities: abilities.into_iter().map(Cow::Borrowed).collect() }.into() + } } -impl IntoLua<'_> for BodyHi { +impl<'a> From> for Body<'a> { + fn from(value: BodyHi<'a>) -> Self { Self::Hi(value) } +} + +impl IntoLua<'_> for BodyHi<'_> { fn into_lua(self, _: &Lua) -> mlua::Result> { Err("BodyHi cannot be converted to Lua").into_lua_err() } diff --git a/yazi-dds/src/body/hover.rs b/yazi-dds/src/body/hover.rs index 45211b62..e3916fa4 100644 --- a/yazi-dds/src/body/hover.rs +++ b/yazi-dds/src/body/hover.rs @@ -8,21 +8,20 @@ use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyHover<'a> { - pub owned: bool, - pub tab: usize, - pub url: Option>, + pub tab: usize, + pub url: Option>, } impl<'a> BodyHover<'a> { #[inline] pub fn borrowed(tab: usize, url: Option<&'a Url>) -> Body<'a> { - Self { owned: false, tab, url: url.map(Cow::Borrowed) }.into() + Self { tab, url: url.map(Cow::Borrowed) }.into() } } impl BodyHover<'static> { #[inline] - pub fn owned(tab: usize) -> Body<'static> { Self { owned: false, tab, url: None }.into() } + pub fn dummy(tab: usize) -> Body<'static> { Self { tab, url: None }.into() } } impl<'a> From> for Body<'a> { @@ -31,10 +30,10 @@ impl<'a> From> for Body<'a> { impl IntoLua<'_> for BodyHover<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result { - if self.owned && self.url.is_some() { + if let Some(Cow::Owned(url)) = self.url { lua.create_table_from([ ("tab", self.tab.into_lua(lua)?), - ("url", lua.create_any_userdata(self.url.unwrap().into_owned())?.into_lua(lua)?), + ("url", lua.create_any_userdata(url)?.into_lua(lua)?), ])? } else { lua.create_table_from([("tab", self.tab)])? diff --git a/yazi-dds/src/body/rename.rs b/yazi-dds/src/body/rename.rs index 98fac976..55dd68ab 100644 --- a/yazi-dds/src/body/rename.rs +++ b/yazi-dds/src/body/rename.rs @@ -22,7 +22,7 @@ impl<'a> BodyRename<'a> { impl BodyRename<'static> { #[inline] - pub fn owned(tab: usize, from: &Url, to: &Url) -> Body<'static> { + pub fn dummy(tab: usize, from: &Url, to: &Url) -> Body<'static> { Self { tab, from: Cow::Owned(from.clone()), to: Cow::Owned(to.clone()) }.into() } } diff --git a/yazi-dds/src/body/tabs.rs b/yazi-dds/src/body/tabs.rs index 97b619aa..f7b63b26 100644 --- a/yazi-dds/src/body/tabs.rs +++ b/yazi-dds/src/body/tabs.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use mlua::{IntoLua, Lua, MetaMethod, UserData, Value}; +use mlua::{MetaMethod, UserData}; use serde::{Deserialize, Serialize}; use yazi_shared::fs::Url; @@ -8,7 +8,6 @@ use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyTabs<'a> { - pub owned: bool, pub cursor: usize, pub items: Vec>, } @@ -16,59 +15,20 @@ pub struct BodyTabs<'a> { impl<'a> BodyTabs<'a> { #[inline] pub fn borrowed(cursor: usize, urls: &[&'a Url]) -> Body<'a> { - Self { - owned: false, - cursor, - items: urls.iter().map(|&u| BodyTabsItem { url: Cow::Borrowed(u) }).collect(), - } - .into() + Self { cursor, items: urls.iter().map(|&u| BodyTabsItem::from(u)).collect() }.into() } } impl BodyTabs<'static> { #[inline] - pub fn owned(cursor: usize) -> Body<'static> { - Self { owned: false, cursor, items: Default::default() }.into() - } + pub fn dummy(cursor: usize) -> Body<'static> { Self { cursor, items: Default::default() }.into() } } impl<'a> From> for Body<'a> { fn from(value: BodyTabs<'a>) -> Self { Self::Tabs(value) } } -impl IntoLua<'_> for BodyTabs<'static> { - fn into_lua(self, lua: &Lua) -> mlua::Result> { - if self.owned { - BodyTabsIter::from(self).into_lua(lua) - } else { - lua.create_table_from([("cursor", self.cursor)])?.into_lua(lua) - } - } -} - -// --- Item -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BodyTabsItem<'a> { - pub url: Cow<'a, Url>, -} - -impl UserData for BodyTabsItem<'static> { - fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("url", |lua, me| lua.create_any_userdata(me.url.clone())); - } -} - -// --- Iterator -pub struct BodyTabsIter { - pub cursor: usize, - pub items: Vec>, -} - -impl From> for BodyTabsIter { - fn from(value: BodyTabs<'static>) -> Self { Self { cursor: value.cursor, items: value.items } } -} - -impl UserData for BodyTabsIter { +impl UserData for BodyTabs<'static> { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("cursor", |_, me| Ok(me.cursor)); } @@ -81,3 +41,19 @@ impl UserData for BodyTabsIter { }); } } + +// --- Item +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BodyTabsItem<'a> { + pub url: Cow<'a, Url>, +} + +impl<'a> From<&'a Url> for BodyTabsItem<'a> { + fn from(value: &'a Url) -> Self { Self { url: Cow::Borrowed(value) } } +} + +impl UserData for BodyTabsItem<'static> { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("url", |lua, me| lua.create_any_userdata(me.url.clone())); + } +} diff --git a/yazi-dds/src/body/yank.rs b/yazi-dds/src/body/yank.rs index 5bcc012d..d18c3fcf 100644 --- a/yazi-dds/src/body/yank.rs +++ b/yazi-dds/src/body/yank.rs @@ -8,23 +8,20 @@ use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyYank<'a> { - pub owned: bool, - pub cut: bool, - pub urls: Cow<'a, HashSet>, + pub cut: bool, + pub urls: Cow<'a, HashSet>, } impl<'a> BodyYank<'a> { #[inline] pub fn borrowed(cut: bool, urls: &'a HashSet) -> Body<'a> { - Self { owned: false, cut, urls: Cow::Borrowed(urls) }.into() + Self { cut, urls: Cow::Borrowed(urls) }.into() } } impl BodyYank<'static> { #[inline] - pub fn owned(cut: bool) -> Body<'static> { - Self { owned: false, cut, urls: Default::default() }.into() - } + pub fn dummy(cut: bool) -> Body<'static> { Self { cut, urls: Default::default() }.into() } } impl<'a> From> for Body<'a> { @@ -33,8 +30,8 @@ impl<'a> From> for Body<'a> { impl IntoLua<'_> for BodyYank<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result> { - if self.owned { - BodyYankIter::from(self).into_lua(lua) + if let Cow::Owned(urls) = self.urls { + BodyYankIter { cut: self.cut, urls: urls.into_iter().collect() }.into_lua(lua) } else { lua.create_table_from([("cut", self.cut)])?.into_lua(lua) } @@ -47,12 +44,6 @@ pub struct BodyYankIter { pub urls: Vec, } -impl From> for BodyYankIter { - fn from(value: BodyYank) -> Self { - Self { cut: value.cut, urls: value.urls.into_owned().into_iter().collect() } - } -} - impl UserData for BodyYankIter { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("is_cut", |_, me| Ok(me.cut)); diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index eb9a9681..fdaa8ac1 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -4,18 +4,19 @@ use anyhow::{anyhow, Result}; use yazi_boot::BOOT; use yazi_shared::{emit, event::Cmd, Layer}; -use crate::body::Body; +use crate::{body::Body, ID}; #[derive(Debug)] pub struct Payload<'a> { pub receiver: u64, pub severity: u8, + pub sender: u64, pub body: Body<'a>, } impl<'a> Payload<'a> { #[inline] - pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: 0, severity: 0, body } } + pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: 0, severity: 0, sender: *ID, body } } #[inline] pub(super) fn with_receiver(mut self, receiver: u64) -> Self { @@ -56,7 +57,7 @@ impl FromStr for Payload<'_> { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - let mut parts = s.splitn(4, ','); + let mut parts = s.splitn(5, ','); let kind = parts.next().ok_or_else(|| anyhow!("empty kind"))?; @@ -66,9 +67,12 @@ impl FromStr for Payload<'_> { let severity = parts.next().and_then(|s| s.parse().ok()).ok_or_else(|| anyhow!("invalid severity"))?; + let sender = + parts.next().and_then(|s| s.parse().ok()).ok_or_else(|| anyhow!("invalid sender"))?; + let body = parts.next().ok_or_else(|| anyhow!("empty body"))?; - Ok(Self { receiver, severity, body: Body::from_str(kind, body)? }) + Ok(Self { receiver, severity, sender, body: Body::from_str(kind, body)? }) } } @@ -87,7 +91,7 @@ impl Display for Payload<'_> { }; if let Ok(s) = result { - write!(f, "{},{},{},{s}", self.body.kind(), self.receiver, self.severity) + write!(f, "{},{},{},{},{s}", self.body.kind(), self.receiver, self.severity, self.sender) } else { Err(std::fmt::Error) } diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index fb72c2c8..19535bcc 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -88,69 +88,70 @@ impl Pubsub { } pub fn pub_from_hi() -> bool { - Client::push(Payload::new( - BodyHi { id: *ID, abilities: REMOTE.read().keys().cloned().collect() }.into(), - )); + let abilities = REMOTE.read().keys().cloned().collect(); + let abilities = BOOT.remote_events.union(&abilities).collect(); + + Client::push(BodyHi::borrowed(abilities).upgrade()); true } pub fn pub_from_tabs(tab: usize, urls: &[&Url]) { if LOCAL.read().contains_key("tabs") { - Self::pub_(BodyTabs::owned(tab)); + Self::pub_(BodyTabs::dummy(tab)); } if PEERS.read().values().any(|p| p.able("tabs")) { Client::push(BodyTabs::borrowed(tab, urls).upgrade()); } if BOOT.local_events.contains("tabs") { - BodyTabs::borrowed(tab, urls).upgrade().flush(true); + BodyTabs::borrowed(tab, urls).upgrade().with_receiver(*ID).flush(true); } } pub fn pub_from_cd(tab: usize, url: &Url) { if LOCAL.read().contains_key("cd") { - Self::pub_(BodyCd::owned(tab)); + Self::pub_(BodyCd::dummy(tab)); } if PEERS.read().values().any(|p| p.able("cd")) { Client::push(BodyCd::borrowed(tab, url).upgrade()); } if BOOT.local_events.contains("cd") { - BodyCd::borrowed(tab, url).upgrade().flush(true); + BodyCd::borrowed(tab, url).upgrade().with_receiver(*ID).flush(true); } } pub fn pub_from_hover(tab: usize, url: Option<&Url>) { if LOCAL.read().contains_key("hover") { - Self::pub_(BodyHover::owned(tab)); + Self::pub_(BodyHover::dummy(tab)); } if PEERS.read().values().any(|p| p.able("hover")) { Client::push(BodyHover::borrowed(tab, url).upgrade()); } if BOOT.local_events.contains("hover") { - BodyHover::borrowed(tab, url).upgrade().flush(true); + BodyHover::borrowed(tab, url).upgrade().with_receiver(*ID).flush(true); } } pub fn pub_from_rename(tab: usize, from: &Url, to: &Url) { if LOCAL.read().contains_key("rename") { - Self::pub_(BodyRename::owned(tab, from, to)); + Self::pub_(BodyRename::dummy(tab, from, to)); } if PEERS.read().values().any(|p| p.able("rename")) { Client::push(BodyRename::borrowed(tab, from, to).upgrade()); } if BOOT.local_events.contains("rename") { - BodyRename::borrowed(tab, from, to).upgrade().flush(true); + BodyRename::borrowed(tab, from, to).upgrade().with_receiver(*ID).flush(true); } } pub fn pub_from_yank(cut: bool, urls: &HashSet) { if LOCAL.read().contains_key("yank") { - Self::pub_(BodyYank::owned(cut)); + Self::pub_(BodyYank::dummy(cut)); } if PEERS.read().values().any(|p| p.able("yank")) { Client::push(BodyYank::borrowed(cut, urls).upgrade()); } if BOOT.local_events.contains("yank") { - BodyYank::borrowed(cut, urls).upgrade().flush(true); + BodyYank::borrowed(cut, urls).upgrade().with_receiver(*ID).flush(true); } } } diff --git a/yazi-dds/src/server.rs b/yazi-dds/src/server.rs index 679f8634..f7a243cd 100644 --- a/yazi-dds/src/server.rs +++ b/yazi-dds/src/server.rs @@ -92,16 +92,21 @@ impl Server { } fn handle_hi(s: String, id: &mut Option, tx: mpsc::UnboundedSender) { - let Ok(Body::Hi(hi)) = Payload::from_str(&s).map(|p| p.body) else { return }; + let Ok(payload) = Payload::from_str(&s) else { return }; + let Body::Hi(hi) = payload.body else { return }; let mut clients = CLIENTS.write(); - id.replace(hi.id).and_then(|id| clients.remove(&id)); + id.replace(payload.sender).and_then(|id| clients.remove(&id)); if let Some(ref state) = *STATE.read() { state.values().for_each(|s| _ = tx.send(format!("{s}\n"))); } - clients.insert(hi.id, Client { id: hi.id, tx, abilities: hi.abilities }); + clients.insert(payload.sender, Client { + id: payload.sender, + tx, + abilities: hi.abilities.into_iter().map(|s| s.into_owned()).collect(), + }); Self::handle_hey(&clients); } diff --git a/yazi-dds/src/state.rs b/yazi-dds/src/state.rs index 7d15af8e..36d1ef8e 100644 --- a/yazi-dds/src/state.rs +++ b/yazi-dds/src/state.rs @@ -36,10 +36,11 @@ impl State { let mut inner = HashMap::new(); while buf.read_line(&mut line).await? > 0 { - let mut parts = line.splitn(4, ','); + let mut parts = line.splitn(5, ','); let Some(kind) = parts.next() else { continue }; let Some(_) = parts.next() else { continue }; let Some(severity) = parts.next().and_then(|s| s.parse::().ok()) else { continue }; + let Some(_) = parts.next() else { continue }; let Some(body) = parts.next() else { continue }; inner.insert(format!("{}_{severity}_{kind}", Body::tab(kind, body)), mem::take(&mut line)); }