greetd_ipc: Split codecs into separate files
This commit is contained in:
45
greetd_ipc/src/codec/mod.rs
Normal file
45
greetd_ipc/src/codec/mod.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
//! Reader/writer codecs for Request/Response.
|
||||
//!
|
||||
//! This is implemented in the form of two traits, SyncCodec and TokioCodec,
|
||||
//! which operate on the `std` and `tokio` implementations of reader/writer
|
||||
//! traits. The former is intended as the name suggests for synchronous
|
||||
//! operation, while the latter is for asynchronous operation when using tokio.
|
||||
//!
|
||||
//! These codecs are hidden behind the `sync-codec` and `tokio-codec` features,
|
||||
//! respectively. These features also implicitly enable the `codec` feature,
|
||||
//! which controls the entire `codec` module.
|
||||
//!
|
||||
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum Error {
|
||||
#[error("serialization error: {0}")]
|
||||
Serialization(String),
|
||||
#[error("i/o error: {0}")]
|
||||
Io(String),
|
||||
#[error("EOF")]
|
||||
Eof,
|
||||
}
|
||||
|
||||
impl From<serde_json::error::Error> for Error {
|
||||
fn from(error: serde_json::error::Error) -> Self {
|
||||
Error::Serialization(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
Error::Io(format!("{}", error))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sync-codec")]
|
||||
mod sync;
|
||||
#[cfg(feature = "sync-codec")]
|
||||
pub use self::sync::SyncCodec;
|
||||
|
||||
#[cfg(feature = "tokio-codec")]
|
||||
mod tokio;
|
||||
#[cfg(feature = "tokio-codec")]
|
||||
pub use self::tokio::TokioCodec;
|
78
greetd_ipc/src/codec/sync.rs
Normal file
78
greetd_ipc/src/codec/sync.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
//! Synchronous reader/writer implementation, operating on an implementor of std::io::{Read, Write}.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::env;
|
||||
//! use std::os::unix::net::UnixStream;
|
||||
//! use greetd_ipc::{Request, Response};
|
||||
//! use greetd_ipc::codec::SyncCodec;
|
||||
//!
|
||||
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let mut stream = UnixStream::connect(env::var("GREETD_SOCK")?)?;
|
||||
//! Request::CreateSession { username: "john".to_string() }.write_to(&mut stream)?;
|
||||
//! let resp = Response::read_from(&mut stream)?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::{codec::Error, Request, Response};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Reader/writer implementation over std::io::{Read,Write}.
|
||||
pub trait SyncCodec {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl SyncCodec for Request {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut resp_buf = vec![0; len as usize];
|
||||
stream.read_exact(&mut resp_buf)?;
|
||||
serde_json::from_slice(&resp_buf).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes)?;
|
||||
stream.write_all(&body_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncCodec for Response {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut resp_buf = vec![0; len as usize];
|
||||
stream.read_exact(&mut resp_buf)?;
|
||||
serde_json::from_slice(&resp_buf).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes)?;
|
||||
stream.write_all(&body_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
101
greetd_ipc/src/codec/tokio.rs
Normal file
101
greetd_ipc/src/codec/tokio.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
//! Asynchronous reader/writer implementation, operating on an implementor of tokio::io::{AsyncReadExt, AsyncWriteExt}.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::env;
|
||||
//! use tokio::net::UnixStream;
|
||||
//! use greetd_ipc::{Request, Response};
|
||||
//! use greetd_ipc::codec::TokioCodec;
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let mut stream = UnixStream::connect(env::var("GREETD_SOCK")?).await?;
|
||||
//! Request::CreateSession { username: "john".to_string() }.write_to(&mut stream).await?;
|
||||
//! let resp = Response::read_from(&mut stream).await?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
use crate::{codec::Error, Request, Response};
|
||||
use async_trait::async_trait;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
/// Reader/writer implementation over tokio::io::{AsyncReadExt, AsyncWriteExt}.
|
||||
#[async_trait]
|
||||
pub trait TokioCodec {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TokioCodec for Request {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.await
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut body_bytes = vec![0; len as usize];
|
||||
stream.read_exact(&mut body_bytes).await?;
|
||||
let body = serde_json::from_slice(&body_bytes)?;
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes).await?;
|
||||
stream.write_all(&body_bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TokioCodec for Response {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.await
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut body_bytes = vec![0; len as usize];
|
||||
stream.read_exact(&mut body_bytes).await?;
|
||||
let body = serde_json::from_slice(&body_bytes)?;
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes).await?;
|
||||
stream.write_all(&body_bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -33,6 +33,10 @@
|
||||
//!
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "codec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "codec")))]
|
||||
pub mod codec;
|
||||
|
||||
/// A request from a greeter to greetd. The request type is internally tagged
|
||||
/// with the"type" field, with the type written in snake_case.
|
||||
///
|
||||
@@ -147,233 +151,3 @@ pub enum Response {
|
||||
auth_message: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// Reader/writer codecs for Request/Response.
|
||||
///
|
||||
/// This is implemented in the form of two traits, SyncCodec and TokioCodec,
|
||||
/// which operate on the `std` and `tokio` implementations of reader/writer
|
||||
/// traits. The former is intended as the name suggests for synchronous
|
||||
/// operation, while the latter is for asynchronous operation when using tokio.
|
||||
///
|
||||
/// These codecs are hidden behind the `sync-codec` and `tokio-codec` features,
|
||||
/// respectively. These features also implicitly enable the `codec` feature,
|
||||
/// which controls the entire `codec` module.
|
||||
///
|
||||
#[cfg(feature = "codec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "codec")))]
|
||||
pub mod codec {
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum Error {
|
||||
#[error("serialization error: {0}")]
|
||||
Serialization(String),
|
||||
#[error("i/o error: {0}")]
|
||||
Io(String),
|
||||
#[error("EOF")]
|
||||
Eof,
|
||||
}
|
||||
|
||||
impl From<serde_json::error::Error> for Error {
|
||||
fn from(error: serde_json::error::Error) -> Self {
|
||||
Error::Serialization(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
Error::Io(format!("{}", error))
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous reader/writer implementation, operating on an implementor of std::io::{Read, Write}.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::env;
|
||||
/// use std::os::unix::net::UnixStream;
|
||||
/// use greetd_ipc::{Request, Response};
|
||||
/// use greetd_ipc::codec::SyncCodec;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let mut stream = UnixStream::connect(env::var("GREETD_SOCK")?)?;
|
||||
/// Request::CreateSession { username: "john".to_string() }.write_to(&mut stream)?;
|
||||
/// let resp = Response::read_from(&mut stream)?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "sync-codec")]
|
||||
mod sync_codec {
|
||||
use crate::{codec::Error, Request, Response};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
/// Reader/writer implementation over std::io::{Read,Write}.
|
||||
pub trait SyncCodec {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl SyncCodec for Request {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut resp_buf = vec![0; len as usize];
|
||||
stream.read_exact(&mut resp_buf)?;
|
||||
serde_json::from_slice(&resp_buf).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes)?;
|
||||
stream.write_all(&body_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncCodec for Response {
|
||||
fn read_from<T: Read>(stream: &mut T) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut resp_buf = vec![0; len as usize];
|
||||
stream.read_exact(&mut resp_buf)?;
|
||||
serde_json::from_slice(&resp_buf).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn write_to<T: Write>(&self, stream: &mut T) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes)?;
|
||||
stream.write_all(&body_bytes)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "sync-codec")]
|
||||
pub use sync_codec::SyncCodec;
|
||||
|
||||
/// Asynchronous reader/writer implementation, operating on an implementor of tokio::io::{AsyncReadExt, AsyncWriteExt}.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::env;
|
||||
/// use tokio::net::UnixStream;
|
||||
/// use greetd_ipc::{Request, Response};
|
||||
/// use greetd_ipc::codec::TokioCodec;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let mut stream = UnixStream::connect(env::var("GREETD_SOCK")?).await?;
|
||||
/// Request::CreateSession { username: "john".to_string() }.write_to(&mut stream).await?;
|
||||
/// let resp = Response::read_from(&mut stream).await?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "tokio-codec")]
|
||||
mod tokio_codec {
|
||||
use crate::{codec::Error, Request, Response};
|
||||
use async_trait::async_trait;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
/// Reader/writer implementation over tokio::io::{AsyncReadExt, AsyncWriteExt}.
|
||||
#[async_trait]
|
||||
pub trait TokioCodec {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
Self: std::marker::Sized;
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TokioCodec for Request {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.await
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut body_bytes = vec![0; len as usize];
|
||||
stream.read_exact(&mut body_bytes).await?;
|
||||
let body = serde_json::from_slice(&body_bytes)?;
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes).await?;
|
||||
stream.write_all(&body_bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TokioCodec for Response {
|
||||
async fn read_from<T: AsyncReadExt + std::marker::Unpin + Send>(
|
||||
stream: &mut T,
|
||||
) -> Result<Self, Error> {
|
||||
let mut len_bytes = [0; 4];
|
||||
stream
|
||||
.read_exact(&mut len_bytes)
|
||||
.await
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => Error::Eof,
|
||||
_ => e.into(),
|
||||
})?;
|
||||
let len = u32::from_ne_bytes(len_bytes);
|
||||
|
||||
let mut body_bytes = vec![0; len as usize];
|
||||
stream.read_exact(&mut body_bytes).await?;
|
||||
let body = serde_json::from_slice(&body_bytes)?;
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
async fn write_to<T: AsyncWriteExt + std::marker::Unpin + Send>(
|
||||
&self,
|
||||
stream: &mut T,
|
||||
) -> Result<(), Error> {
|
||||
let body_bytes = serde_json::to_vec(self)?;
|
||||
let len_bytes = (body_bytes.len() as u32).to_ne_bytes();
|
||||
stream.write_all(&len_bytes).await?;
|
||||
stream.write_all(&body_bytes).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio-codec")]
|
||||
pub use tokio_codec::TokioCodec;
|
||||
}
|
||||
|
Reference in New Issue
Block a user