rh 0.1.14

A user-friendly command-line tool to request HTTP APis
Documentation
use super::{HeaderRender, Render, ResponseRender, DIRECTION_RESPONSE};
use crate::request::Response;
use crate::rh_name;
use crate::shell::json::JsonRender;
use crate::{core::Workspace, theme::Theme};
use content_inspector::inspect;
use serde_json::Value;
use std::cell::RefCell;
use std::io::Read;
use std::io::{Result, Write};

impl<'a> ResponseRender<'a> {
    pub fn new(workspace: &'a Workspace, response: RefCell<Response>, theme: &'a dyn Theme, style_enabled: bool) -> Self {
        Self {
            workspace,
            response,
            theme,
            style_enabled,
        }
    }
}

impl<'a> Render for ResponseRender<'a> {
    #[inline]
    fn write<W>(&self, writer: &mut W) -> Result<()>
    where
        W: Write,
    {
        let ws = self.workspace;
        let flags = ws.flags;
        if flags.show_response_status {
            if flags.show_direction {
                self.write_direction(writer, true)?;
            }
            self.write_version_and_status(writer)?;
        }
        if flags.show_response_headers {
            self.write_headers(writer)?;
        }
        if flags.show_response_body {
            self.write_body(writer)?;
        }
        Ok(())
    }

    #[inline]
    fn is_style_active(&self) -> bool {
        self.style_enabled
    }
}

impl<'a> ResponseRender<'a> {
    #[inline]
    fn write_direction<W: Write>(&self, writer: &mut W, is_standard: bool) -> Result<()> {
        self.write_with_style(writer, DIRECTION_RESPONSE, &self.theme.response().direction(is_standard))
    }

    #[inline]
    fn write_version_and_status<W: Write>(&self, writer: &mut W) -> Result<()> {
        let response = &self.response.borrow();
        let status = response.status();
        let theme = self.workspace.theme.response();

        let style = theme.version();
        let message = format!("{:?} ", response.version());
        self.write_with_style(writer, message.as_bytes(), &style)?;

        let style = theme.status();
        self.write_with_style(writer, status.as_str().as_bytes(), &style)?;
        writer.write_all(b" ")?;
        self.write_with_style(writer, status.canonical_reason().unwrap_or("Unknown").as_bytes(), &style)?;
        self.write_newline(writer)
    }

    #[inline]
    fn write_body<W: Write>(&self, writer: &mut W) -> Result<()> {
        let ws = self.workspace;
        let flags = ws.flags;
        let mut response = self.response.borrow_mut();

        let mut bytes = Vec::new();
        let size = response.read_to_end(&mut bytes).unwrap_or(0);
        let content_type = inspect(&bytes);
        if content_type.is_binary() {
            self.write_binary_usage(writer, size)?;
        } else {
            let body = String::from_utf8_lossy(&bytes);
            match serde_json::from_str::<Value>(&body) {
                Ok(json) => {
                    let json_render = JsonRender::new(&json, flags.show_response_compact, self.style_enabled);
                    json_render.write(writer)?;
                }
                Err(_) => {
                    writer.write_all(body.as_bytes())?;
                }
            }
        }
        self.write_newline(writer)
    }

    #[inline]
    fn write_binary_usage<W: Write>(&self, writer: &mut W, size: usize) -> Result<()> {
        let message = format!(
            "Binary data not shown in terminal\nContent size {}b\nTo copy the content in a file, you should try:\n{} > filename",
            size,
            rh_name!()
        );
        writer.write_all(message.as_bytes())?;
        self.write_newline(writer)?;
        Ok(())
    }

    #[inline]
    fn write_headers<W: Write>(&self, writer: &mut W) -> Result<()> {
        let response = self.response.borrow();
        let headers = response.headers();
        let response_theme = self.theme.response();
        let header_theme = response_theme.as_header();
        let direction_theme = response_theme.as_direction();
        let header_render = HeaderRender::new(self.workspace, headers, header_theme, direction_theme, DIRECTION_RESPONSE, self.style_enabled);
        header_render.write(writer)
    }
}