Skip to content

Commit 5fbb1a8

Browse files
committed
feat: add logging to TCP streams
1 parent 07ce319 commit 5fbb1a8

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

src/log.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use crate::context::Context;
66

7+
mod logging_stream;
8+
79
#[macro_export]
810
macro_rules! info {
911
($ctx:expr, $msg:expr) => {

src/log/logging_stream.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//! Stream that logs errors as events.
2+
//!
3+
//! This stream can be used to wrap IMAP,
4+
//! SMTP and HTTP streams so errors
5+
//! that occur are logged before
6+
//! they are processed.
7+
8+
use std::task::{Context, Poll};
9+
use std::pin::Pin;
10+
use std::time::Duration;
11+
12+
use pin_project::pin_project;
13+
14+
use crate::net::session::SessionStream;
15+
16+
use tokio::io::{AsyncWrite, AsyncRead, ReadBuf};
17+
18+
/// Stream that logs errors to the event channel.
19+
#[derive(Debug)]
20+
#[pin_project]
21+
pub struct LoggingStream<S: SessionStream> {
22+
#[pin]
23+
inner: S,
24+
25+
/// Name of the stream to distinguish log messages produced by it.
26+
name: String
27+
}
28+
29+
impl<S: SessionStream> LoggingStream<S> {
30+
pub fn new(inner: S, name: String) -> Self {
31+
Self {
32+
inner,
33+
name
34+
}
35+
}
36+
}
37+
38+
impl<S: SessionStream> AsyncRead for LoggingStream<S> {
39+
fn poll_read(
40+
self: Pin<&mut Self>,
41+
cx: &mut Context<'_>,
42+
buf: &mut ReadBuf<'_>,
43+
) -> Poll<std::io::Result<()>> {
44+
self.project().inner.poll_read(cx, buf)
45+
}
46+
}
47+
48+
impl<S: SessionStream> AsyncWrite for LoggingStream<S> {
49+
fn poll_write(
50+
self: Pin<&mut Self>,
51+
cx: &mut std::task::Context<'_>,
52+
buf: &[u8],
53+
) -> Poll<std::io::Result<usize>> {
54+
self.project().inner.poll_write(cx, buf)
55+
}
56+
57+
fn poll_flush(
58+
self: Pin<&mut Self>,
59+
cx: &mut std::task::Context<'_>,
60+
) -> Poll<std::io::Result<()>> {
61+
self.project().inner.poll_flush(cx)
62+
}
63+
64+
fn poll_shutdown(
65+
self: Pin<&mut Self>,
66+
cx: &mut std::task::Context<'_>,
67+
) -> Poll<std::io::Result<()>> {
68+
self.project().inner.poll_shutdown(cx)
69+
}
70+
71+
fn poll_write_vectored(
72+
self: Pin<&mut Self>,
73+
cx: &mut Context<'_>,
74+
bufs: &[std::io::IoSlice<'_>],
75+
) -> Poll<std::io::Result<usize>> {
76+
self.project().inner.poll_write_vectored(cx, bufs)
77+
}
78+
79+
fn is_write_vectored(&self) -> bool {
80+
self.inner.is_write_vectored()
81+
}
82+
}
83+
84+
impl<S: SessionStream> SessionStream for LoggingStream<S> {
85+
fn set_read_timeout(&mut self, timeout: Option<Duration>) {
86+
self.inner.set_read_timeout(timeout)
87+
}
88+
}

0 commit comments

Comments
 (0)