makepad_platform/event/
network.rs

1use crate::makepad_micro_serde::*;
2use crate::makepad_live_id::*;
3use std::sync::mpsc::{channel, Receiver, Sender};
4use std::collections::BTreeMap;
5use std::str;
6
7#[derive(Clone, Debug)]
8pub struct NetworkResponseItem{
9    pub request_id: LiveId,
10    pub response: NetworkResponse,
11}
12
13pub type NetworkResponsesEvent = Vec<NetworkResponseItem>;
14
15#[derive(Clone, Debug)]
16pub struct HttpError{
17    pub message: String,
18    pub metadata_id: LiveId
19}
20
21
22#[derive(Clone, Debug)]
23pub struct HttpProgress{
24    pub loaded:u64, 
25    pub total:u64,
26}
27
28#[derive(Clone, Debug)]
29pub enum NetworkResponse{
30    HttpRequestError(HttpError),
31    HttpResponse(HttpResponse),
32    HttpStreamResponse(HttpResponse),
33    HttpStreamComplete(HttpResponse),
34    HttpProgress(HttpProgress),
35}
36/*
37pub struct NetworkResponseIter<I> {
38    iter: Option<I>,
39}
40*/
41/*
42impl<I> Iterator for NetworkResponseIter<I> where I: Iterator {
43    type Item = I::Item;
44    
45    fn next(&mut self) -> Option<I::Item> {
46        match &mut self.iter{
47            None=>None,
48            Some(v)=>v.next()
49        }
50    }
51}*/
52
53pub struct NetworkResponseChannel {
54    pub receiver: Receiver<NetworkResponseItem>,
55    pub sender: Sender<NetworkResponseItem>,
56}
57
58impl Default for NetworkResponseChannel {
59    fn default() -> Self {
60        let (sender, receiver) = channel();
61        Self {
62            sender,
63            receiver
64        }
65    }
66}
67
68
69#[derive(PartialEq, Debug)]
70pub struct HttpRequest {
71    pub metadata_id: LiveId,
72    pub url: String,
73    pub method: HttpMethod,
74    pub headers: BTreeMap<String, Vec<String>>,
75    pub ignore_ssl_cert: bool,
76    pub is_streaming: bool,
77    pub body: Option<Vec<u8>>,
78}
79
80#[derive(Debug)]
81pub struct SplitUrl<'a>{
82    pub proto: &'a str,
83    pub host: &'a str,
84    pub port: &'a str,
85    pub file: &'a str,
86    pub hash: &'a str,
87}
88
89impl HttpRequest { 
90    pub fn new(url: String, method: HttpMethod) -> Self {
91        HttpRequest {
92            metadata_id: LiveId(0),
93            url,
94            method,
95            is_streaming: false,
96            ignore_ssl_cert: false,
97            headers: BTreeMap::new(),
98            body: None
99        }
100    }
101
102    pub fn split_url(&self)->SplitUrl{
103        let (proto, rest) = self.url.split_once("://").unwrap_or((&self.url, "http://"));
104        let (host, port, rest) = if let Some((host, rest)) = rest.split_once(":"){
105            let (port, rest) = rest.split_once("/").unwrap_or((rest, ""));
106            (host, port, rest)
107        }
108        else{
109            let (host, rest) = rest.split_once("/").unwrap_or((rest, ""));
110            (host,match proto{
111                "http"|"ws"=>"80",
112                "https"|"wss"=>"443",
113                _=>"80"
114            },rest)
115        };
116        let (file, hash) = rest.split_once("#").unwrap_or((rest, ""));
117        return SplitUrl{
118            proto,
119            host,
120            port,
121            file, 
122            hash
123        }
124    }
125    
126    pub fn set_ignore_ssl_cert(&mut self){
127        self.ignore_ssl_cert = true
128    }
129    
130    pub fn set_is_streaming(&mut self){
131        self.is_streaming = true
132    }
133    
134    pub fn set_metadata_id(&mut self, id: LiveId){
135        self.metadata_id = id;
136    }
137    
138    pub fn set_header(&mut self, name: String, value: String) {
139        let entry = self.headers.entry(name).or_insert(Vec::new());
140        entry.push(value);
141    }
142
143    pub fn get_headers_string(&self) -> String {
144        let mut headers_string = String::new();
145        for (key, value) in self.headers.iter() {
146            headers_string.push_str(&format!("{}: {}\r\n", key, value.join(",")));
147        }
148        headers_string
149    }
150
151    pub fn set_body(&mut self, body: Vec<u8>) {
152        self.body = Some(body);
153    }
154
155    pub fn set_body_string(&mut self, v: &str) {
156        self.body = Some(v.as_bytes().to_vec());
157    }
158
159    pub fn set_json_body<T: SerJson>(&mut self, body: T) {
160       let json_body = body.serialize_json();
161       let serialized_body = json_body.into_bytes();
162       self.body = Some(serialized_body); 
163    }
164
165    pub fn set_string_body(&mut self, body: String) {
166        self.body = Some(body.into_bytes());
167    }
168}
169
170#[derive(Debug, Clone)]
171pub struct HttpResponse {
172    pub metadata_id: LiveId,
173    pub status_code: u16,
174    pub headers: BTreeMap<String, Vec<String>>,
175    pub body: Option<Vec<u8>>,
176}
177
178impl HttpResponse {
179    pub fn new(metadata_id: LiveId, status_code: u16, string_headers: String, body: Option<Vec<u8>>) -> Self {
180        HttpResponse {
181            metadata_id,
182            status_code,
183            headers: HttpResponse::parse_headers(string_headers),
184            body
185        }
186    }
187
188    pub fn set_header(&mut self, name: String, value: String) {
189        let entry = self.headers.entry(name).or_insert(Vec::new());
190        entry.push(value);
191    }
192
193    pub fn get_body(&self) -> Option<&Vec<u8>> {
194        self.body.as_ref()
195    }
196
197    pub fn get_string_body(&self) -> Option<String> {
198        if let Some(body) = self.body.as_ref() {
199            if let Ok(utf8) = String::from_utf8(body.to_vec()){
200                return Some(utf8)
201            }
202        }
203        None
204    }
205
206    // Todo: a more generic function that supports serialization into rust structs from other MIME types
207    pub fn get_json_body<T: DeJson>(&self) -> Result<T, DeJsonErr> { 
208        if let Some(body) = self.body.as_ref() {
209            let json = str::from_utf8(&body).unwrap();
210            DeJson::deserialize_json(&json)
211        } else {
212            Err(DeJsonErr{
213                msg:"No body present".to_string(),
214                line:0,
215                col:0
216            })
217        }
218    }
219
220    fn parse_headers(headers_string: String) -> BTreeMap<String, Vec<String>> {
221        let mut headers = BTreeMap::new();
222        for line in headers_string.lines() {
223            let mut split = line.split(":");
224            let key = split.next().unwrap();
225            let values = split.next().unwrap().to_string();
226            for val in values.split(",") {
227                let entry = headers.entry(key.to_string()).or_insert(Vec::new());
228                entry.push(val.to_string());
229            }
230        }
231        headers
232    }
233}
234
235#[derive(PartialEq, Debug)]
236pub enum HttpMethod{
237    GET,
238    HEAD,
239    POST,
240    PUT,
241    DELETE,
242    CONNECT,
243    OPTIONS,
244    TRACE,
245    PATCH
246}
247
248impl HttpMethod {
249    pub fn to_string(&self) -> &str {
250        match self {
251            Self::GET => "GET",
252            Self::HEAD => "HEAD",
253            Self::POST => "POST",
254            Self::PUT => "PUT",
255            Self::DELETE => "DELETE",
256            Self::CONNECT => "CONNECT",
257            Self::OPTIONS => "OPTIONS",
258            Self::TRACE => "TRACE",
259            Self::PATCH => "PATCH",
260        }
261    }
262}