use std::time::Duration;
use shep_client::{Client, RequestError};
use shep_core::protocol::{Request, Response};
use crate::exit::ExitCode;
use crate::output::{Render, Streams, emit, write_outcome};
pub(crate) const UNRECOGNISED: &str =
"the daemon answered with a response this client does not understand";
pub(crate) fn unexpected_response(streams: &mut Streams<'_>) -> ExitCode {
streams.fail(ExitCode::Internal, UNRECOGNISED)
}
pub(crate) fn client_error(streams: &mut Streams<'_>, err: &RequestError) -> ExitCode {
streams.fail(ExitCode::from(err), &err.to_string())
}
pub(crate) async fn request_payload<T, F>(
client: &Client,
streams: &mut Streams<'_>,
body: Request,
deadline: Option<Duration>,
extract: F,
) -> Result<T, ExitCode>
where
F: FnOnce(Response) -> Option<T>,
{
match client.request_with_deadline(body, deadline).await {
Ok(response) => extract(response).ok_or_else(|| unexpected_response(streams)),
Err(err) => Err(client_error(streams, &err)),
}
}
pub(crate) async fn request_and_render<T, F>(
client: &Client,
streams: &mut Streams<'_>,
command: &str,
body: Request,
deadline: Option<Duration>,
extract: F,
) -> ExitCode
where
T: Render,
F: FnOnce(Response) -> Option<T>,
{
match request_payload(client, streams, body, deadline, extract).await {
Ok(payload) => write_outcome(emit(
&mut *streams.out,
streams.fmt,
command,
payload,
streams.style,
)),
Err(code) => code,
}
}