#![forbid(unsafe_code)]
use super::{Connection, Error, Response, Result};
use std::io::ErrorKind;
enum EstablishedSessionState {
Exited(Option<u32>),
TtyAllocFail,
}
#[derive(Debug)]
pub struct EstablishedSession {
pub(super) conn: Connection,
pub(super) session_id: u32,
}
impl EstablishedSession {
fn check_session_id(&self, session_id: u32) -> Result<()> {
if self.session_id != session_id {
Err(Error::UnmatchedSessionId)
} else {
Ok(())
}
}
async fn wait_impl(&mut self) -> Result<EstablishedSessionState> {
use Response::*;
let response = match self.conn.read_response().await {
Result::Ok(response) => response,
Err(err) => match &err {
Error::IOError(io_err) if io_err.kind() == ErrorKind::UnexpectedEof => {
return Result::Ok(EstablishedSessionState::Exited(None))
}
_ => return Err(err),
},
};
match response {
TtyAllocFail { session_id } => {
self.check_session_id(session_id)?;
Result::Ok(EstablishedSessionState::TtyAllocFail)
}
ExitMessage {
session_id,
exit_value,
} => {
self.check_session_id(session_id)?;
Result::Ok(EstablishedSessionState::Exited(Some(exit_value)))
}
response => Err(Error::InvalidServerResponse(
"Expected Response TtyAllocFail or ExitMessage",
response,
)),
}
}
pub async fn wait(mut self) -> Result<SessionStatus, (Error, Self)> {
use EstablishedSessionState::*;
match self.wait_impl().await {
Ok(Exited(exit_value)) => Ok(SessionStatus::Exited { exit_value }),
Ok(TtyAllocFail) => Ok(SessionStatus::TtyAllocFail(self)),
Err(err) => Err((err, self)),
}
}
}
#[derive(Debug)]
pub enum SessionStatus {
TtyAllocFail(EstablishedSession),
Exited { exit_value: Option<u32> },
}