use autofork_core::config::Paths;
use tokio::io::{AsyncRead, AsyncWrite};
pub trait Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static {}
impl<T: AsyncRead + AsyncWrite + Unpin + Send + 'static> Stream for T {}
#[cfg(unix)]
pub use unix::Listener;
#[cfg(windows)]
pub use windows::Listener;
#[cfg(unix)]
mod unix {
use super::Paths;
use std::path::PathBuf;
use tokio::net::{UnixListener, UnixStream};
pub struct Listener {
inner: UnixListener,
path: PathBuf,
}
impl Listener {
pub fn bind(paths: &Paths) -> std::io::Result<Self> {
let path = paths.socket();
let _ = std::fs::remove_file(&path);
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let inner = UnixListener::bind(&path)?;
{
use std::os::unix::fs::PermissionsExt;
let _ = std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600));
}
Ok(Self { inner, path })
}
pub async fn accept(&mut self) -> std::io::Result<UnixStream> {
let (stream, _) = self.inner.accept().await?;
Ok(stream)
}
pub fn describe(&self) -> String {
self.path.display().to_string()
}
pub fn cleanup(paths: &Paths) {
let _ = std::fs::remove_file(paths.socket());
}
}
}
#[cfg(windows)]
mod windows {
use super::Paths;
use tokio::net::windows::named_pipe::{NamedPipeServer, ServerOptions};
pub struct Listener {
name: String,
server: NamedPipeServer,
}
impl Listener {
pub fn bind(paths: &Paths) -> std::io::Result<Self> {
let name = paths.pipe_name();
let server = ServerOptions::new()
.first_pipe_instance(true)
.create(&name)?;
Ok(Self { name, server })
}
pub async fn accept(&mut self) -> std::io::Result<NamedPipeServer> {
self.server.connect().await?;
let next = ServerOptions::new().create(&self.name)?;
Ok(std::mem::replace(&mut self.server, next))
}
pub fn describe(&self) -> String {
self.name.clone()
}
pub fn cleanup(_paths: &Paths) {}
}
}