use std::sync::Arc;
use microsandbox_control_client::{
CheckedControlRequest, ControlClientError, ControlConnection, ErrorKind,
};
use super::registry::{Entry, SharedError};
#[derive(Clone)]
pub(crate) struct ControlSession {
pub(super) entry: Arc<Entry>,
connection: ControlConnection,
}
impl ControlSession {
pub(super) fn new(entry: Arc<Entry>, connection: ControlConnection) -> Self {
Self { entry, connection }
}
pub fn capabilities(&self) -> microsandbox_control_client::Capabilities {
*self.connection.capabilities()
}
#[cfg(test)]
pub(super) fn mode(&self) -> microsandbox_control_client::ControlMode {
self.connection.mode()
}
pub async fn request<R: CheckedControlRequest>(
&self,
request: &R,
) -> Result<R::Response, SharedError> {
if self.entry.invalidated.is_cancelled() {
return Err(Arc::new(ControlClientError::RuntimeChanged));
}
match self.connection.request_typed(request).await {
Ok(response) => Ok(response),
Err(error) => {
let invalidate = match &error {
ControlClientError::Client(error) => matches!(
error.kind,
ErrorKind::Closed
| ErrorKind::PeerClosed
| ErrorKind::TruncatedFrame
| ErrorKind::Io(_)
| ErrorKind::Timeout
| ErrorKind::InvalidData
),
ControlClientError::RuntimeChanged
| ControlClientError::InvalidJsonResponse { .. }
| ControlClientError::InvalidResponse { .. } => true,
_ => false,
};
let error = Arc::new(error);
if invalidate {
self.entry.invalidate(error.clone());
self.connection.close().await;
}
Err(error)
}
}
}
}