use crate::utils::{is_client_error, is_server_error};
use crate::{Error, Result};
use soup::gio::prelude::{MemoryOutputStreamExt, OutputStreamExt};
use soup::{Message, MessageHeaders, Status, gio, glib};
#[derive(Debug)]
pub struct Response {
message: Message,
body: gio::InputStream,
io_priority: glib::Priority,
}
impl Response {
pub(crate) fn new(
message: Message,
body: gio::InputStream,
io_priority: glib::Priority,
) -> Self {
Self {
message,
body,
io_priority,
}
}
}
impl Response {
pub fn status(&self) -> Status {
self.message.status()
}
pub fn status_code(&self) -> u32 {
self.message.status_code()
}
pub fn uri(&self) -> glib::Uri {
self.message.uri().expect("URI to be set")
}
pub fn headers(&self) -> MessageHeaders {
self.message
.response_headers()
.expect("response headers to be set")
}
pub fn remote_addr(&self) -> Option<gio::SocketAddress> {
self.message.remote_address()
}
pub async fn bytes(self) -> Result<glib::Bytes> {
let output_stream = gio::MemoryOutputStream::new_resizable();
let flags =
gio::OutputStreamSpliceFlags::CLOSE_SOURCE | gio::OutputStreamSpliceFlags::CLOSE_TARGET;
output_stream
.splice_future(&self.body, flags, self.io_priority)
.await
.map_err(|error| Error::new_with_uri(error, self.message.uri()))?;
Ok(output_stream.steal_as_bytes())
}
pub async fn text(self) -> Result<String> {
let bytes = self.bytes().await?;
let text = String::from_utf8_lossy(&bytes);
Ok(text.into_owned())
}
#[cfg(feature = "json")]
pub async fn json<T>(self) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let uri = self.message.uri();
let bytes = self.bytes().await?;
json::from_slice(&bytes).map_err(|error| Error::new_with_uri(error, uri))
}
pub fn error_for_status(self) -> Result<Self> {
let status_code = self.message.status_code();
if is_client_error(status_code) || is_server_error(status_code) {
Err(Error::new_status(self.message()))
} else {
Ok(self)
}
}
pub fn error_for_status_ref(&self) -> Result<&Self> {
let status_code = self.message.status_code();
if is_client_error(status_code) || is_server_error(status_code) {
Err(Error::new_status(self.message()))
} else {
Ok(self)
}
}
pub fn message(&self) -> &Message {
&self.message
}
pub fn split(self) -> (Message, gio::InputStream) {
(self.message, self.body)
}
}