diff --git a/src/sock.rs b/src/sock.rs index e6866fa..30b9b1b 100644 --- a/src/sock.rs +++ b/src/sock.rs @@ -1,6 +1,7 @@ //! Socket handling use super::*; use std::str; +use std::io; use std::path::{ Path, PathBuf }; @@ -31,6 +32,25 @@ pub enum SocketAddr IP(std::net::SocketAddr), } +impl TryFrom for SocketAddrUnix +{ + type Error = AddrParseError; + + fn try_from(from: tokio::net::unix::SocketAddr) -> Result + { + from.as_pathname().ok_or(AddrParseError).map(|path| Self{path: path.into()}) + } +} + +impl From for SocketAddr +{ + fn from(from: SocketAddrUnix) -> Self + { + Self::Unix(from) + } +} + + impl From for SocketAddr { fn from(from: std::net::SocketAddr) -> Self @@ -62,3 +82,79 @@ impl str::FromStr for SocketAddr } } +#[derive(Debug)] +enum ListenerInner +{ + Unix(tokio::net::UnixListener), + Tcp(tokio::net::TcpListener), +} + +#[derive(Debug)] +enum StreamInner +{ + Unix(tokio::net::UnixStream), + Tcp(tokio::net::TcpStream), +} + +impl ListenerInner +{ + fn con_unix(sock: &SocketAddrUnix) -> io::Result + { + tokio::net::UnixListener::bind(&sock.path).map(Self::Unix) + } + async fn con_tcp(sock: &std::net::SocketAddr) -> io::Result + { + tokio::net::TcpListener::bind(sock).await.map(Self::Tcp) + } +} + +/// A connected socket. +//TODO: Stream::connect(), direct connection +#[derive(Debug)] +pub struct Stream(Box, SocketAddr); + +impl From<(tokio::net::UnixStream, tokio::net::unix::SocketAddr)> for Stream +{ + fn from((s, a): (tokio::net::UnixStream, tokio::net::unix::SocketAddr)) -> Self + { + Self(Box::new(StreamInner::Unix(s)), SocketAddrUnix::try_from(a).unwrap().into()) + } +} + +impl From<(tokio::net::TcpStream, std::net::SocketAddr)> for Stream +{ + fn from((s, a): (tokio::net::TcpStream, std::net::SocketAddr)) -> Self + { + Self(Box::new(StreamInner::Tcp(s)), a.into()) + } +} + +/// A network listener, for either a Unix socket or TCP socket. +#[derive(Debug)] +pub struct Listener(Box); + +impl Listener +{ + /// Bind to Unix socket or IP/port. + /// + /// Completes immediately when binding unix socket + pub async fn bind(sock: impl Into) -> io::Result + { + match sock.into() { + SocketAddr::Unix(ref unix) => ListenerInner::con_unix(unix).map(Box::new), + SocketAddr::IP(ref tcp) => ListenerInner::con_tcp(tcp).await.map(Box::new), + }.map(Self) + } + + /// Accept connection on this listener. + pub async fn accept(&self) -> io::Result + { + match self.0.as_ref() + { + ListenerInner::Unix(un) => un.accept().await.map(Into::into), + ListenerInner::Tcp(tcp) => tcp.accept().await.map(Into::into), + } + } +} + +//TODO: impl Stream