1use alloc::string::String;
2use alloc::vec::Vec;
3use num_enum::{IntoPrimitive, TryFromPrimitive};
4
5use super::ErrorCode;
6#[derive(scale::Encode, scale::Decode)]
7#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
8pub struct HttpRequest {
9 pub url: String,
10 pub method: String,
11 pub headers: Vec<(String, String)>,
12 pub body: Vec<u8>,
13}
14
15impl HttpRequest {
16 pub fn new(
18 url: impl Into<String>,
19 method: impl Into<String>,
20 headers: Vec<(String, String)>,
21 body: Vec<u8>,
22 ) -> Self {
23 Self {
24 url: url.into(),
25 method: method.into(),
26 headers,
27 body,
28 }
29 }
30}
31
32#[derive(scale::Encode, scale::Decode)]
33#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
34pub struct HttpResponse {
35 pub status_code: u16,
36 pub reason_phrase: String,
37 pub headers: Vec<(String, String)>,
38 pub body: Vec<u8>,
39}
40
41#[derive(
42 scale::Encode, scale::Decode, TryFromPrimitive, IntoPrimitive, Clone, Copy, Debug, PartialEq, Eq,
43)]
44#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
45#[repr(u32)]
46pub enum HttpRequestError {
47 InvalidUrl,
48 InvalidMethod,
49 InvalidHeaderName,
50 InvalidHeaderValue,
51 FailedToCreateClient,
52 Timeout,
53 NotAllowed,
54 TooManyRequests,
55 NetworkError,
56 ResponseTooLarge,
57}
58
59impl super::sealed::Sealed for HttpRequestError {}
60impl super::CodableError for HttpRequestError {
61 fn encode(&self) -> u32 {
62 let code: u32 = (*self).into();
63 code + 1
64 }
65
66 fn decode(code: u32) -> Option<Self> {
67 if code == 0 {
68 return None;
69 }
70 core::convert::TryFrom::try_from(code - 1).ok()
71 }
72}
73
74impl From<ErrorCode> for HttpRequestError {
75 fn from(value: ErrorCode) -> Self {
76 match <Self as super::CodableError>::decode(value.0) {
77 None => crate::panic!("chain extension: invalid HttpRequestError"),
78 Some(err) => err,
79 }
80 }
81}
82
83impl From<scale::Error> for HttpRequestError {
84 fn from(_value: scale::Error) -> Self {
85 crate::panic!("chain_ext: failed to decocde HttpRequestError")
86 }
87}
88
89impl HttpRequestError {
90 pub fn display(&self) -> &'static str {
91 match self {
92 Self::InvalidUrl => "Invalid URL",
93 Self::InvalidMethod => "Invalid method",
94 Self::InvalidHeaderName => "Invalid header name",
95 Self::InvalidHeaderValue => "Invalid header value",
96 Self::FailedToCreateClient => "Failed to create client",
97 Self::Timeout => "Timeout",
98 Self::NotAllowed => "Not allowed",
99 Self::TooManyRequests => "Too many requests",
100 Self::NetworkError => "Network error",
101 Self::ResponseTooLarge => "Response too large",
102 }
103 }
104}
105
106impl HttpResponse {
107 pub fn ok(body: Vec<u8>) -> Self {
108 Self {
109 status_code: 200,
110 reason_phrase: "OK".into(),
111 headers: Default::default(),
112 body,
113 }
114 }
115
116 pub fn not_found() -> Self {
117 Self {
118 status_code: 404,
119 reason_phrase: "Not Found".into(),
120 headers: Default::default(),
121 body: Default::default(),
122 }
123 }
124}
125
126#[macro_export]
127macro_rules! http_req {
128 ($method: expr, $url: expr, $data: expr, $headers: expr) => {{
129 use $crate::chain_extension::HttpRequest;
130 let headers = $headers;
131 let body = $data;
132 let request = HttpRequest {
133 url: $url.into(),
134 method: $method.into(),
135 headers,
136 body,
137 };
138 $crate::ext().http_request(request)
139 }};
140 ($method: expr, $url: expr, $data: expr) => {{
141 $crate::http_req!($method, $url, $data, Default::default())
142 }};
143}
144
145#[macro_export]
166macro_rules! http_get {
167 ($url: expr, $headers: expr) => {{
168 $crate::http_req!("GET", $url, Default::default(), $headers)
169 }};
170 ($url: expr) => {{
171 $crate::http_get!($url, Default::default())
172 }};
173}
174
175#[macro_export]
197macro_rules! http_post {
198 ($url: expr, $data: expr, $headers: expr) => {{
199 $crate::http_req!("POST", $url, $data.into(), $headers)
200 }};
201 ($url: expr, $data: expr) => {{
202 $crate::http_post!($url, $data, Default::default())
203 }};
204}
205
206#[macro_export]
221macro_rules! http_put {
222 ($url: expr, $data: expr, $headers: expr) => {{
223 $crate::http_req!("PUT", $url, $data.into(), $headers)
224 }};
225 ($url: expr, $data: expr) => {{
226 $crate::http_put!($url, $data, Default::default())
227 }};
228}