Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: Reader/Writer support, ability to split to Reader and Writer (maybe also Full-Duplex) #70

Open
yanshay opened this issue Jan 24, 2025 · 1 comment

Comments

@yanshay
Copy link
Contributor

yanshay commented Jan 24, 2025

I'm using picoserve as http server and it seem to require the ability to work with Reader and Writer (sammhicks/picoserve#71).

I saw in #59 reference to full-duplex which probably covers this. I don't think picoserve needs full-duplex, just need separate writer/reader.

Submitting the issue as a reminder. Will look into this myself though probably beyond my understanding of this crate.

@yanshay
Copy link
Contributor Author

yanshay commented Jan 27, 2025

Not a proper solution and not full duplex, but the below allow using picoserve with esp-mbedtls as is, in case someone needs to.

Not all capabilities there will work, just the simple stuff.

pub struct SessionWrapper<'a> {
    session: Rc<Mutex<NoopRawMutex, Session<'a, TcpSocket<'a>>>>,
}

impl<'a,'s> SessionWrapper<'s>
where
    's: 'a
{
    pub fn new(session: Session<'s, TcpSocket<'s>>) -> Self {
        Self {
            session: Rc::new(Mutex::new(session))
        }
    }
}

// Reader

pub struct SessionReader<'a> {
    session: Rc<Mutex<NoopRawMutex, Session<'a, TcpSocket<'a>>>>
}

impl<'a> embedded_io_async::ErrorType for SessionReader<'a> {
    type Error = TlsError;
}

impl<'a> embedded_io_async::Read for SessionReader<'a> {
    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        let mut session = self.session.lock().await;
        let res = session.read(buf).await;
        res
    }
}

// Writer

pub struct SessionWriter<'a>
{
        session: Rc<Mutex<NoopRawMutex, Session<'a, TcpSocket<'a>>>>,
}

impl<'a> embedded_io_async::ErrorType for SessionWriter<'a>
{
    type Error = TlsError;
}

impl<'a> embedded_io_async::Write for SessionWriter<'a>
{
    async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
        let mut session = self.session.lock().await;
        let res = session.write(buf).await;
        res
    }

    async fn flush(&mut self) -> Result<(), Self::Error> {
        let mut session = self.session.lock().await;
        let res = session.flush().await;
        res
    }
}

// Implement picoserve Socket on SessionWrapper

impl <'s> picoserve::io::Socket for SessionWrapper<'s>{
    type Error = TlsError;
    type ReadHalf<'a> = SessionReader<'s> where 's: 'a;
    type WriteHalf<'a> = SessionWriter<'s> where 's : 'a;

    fn split(&mut self) -> (Self::ReadHalf<'_>, Self::WriteHalf<'_>) {
        (
            SessionReader { session: self.session.clone() },
            SessionWriter { session: self.session.clone() },
        )
    }

    async fn shutdown<Timer: picoserve::Timer>(
        mut self,
        _timeouts: &picoserve::Timeouts<Timer::Duration>,
        _timer: &mut Timer,
    ) -> Result<(), picoserve::Error<Self::Error>> {
        Ok(())
    }
}

// Copied from picoserve since need to disable embassy feature of picoserve

struct EmbassyTimer;

impl picoserve::time::Timer for EmbassyTimer {
    type Duration = embassy_time::Duration;
    type TimeoutError = embassy_time::TimeoutError;

    async fn run_with_timeout<F: core::future::Future>(
        &mut self,
        duration: Self::Duration,
        future: F,
    ) -> Result<F::Output, Self::TimeoutError> {
        embassy_time::with_timeout(duration, future).await
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant