mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat!: DDS client-server version check (#1111)
This commit is contained in:
parent
add801f28e
commit
e4d67121f8
21 changed files with 136 additions and 72 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -1698,9 +1698,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.202"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
@ -1717,9 +1717,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.202"
|
version = "1.0.203"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -2052,9 +2052,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.37.0"
|
version = "1.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -2071,9 +2071,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -2807,6 +2807,7 @@ dependencies = [
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"uzers",
|
"uzers",
|
||||||
|
"vergen",
|
||||||
"yazi-boot",
|
"yazi-boot",
|
||||||
"yazi-shared",
|
"yazi-shared",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ imagesize = "0.12.0"
|
||||||
kamadak-exif = "0.5.5"
|
kamadak-exif = "0.5.5"
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||||
|
|
||||||
# External dependencies
|
# External dependencies
|
||||||
clap = { version = "4.5.4", features = [ "derive" ] }
|
clap = { version = "4.5.4", features = [ "derive" ] }
|
||||||
serde = { version = "1.0.202", features = [ "derive" ] }
|
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = { version = "4.5.4", features = [ "derive" ] }
|
clap = { version = "4.5.4", features = [ "derive" ] }
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ clap = { version = "4.5.4", features = [ "derive" ] }
|
||||||
crossterm = "0.27.0"
|
crossterm = "0.27.0"
|
||||||
md-5 = "0.10.6"
|
md-5 = "0.10.6"
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.117"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
toml_edit = "0.22.13"
|
toml_edit = "0.22.13"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ pub(super) enum Command {
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
pub(super) struct CommandPub {
|
pub(super) struct CommandPub {
|
||||||
/// The receiver ID.
|
|
||||||
#[arg(index = 1)]
|
|
||||||
pub(super) receiver: u64,
|
|
||||||
/// The kind of message.
|
/// The kind of message.
|
||||||
#[arg(index = 2)]
|
#[arg(index = 1)]
|
||||||
pub(super) kind: String,
|
pub(super) kind: String,
|
||||||
|
/// The receiver ID.
|
||||||
|
#[arg(index = 2)]
|
||||||
|
pub(super) receiver: Option<u64>,
|
||||||
/// Send the message with a string body.
|
/// Send the message with a string body.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub(super) str: Option<String>,
|
pub(super) str: Option<String>,
|
||||||
|
|
@ -41,6 +41,17 @@ pub(super) struct CommandPub {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandPub {
|
impl CommandPub {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(super) fn receiver(&self) -> Result<u64> {
|
||||||
|
if let Some(receiver) = self.receiver {
|
||||||
|
Ok(receiver)
|
||||||
|
} else if let Ok(s) = std::env::var("YAZI_ID") {
|
||||||
|
Ok(s.parse()?)
|
||||||
|
} else {
|
||||||
|
bail!("No receiver ID provided, also no YAZI_ID environment variable found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(super) fn body(&self) -> Result<Cow<str>> {
|
pub(super) fn body(&self) -> Result<Cow<str>> {
|
||||||
if let Some(json) = &self.json {
|
if let Some(json) = &self.json {
|
||||||
|
|
@ -48,19 +59,19 @@ impl CommandPub {
|
||||||
} else if let Some(str) = &self.str {
|
} else if let Some(str) = &self.str {
|
||||||
Ok(serde_json::to_string(str)?.into())
|
Ok(serde_json::to_string(str)?.into())
|
||||||
} else {
|
} else {
|
||||||
bail!("No body provided");
|
Ok("".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(clap::Args)]
|
#[derive(clap::Args)]
|
||||||
pub(super) struct CommandPubStatic {
|
pub(super) struct CommandPubStatic {
|
||||||
/// The severity of the message.
|
|
||||||
#[arg(index = 1)]
|
|
||||||
pub(super) severity: u16,
|
|
||||||
/// The kind of message.
|
/// The kind of message.
|
||||||
#[arg(index = 2)]
|
#[arg(index = 1)]
|
||||||
pub(super) kind: String,
|
pub(super) kind: String,
|
||||||
|
/// The severity of the message.
|
||||||
|
#[arg(index = 2)]
|
||||||
|
pub(super) severity: u16,
|
||||||
/// Send the message with a string body.
|
/// Send the message with a string body.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub(super) str: Option<String>,
|
pub(super) str: Option<String>,
|
||||||
|
|
@ -77,7 +88,7 @@ impl CommandPubStatic {
|
||||||
} else if let Some(str) = &self.str {
|
} else if let Some(str) = &self.str {
|
||||||
Ok(serde_json::to_string(str)?.into())
|
Ok(serde_json::to_string(str)?.into())
|
||||||
} else {
|
} else {
|
||||||
bail!("No body provided");
|
Ok("".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
match Args::parse().command {
|
match Args::parse().command {
|
||||||
Command::Pub(cmd) => {
|
Command::Pub(cmd) => {
|
||||||
yazi_dds::init();
|
yazi_dds::init();
|
||||||
if let Err(e) = yazi_dds::Client::shot(&cmd.kind, cmd.receiver, None, &cmd.body()?).await {
|
if let Err(e) = yazi_dds::Client::shot(&cmd.kind, cmd.receiver()?, None, &cmd.body()?).await {
|
||||||
eprintln!("Cannot send message: {e}");
|
eprintln!("Cannot send message: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ crossterm = "0.27.0"
|
||||||
globset = "0.4.14"
|
globset = "0.4.14"
|
||||||
indexmap = "2.2.6"
|
indexmap = "2.2.6"
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
serde = { version = "1.0.202", features = [ "derive" ] }
|
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
toml = { version = "0.8.13", features = [ "preserve_order" ] }
|
toml = { version = "0.8.13", features = [ "preserve_order" ] }
|
||||||
validator = { version = "0.18.1", features = [ "derive" ] }
|
validator = { version = "0.18.1", features = [ "derive" ] }
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ parking_lot = "0.12.3"
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
serde = "1.0.202"
|
serde = "1.0.203"
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.15"
|
tokio-stream = "0.1.15"
|
||||||
tokio-util = "0.7.11"
|
tokio-util = "0.7.11"
|
||||||
unicode-width = "0.1.12"
|
unicode-width = "0.1.12"
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ bitflags! {
|
||||||
pub struct Opt: u8 {
|
pub struct Opt: u8 {
|
||||||
const FIND = 0b00001;
|
const FIND = 0b00001;
|
||||||
const VISUAL = 0b00010;
|
const VISUAL = 0b00010;
|
||||||
const SELECT = 0b00100;
|
const FILTER = 0b00100;
|
||||||
const FILTER = 0b01000;
|
const SELECT = 0b01000;
|
||||||
const SEARCH = 0b10000;
|
const SEARCH = 0b10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -21,8 +21,8 @@ impl From<Cmd> for Opt {
|
||||||
("all", true) => Self::all(),
|
("all", true) => Self::all(),
|
||||||
("find", true) => acc | Self::FIND,
|
("find", true) => acc | Self::FIND,
|
||||||
("visual", true) => acc | Self::VISUAL,
|
("visual", true) => acc | Self::VISUAL,
|
||||||
("select", true) => acc | Self::SELECT,
|
|
||||||
("filter", true) => acc | Self::FILTER,
|
("filter", true) => acc | Self::FILTER,
|
||||||
|
("select", true) => acc | Self::SELECT,
|
||||||
("search", true) => acc | Self::SEARCH,
|
("search", true) => acc | Self::SEARCH,
|
||||||
_ => acc,
|
_ => acc,
|
||||||
}
|
}
|
||||||
|
|
@ -36,8 +36,8 @@ impl Tab {
|
||||||
if opt.is_empty() {
|
if opt.is_empty() {
|
||||||
_ = self.escape_find()
|
_ = self.escape_find()
|
||||||
|| self.escape_visual()
|
|| self.escape_visual()
|
||||||
|| self.escape_select()
|
|
||||||
|| self.escape_filter()
|
|| self.escape_filter()
|
||||||
|
|| self.escape_select()
|
||||||
|| self.escape_search();
|
|| self.escape_search();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -48,12 +48,12 @@ impl Tab {
|
||||||
if opt.contains(Opt::VISUAL) {
|
if opt.contains(Opt::VISUAL) {
|
||||||
self.escape_visual();
|
self.escape_visual();
|
||||||
}
|
}
|
||||||
if opt.contains(Opt::SELECT) {
|
|
||||||
self.escape_select();
|
|
||||||
}
|
|
||||||
if opt.contains(Opt::FILTER) {
|
if opt.contains(Opt::FILTER) {
|
||||||
self.escape_filter();
|
self.escape_filter();
|
||||||
}
|
}
|
||||||
|
if opt.contains(Opt::SELECT) {
|
||||||
|
self.escape_select();
|
||||||
|
}
|
||||||
if opt.contains(Opt::SEARCH) {
|
if opt.contains(Opt::SEARCH) {
|
||||||
self.escape_search();
|
self.escape_search();
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +70,15 @@ impl Tab {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn escape_filter(&mut self) -> bool {
|
||||||
|
if self.current.files.filter().is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.filter_do(super::filter::Opt::default());
|
||||||
|
render_and!(true)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn escape_select(&mut self) -> bool {
|
pub fn escape_select(&mut self) -> bool {
|
||||||
if self.selected.is_empty() {
|
if self.selected.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -82,15 +91,6 @@ impl Tab {
|
||||||
render_and!(true)
|
render_and!(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn escape_filter(&mut self) -> bool {
|
|
||||||
if self.current.files.filter().is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.filter_do(super::filter::Opt::default());
|
|
||||||
render_and!(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn escape_search(&mut self) -> bool {
|
pub fn escape_search(&mut self) -> bool {
|
||||||
if !self.current.cwd.is_search() {
|
if !self.current.cwd.is_search() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,14 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||||
parking_lot = "0.12.3"
|
parking_lot = "0.12.3"
|
||||||
serde = { version = "1.0.202", features = [ "derive" ] }
|
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.117"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.15"
|
tokio-stream = "0.1.15"
|
||||||
tokio-util = "0.7.11"
|
tokio-util = "0.7.11"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
vergen = { version = "8.3.1", features = [ "build", "git", "gitcl" ] }
|
||||||
|
|
||||||
[target."cfg(unix)".dependencies]
|
[target."cfg(unix)".dependencies]
|
||||||
uzers = "0.12.0"
|
uzers = "0.12.0"
|
||||||
|
|
|
||||||
9
yazi-dds/build.rs
Normal file
9
yazi-dds/build.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use vergen::EmitBuilder;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
EmitBuilder::builder().git_sha(true).emit()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -4,11 +4,11 @@ use serde::{Deserialize, Serialize};
|
||||||
use super::Body;
|
use super::Body;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct BodyBye {}
|
pub struct BodyBye;
|
||||||
|
|
||||||
impl BodyBye {
|
impl BodyBye {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn borrowed() -> Body<'static> { Self {}.into() }
|
pub fn owned() -> Body<'static> { Self.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<BodyBye> for Body<'a> {
|
impl<'a> From<BodyBye> for Body<'a> {
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,20 @@ use std::collections::HashMap;
|
||||||
use mlua::{ExternalResult, IntoLua, Lua, Value};
|
use mlua::{ExternalResult, IntoLua, Lua, Value};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::Body;
|
use super::{Body, BodyHi};
|
||||||
use crate::Peer;
|
use crate::Peer;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct BodyHey {
|
pub struct BodyHey {
|
||||||
pub peers: HashMap<u64, Peer>,
|
pub peers: HashMap<u64, Peer>,
|
||||||
|
pub version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BodyHey {
|
||||||
|
#[inline]
|
||||||
|
pub fn owned(peers: HashMap<u64, Peer>) -> Body<'static> {
|
||||||
|
Self { peers, version: BodyHi::version() }.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BodyHey> for Body<'_> {
|
impl From<BodyHey> for Body<'_> {
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,21 @@ use super::Body;
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct BodyHi<'a> {
|
pub struct BodyHi<'a> {
|
||||||
pub abilities: HashSet<Cow<'a, String>>,
|
pub abilities: HashSet<Cow<'a, String>>,
|
||||||
|
pub version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BodyHi<'a> {
|
impl<'a> BodyHi<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn borrowed(abilities: HashSet<&'a String>) -> Body<'a> {
|
pub fn borrowed(abilities: HashSet<&'a String>) -> Body<'a> {
|
||||||
Self { abilities: abilities.into_iter().map(Cow::Borrowed).collect() }.into()
|
Self {
|
||||||
|
abilities: abilities.into_iter().map(Cow::Borrowed).collect(),
|
||||||
|
version: Self::version(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn version() -> String { format!("{} {}", env!("CARGO_PKG_VERSION"), env!("VERGEN_GIT_SHA")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<BodyHi<'a>> for Body<'a> {
|
impl<'a> From<BodyHi<'a>> for Body<'a> {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{collections::{HashMap, HashSet}, mem, str::FromStr};
|
use std::{collections::{HashMap, HashSet}, mem, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time};
|
use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time};
|
||||||
|
|
@ -69,7 +69,7 @@ impl Client {
|
||||||
let payload = format!(
|
let payload = format!(
|
||||||
"{}\n{kind},{receiver},{sender},{body}\n{}\n",
|
"{}\n{kind},{receiver},{sender},{body}\n{}\n",
|
||||||
Payload::new(BodyHi::borrowed(Default::default())),
|
Payload::new(BodyHi::borrowed(Default::default())),
|
||||||
Payload::new(BodyBye::borrowed())
|
Payload::new(BodyBye::owned())
|
||||||
);
|
);
|
||||||
|
|
||||||
let (mut lines, mut writer) = Stream::connect().await?;
|
let (mut lines, mut writer) = Stream::connect().await?;
|
||||||
|
|
@ -77,12 +77,26 @@ impl Client {
|
||||||
writer.flush().await?;
|
writer.flush().await?;
|
||||||
drop(writer);
|
drop(writer);
|
||||||
|
|
||||||
while let Ok(Some(s)) = lines.next_line().await {
|
let mut version = None;
|
||||||
if matches!(s.split(',').next(), Some(kind) if kind == "bye") {
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
break;
|
match line.split(',').next() {
|
||||||
|
Some("hey") if version.is_none() => {
|
||||||
|
if let Ok(Body::Hey(hey)) = Payload::from_str(&line).map(|p| p.body) {
|
||||||
|
version = Some(hey.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some("bye") => break,
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version != Some(BodyHi::version()) {
|
||||||
|
bail!(
|
||||||
|
"Incompatible version (Ya {}, Yazi {})",
|
||||||
|
BodyHi::version(),
|
||||||
|
version.as_deref().unwrap_or("Unknown")
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ use std::{collections::HashMap, str::FromStr, time::Duration};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tokio::{io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, select, sync::mpsc, task::JoinHandle, time};
|
use tokio::{io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle, time};
|
||||||
use yazi_shared::RoCell;
|
use yazi_shared::RoCell;
|
||||||
|
|
||||||
use crate::{body::{Body, BodyBye, BodyHey}, Client, Payload, Peer, Stream, STATE};
|
use crate::{body::{Body, BodyBye, BodyHey}, Client, ClientWriter, Payload, Peer, Stream, STATE};
|
||||||
|
|
||||||
pub(super) static CLIENTS: RoCell<RwLock<HashMap<u64, Client>>> = RoCell::new();
|
pub(super) static CLIENTS: RoCell<RwLock<HashMap<u64, Client>>> = RoCell::new();
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ impl Server {
|
||||||
|
|
||||||
let Some(id) = id else { continue };
|
let Some(id) = id else { continue };
|
||||||
if line.starts_with("bye,") {
|
if line.starts_with("bye,") {
|
||||||
writer.write_all(BodyBye::borrowed().with_receiver(id).with_sender(0).to_string().as_bytes()).await.ok();
|
Self::handle_bye(id, rx, writer).await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,11 @@ impl Server {
|
||||||
else => break
|
else => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::handle_bye(id);
|
|
||||||
|
let mut clients = CLIENTS.write();
|
||||||
|
if id.and_then(|id| clients.remove(&id)).is_some() {
|
||||||
|
Self::handle_hey(&clients);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
@ -111,18 +115,24 @@ impl Server {
|
||||||
fn handle_hey(clients: &HashMap<u64, Client>) {
|
fn handle_hey(clients: &HashMap<u64, Client>) {
|
||||||
let payload = format!(
|
let payload = format!(
|
||||||
"{}\n",
|
"{}\n",
|
||||||
Payload::new(
|
Payload::new(BodyHey::owned(
|
||||||
BodyHey { peers: clients.values().map(|c| (c.id, Peer::new(&c.abilities))).collect() }
|
clients.values().map(|c| (c.id, Peer::new(&c.abilities))).collect()
|
||||||
.into()
|
))
|
||||||
)
|
|
||||||
);
|
);
|
||||||
clients.values().for_each(|c| _ = c.tx.send(payload.clone()));
|
clients.values().for_each(|c| _ = c.tx.send(payload.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_bye(id: Option<u64>) {
|
async fn handle_bye(id: u64, mut rx: UnboundedReceiver<String>, mut writer: ClientWriter) {
|
||||||
let mut clients = CLIENTS.write();
|
while let Ok(payload) = rx.try_recv() {
|
||||||
if id.and_then(|id| clients.remove(&id)).is_some() {
|
if writer.write_all(payload.as_bytes()).await.is_err() {
|
||||||
Self::handle_hey(&clients);
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = writer
|
||||||
|
.write_all(BodyBye::owned().with_receiver(id).with_sender(0).to_string().as_bytes())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
writer.flush().await.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
tokio-util = "0.7.11"
|
tokio-util = "0.7.11"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@ md-5 = "0.10.6"
|
||||||
mlua = { version = "0.9.8", features = [ "lua54", "serialize", "macros", "async" ] }
|
mlua = { version = "0.9.8", features = [ "lua54", "serialize", "macros", "async" ] }
|
||||||
parking_lot = "0.12.3"
|
parking_lot = "0.12.3"
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
serde = "1.0.202"
|
serde = "1.0.203"
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.117"
|
||||||
shell-escape = "0.1.5"
|
shell-escape = "0.1.5"
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.15"
|
tokio-stream = "0.1.15"
|
||||||
tokio-util = "0.7.11"
|
tokio-util = "0.7.11"
|
||||||
unicode-width = "0.1.12"
|
unicode-width = "0.1.12"
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,4 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||||
# External dependencies
|
# External dependencies
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
mlua = { version = "0.9.8", features = [ "lua54" ] }
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ async-priority-channel = "0.2.0"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
parking_lot = "0.12.3"
|
parking_lot = "0.12.3"
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ parking_lot = "0.12.3"
|
||||||
percent-encoding = "2.3.1"
|
percent-encoding = "2.3.1"
|
||||||
ratatui = "0.26.3"
|
ratatui = "0.26.3"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
serde = { version = "1.0.202", features = [ "derive" ] }
|
serde = { version = "1.0.203", features = [ "derive" ] }
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
tokio = { version = "1.38.0", features = [ "full" ] }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
tracing = { version = "0.1.40", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue