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};
|
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
|
/// A request from a greeter to greetd. The request type is internally tagged
|
||||||
/// with the"type" field, with the type written in snake_case.
|
/// with the"type" field, with the type written in snake_case.
|
||||||
///
|
///
|
||||||
@@ -147,233 +151,3 @@ pub enum Response {
|
|||||||
auth_message: String,
|
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