1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
pub mod info;
pub mod errors;

use curl::easy::{Easy, List};
use std::env::var;

pub use self::errors::DockerApiError;

#[derive(Debug, Clone)]
pub struct Response {
    pub status_code: usize,
    pub body: String,
}

pub enum Method {
    GET,
    POST,
    DELETE,
}

fn request(
    api_endpint: &str,
    method: Method,
    body_w: Option<&str>,
) -> Response {
    let unix_socket_url =
        var("DOCKERS_SOCKET_URL").unwrap_or("/var/run/docker.sock".to_owned());

    let mut e = Easy::new();
    let mut status_code: usize = 0;
    let mut body = Vec::new();
    let body_w = body_w.unwrap_or_default();

    e.unix_socket(&unix_socket_url).unwrap();

    e.url(&format!("http{}", api_endpint)).unwrap();
    let mut headers = List::new();

    headers.append("Content-Type: application/json").unwrap();

    e.http_headers(headers).unwrap();

    let _ = match method {
        Method::GET => e.get(true).unwrap(),
        Method::POST => {
            e.post(true).unwrap();
            e.post_fields_copy(body_w.as_bytes()).unwrap()
        }
        Method::DELETE => {
            e.custom_request("DELETE").unwrap();
        }
    };

    {
        let mut transfer = e.transfer();

        transfer
            .header_function(|h| {
                let header = String::from_utf8(h.to_vec())
                    .expect("Header to string failed");
                print!("header: {}", header);
                if status_code == 0 {
                    let parts: Vec<&str> = header.splitn(3, " ").collect();
                    if parts.len() > 1 {
                        status_code = parts[1]
                            .parse()
                            .expect("Cannot parse this string into usize");
                    }
                }
                true
            })
            .unwrap();

        transfer
            .write_function(|d| {
                body.extend_from_slice(d);

                Ok(d.len())
            })
            .unwrap();

        transfer.perform().unwrap();
    }

    let body = if body.is_empty() {
        "".to_owned()
    } else {
        String::from_utf8(body[..body.len() - 1].to_vec())
            .expect("Cannot parse vec to string")
    };

    println!("{}", body);

    Response {
        status_code: status_code.clone(),
        body,
    }
}

pub fn invalid_api_resp(res: Response) -> DockerApiError {
    DockerApiError::InvalidApiResponseError(res.status_code, res.body)
}

pub fn get_response_from_api_static(
    api_endpoint: &str,
    method: Method,
    query_params: Option<&str>,
    body: Option<&str>,
) -> Result<Response, DockerApiError> {
    let api_endpoint =
        format!("{}{}", api_endpoint, query_params.unwrap_or_default());

    Ok(request(&api_endpoint, method, body))
}

pub trait Client {
    fn get_response_from_api(
        &self,
        api_endpoint: &str,
        method: Method,
        query_params: Option<&str>,
        body: Option<&str>,
    ) -> Result<Response, DockerApiError> {
        let res: Result<Response, DockerApiError> =
            get_response_from_api_static(
                api_endpoint,
                method,
                query_params,
                body,
            );

        res
    }
}