use std::ffi::OsStr;
use std::io;
use std::time::Duration;
use derive_more::{From, TryInto};
use tokio::net::windows::named_pipe::{ClientOptions, NamedPipeClient, NamedPipeServer};
const ERROR_PIPE_BUSY: u32 = 231;
const BUSY_PIPE_SLEEP_DURATION: Duration = Duration::from_millis(50);
#[derive(From, TryInto)]
pub enum NamedPipe {
Client(NamedPipeClient),
Server(NamedPipeServer),
}
impl NamedPipe {
pub fn is_client(&self) -> bool {
matches!(self, Self::Client(_))
}
pub fn as_client(&self) -> Option<&NamedPipeClient> {
match self {
Self::Client(x) => Some(x),
_ => None,
}
}
pub fn as_mut_client(&mut self) -> Option<&mut NamedPipeClient> {
match self {
Self::Client(x) => Some(x),
_ => None,
}
}
pub fn into_client(self) -> Option<NamedPipeClient> {
match self {
Self::Client(x) => Some(x),
_ => None,
}
}
pub fn is_server(&self) -> bool {
matches!(self, Self::Server(_))
}
pub fn as_server(&self) -> Option<&NamedPipeServer> {
match self {
Self::Server(x) => Some(x),
_ => None,
}
}
pub fn as_mut_server(&mut self) -> Option<&mut NamedPipeServer> {
match self {
Self::Server(x) => Some(x),
_ => None,
}
}
pub fn into_server(self) -> Option<NamedPipeServer> {
match self {
Self::Server(x) => Some(x),
_ => None,
}
}
pub(super) async fn connect_as_client(addr: &OsStr) -> io::Result<Self> {
let pipe = loop {
match ClientOptions::new().open(addr) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
Err(e) => return Err(e),
}
tokio::time::sleep(BUSY_PIPE_SLEEP_DURATION).await;
};
Ok(NamedPipe::from(pipe))
}
}