mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 14:51:03 +00:00
101 lines
2.9 KiB
Rust
101 lines
2.9 KiB
Rust
use std::{io, path::PathBuf};
|
|
|
|
use tokio::{io::{AsyncBufReadExt, BufReader, Lines, ReadHalf, WriteHalf}, sync::OnceCell};
|
|
use yazi_fs::{Xdg, create_owned_dir, engine::{Engine, local::Local}};
|
|
|
|
pub struct Stream;
|
|
|
|
#[cfg(unix)]
|
|
pub type ClientReader = Lines<BufReader<ReadHalf<tokio::net::UnixStream>>>;
|
|
#[cfg(windows)]
|
|
pub type ClientReader = Lines<BufReader<ReadHalf<tokio::net::TcpStream>>>;
|
|
|
|
#[cfg(unix)]
|
|
pub(super) type ClientWriter = WriteHalf<tokio::net::UnixStream>;
|
|
#[cfg(windows)]
|
|
pub(super) type ClientWriter = WriteHalf<tokio::net::TcpStream>;
|
|
|
|
#[cfg(unix)]
|
|
pub(super) type ServerListener = tokio::net::UnixListener;
|
|
#[cfg(windows)]
|
|
pub(super) type ServerListener = WinUnixListener;
|
|
|
|
impl Stream {
|
|
#[cfg(unix)]
|
|
pub async fn connect() -> io::Result<(ClientReader, ClientWriter)> {
|
|
let stream = tokio::net::UnixStream::connect(Self::socket_file().await?).await?;
|
|
let (reader, writer) = tokio::io::split(stream);
|
|
Ok((BufReader::new(reader).lines(), writer))
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub async fn connect() -> io::Result<(ClientReader, ClientWriter)> {
|
|
let p = Self::socket_file().await?;
|
|
let uds = tokio::task::spawn_blocking(move || uds_windows::UnixStream::connect(p)).await??;
|
|
|
|
let (reader, writer) = tokio::io::split(WinUnixListener::into_tokio(uds)?);
|
|
Ok((BufReader::new(reader).lines(), writer))
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
pub(super) async fn bind() -> io::Result<ServerListener> {
|
|
let p = Self::socket_file().await?;
|
|
|
|
Local::regular(&p).remove_file().await.ok();
|
|
tokio::net::UnixListener::bind(p)
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub(super) async fn bind() -> io::Result<ServerListener> {
|
|
let p = Self::socket_file().await?;
|
|
Local::regular(&p).remove_file().await.ok();
|
|
|
|
let listener = uds_windows::UnixListener::bind(p)?;
|
|
listener.set_nonblocking(true)?;
|
|
|
|
Ok(WinUnixListener(listener))
|
|
}
|
|
|
|
async fn socket_file() -> io::Result<&'static PathBuf> {
|
|
static ONCE: OnceCell<PathBuf> = OnceCell::const_new();
|
|
ONCE
|
|
.get_or_try_init(|| async move {
|
|
let p = Xdg::runtime_dir();
|
|
create_owned_dir(p).await?;
|
|
|
|
Ok(p.join(".dds.sock"))
|
|
})
|
|
.await
|
|
}
|
|
}
|
|
|
|
// --- WinUnixListener
|
|
#[cfg(windows)]
|
|
pub(super) struct WinUnixListener(uds_windows::UnixListener);
|
|
|
|
#[cfg(windows)]
|
|
impl WinUnixListener {
|
|
pub(super) async fn accept(
|
|
&self,
|
|
) -> io::Result<(tokio::net::TcpStream, uds_windows::SocketAddr)> {
|
|
loop {
|
|
match self.0.accept() {
|
|
Ok((stream, addr)) => return Ok((Self::into_tokio(stream)?, addr)),
|
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
|
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
|
|
}
|
|
Err(e) => return Err(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn into_tokio(uds: uds_windows::UnixStream) -> io::Result<tokio::net::TcpStream> {
|
|
use std::os::windows::io::{FromRawSocket, IntoRawSocket};
|
|
|
|
let raw = uds.into_raw_socket();
|
|
let std = unsafe { std::net::TcpStream::from_raw_socket(raw) };
|
|
std.set_nonblocking(true)?;
|
|
|
|
tokio::net::TcpStream::from_std(std)
|
|
}
|
|
}
|