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
use crate::debug_print_bytes;
use bytes::Bytes;
#[cfg(feature = "fp-bindgen")]
use fp_bindgen::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use typed_builder::TypedBuilder;

/// HTTP request options.
#[derive(Clone, Debug, Deserialize, Serialize, TypedBuilder)]
#[cfg_attr(
    feature = "fp-bindgen",
    derive(Serializable),
    fp(rust_module = "fiberplane_models::providers")
)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct HttpRequest {
    pub url: String,
    pub method: HttpRequestMethod,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub headers: Option<HashMap<String, String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub body: Option<Bytes>,
}

/// Possible errors that may happen during an HTTP request.
#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(
    feature = "fp-bindgen",
    derive(Serializable),
    fp(rust_module = "fiberplane_models::providers")
)]
#[non_exhaustive]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum HttpRequestError {
    Offline,
    NoRoute,
    ConnectionRefused,
    Timeout,
    ResponseTooBig,
    #[cfg_attr(feature = "fp-bindgen", fp(rename_all = "camelCase"))]
    ServerError {
        status_code: u16,
        response: Bytes,
    },
    #[cfg_attr(feature = "fp-bindgen", fp(rename_all = "camelCase"))]
    Other {
        reason: String,
    },
}

impl Debug for HttpRequestError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::Offline => f.write_str("Offline"),
            Self::NoRoute => f.write_str("NoRoute"),
            Self::ConnectionRefused => f.write_str("ConnectionRefused"),
            Self::Timeout => f.write_str("Timeout"),
            Self::ResponseTooBig => f.write_str("ResponseTooBig"),
            Self::ServerError {
                status_code,
                response,
            } => f
                .debug_struct("ServerError")
                .field("status_code", status_code)
                .field("response_length", &response.len())
                .field("response", &debug_print_bytes(response))
                .finish(),
            Self::Other { reason } => f.debug_struct("Other").field("reason", reason).finish(),
        }
    }
}

/// HTTP request method.
// Note: we use SCREAMING_SNAKE_CASE here because this is
// effectively a constant
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(
    feature = "fp-bindgen",
    derive(Serializable),
    fp(rust_module = "fiberplane_models::providers")
)]
#[non_exhaustive]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum HttpRequestMethod {
    Delete,
    Get,
    Head,
    Post,
}

/// Response to an HTTP request.
#[derive(Clone, Deserialize, Serialize, TypedBuilder)]
#[cfg_attr(
    feature = "fp-bindgen",
    derive(Serializable),
    fp(rust_module = "fiberplane_models::providers")
)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct HttpResponse {
    pub body: Bytes,
    pub headers: HashMap<String, String>,
    pub status_code: u16,
}

impl Debug for HttpResponse {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("HttpResponse")
            .field("status_code", &self.status_code)
            .field("headers", &self.headers)
            .field("body_length", &self.body.len())
            .field("body", &debug_print_bytes(&self.body))
            .finish()
    }
}