Skip to main content

mkit_server/ssh/
io.rs

1//! Blocking [`std::io`] frame adapters: `mkit-rpc`'s length-prefixed
2//! framing (`read_frame`, `write_frame`) over a reader and a writer.
3//!
4//! Each call does its blocking I/O inside the future and never yields, like
5//! the `fs` stores: correct under a blocking executor (the CLI's stdio
6//! path). They have no read deadline, so they never return
7//! [`FrameIoError::Timeout`].
8//!
9//! On native targets the stream must be `Send` (the session future is),
10//! and `std::io::StdinLock`/`StdoutLock` are not: pass `std::io::Stdin` and
11//! `std::io::Stdout` themselves, which lock per call; `write_frame`
12//! flushes after every frame.
13
14use std::io::{Read, Write};
15
16use mkit_rpc::mkit::rpc::v1::ssh::SshFrame;
17
18use super::session::{FrameIoError, FrameSink, FrameSource};
19use crate::rt::MaybeSend;
20
21/// A [`FrameSource`] over a blocking reader.
22#[derive(Debug)]
23pub struct ReadFrames<R>(pub R);
24
25impl<R: Read + MaybeSend> FrameSource for ReadFrames<R> {
26    async fn next_frame(&mut self) -> Result<SshFrame, FrameIoError> {
27        mkit_rpc::read_frame(&mut self.0).map_err(FrameIoError::from)
28    }
29}
30
31/// A [`FrameSink`] over a blocking writer; each frame is flushed.
32#[derive(Debug)]
33pub struct WriteFrames<W>(pub W);
34
35impl<W: Write + MaybeSend> FrameSink for WriteFrames<W> {
36    async fn send(&mut self, frame: &SshFrame) -> Result<(), FrameIoError> {
37        mkit_rpc::write_frame(&mut self.0, frame).map_err(FrameIoError::from)
38    }
39}