Skip to main content

windjammer_runtime/platform/native/
net.rs

1/// Native implementation of std::net using reqwest
2use reqwest::blocking::Client;
3use std::time::Duration;
4
5pub type NetResult<T> = Result<T, String>;
6
7/// HTTP Response
8#[derive(Debug, Clone)]
9pub struct Response {
10    pub status: i32,
11    pub headers: Vec<(String, String)>,
12    pub body: String,
13}
14
15/// HTTP Request builder
16#[derive(Debug, Clone)]
17pub struct Request {
18    pub url: String,
19    pub method: String,
20    pub headers: Vec<(String, String)>,
21    pub body: Option<String>,
22    pub timeout: Option<i32>,
23}
24
25impl Request {
26    /// Create a new GET request
27    pub fn get(url: String) -> Self {
28        Self {
29            url,
30            method: "GET".to_string(),
31            headers: Vec::new(),
32            body: None,
33            timeout: None,
34        }
35    }
36
37    /// Create a new POST request
38    pub fn post(url: String, body: String) -> Self {
39        Self {
40            url,
41            method: "POST".to_string(),
42            headers: Vec::new(),
43            body: Some(body),
44            timeout: None,
45        }
46    }
47
48    /// Add a header
49    pub fn header(mut self, key: String, value: String) -> Self {
50        self.headers.push((key, value));
51        self
52    }
53
54    /// Set timeout in seconds
55    pub fn timeout(mut self, seconds: i32) -> Self {
56        self.timeout = Some(seconds);
57        self
58    }
59
60    /// Send the request (blocking)
61    pub fn send(self) -> NetResult<Response> {
62        let client = Client::builder()
63            .timeout(
64                self.timeout
65                    .map(|s| Duration::from_secs(s as u64))
66                    .unwrap_or(Duration::from_secs(30)),
67            )
68            .build()
69            .map_err(|e| format!("Failed to create HTTP client: {}", e))?;
70
71        let mut request = match self.method.as_str() {
72            "GET" => client.get(&self.url),
73            "POST" => client.post(&self.url),
74            "PUT" => client.put(&self.url),
75            "DELETE" => client.delete(&self.url),
76            "PATCH" => client.patch(&self.url),
77            _ => return Err(format!("Unsupported HTTP method: {}", self.method)),
78        };
79
80        // Add headers
81        for (key, value) in self.headers {
82            request = request.header(&key, &value);
83        }
84
85        // Add body if present
86        if let Some(body) = self.body {
87            request = request.body(body);
88        }
89
90        // Send request
91        let response = request
92            .send()
93            .map_err(|e| format!("HTTP request failed: {}", e))?;
94
95        // Extract status
96        let status = response.status().as_u16() as i32;
97
98        // Extract headers
99        let headers: Vec<(String, String)> = response
100            .headers()
101            .iter()
102            .filter_map(
103                |(k, v): (&reqwest::header::HeaderName, &reqwest::header::HeaderValue)| {
104                    v.to_str()
105                        .ok()
106                        .map(|v_str: &str| (k.as_str().to_string(), v_str.to_string()))
107                },
108            )
109            .collect();
110
111        // Extract body
112        let body: String = response
113            .text()
114            .map_err(|e| format!("Failed to read response body: {}", e))?;
115
116        Ok(Response {
117            status,
118            headers,
119            body,
120        })
121    }
122
123    /// Send the request asynchronously
124    pub async fn send_async(self) -> NetResult<Response> {
125        let client = reqwest::Client::builder()
126            .timeout(
127                self.timeout
128                    .map(|s| Duration::from_secs(s as u64))
129                    .unwrap_or(Duration::from_secs(30)),
130            )
131            .build()
132            .map_err(|e| format!("Failed to create HTTP client: {}", e))?;
133
134        let mut request = match self.method.as_str() {
135            "GET" => client.get(&self.url),
136            "POST" => client.post(&self.url),
137            "PUT" => client.put(&self.url),
138            "DELETE" => client.delete(&self.url),
139            "PATCH" => client.patch(&self.url),
140            _ => return Err(format!("Unsupported HTTP method: {}", self.method)),
141        };
142
143        // Add headers
144        for (key, value) in self.headers {
145            request = request.header(&key, &value);
146        }
147
148        // Add body if present
149        if let Some(body) = self.body {
150            request = request.body(body);
151        }
152
153        // Send request
154        let response: reqwest::Response = request
155            .send()
156            .await
157            .map_err(|e: reqwest::Error| format!("HTTP request failed: {}", e))?;
158
159        // Extract status
160        let status = response.status().as_u16() as i32;
161
162        // Extract headers
163        let headers: Vec<(String, String)> = response
164            .headers()
165            .iter()
166            .filter_map(
167                |(k, v): (&reqwest::header::HeaderName, &reqwest::header::HeaderValue)| {
168                    v.to_str()
169                        .ok()
170                        .map(|v_str: &str| (k.as_str().to_string(), v_str.to_string()))
171                },
172            )
173            .collect();
174
175        // Extract body
176        let body: String = response
177            .text()
178            .await
179            .map_err(|e: reqwest::Error| format!("Failed to read response body: {}", e))?;
180
181        Ok(Response {
182            status,
183            headers,
184            body,
185        })
186    }
187}
188
189/// Simple GET request (blocking)
190pub fn get(url: String) -> NetResult<Response> {
191    Request::get(url).send()
192}
193
194/// Simple POST request (blocking)
195pub fn post(url: String, body: String) -> NetResult<Response> {
196    Request::post(url, body).send()
197}
198
199/// Async GET request
200pub async fn get_async(url: String) -> NetResult<Response> {
201    Request::get(url).send_async().await
202}
203
204/// Async POST request
205pub async fn post_async(url: String, body: String) -> NetResult<Response> {
206    Request::post(url, body).send_async().await
207}
208
209/// Download a file
210pub fn download(url: String, path: String) -> NetResult<()> {
211    let response = get(url)?;
212    std::fs::write(&path, response.body).map_err(|e| format!("Failed to write file: {}", e))?;
213    Ok(())
214}
215
216/// Upload a file
217pub fn upload(url: String, path: String) -> NetResult<Response> {
218    let body = std::fs::read_to_string(&path).map_err(|e| format!("Failed to read file: {}", e))?;
219    post(url, body)
220}
221
222// WebSocket support would require tokio-tungstenite
223// For now, we'll provide a stub
224pub struct WebSocket;
225
226impl WebSocket {
227    pub fn connect(_url: String) -> NetResult<WebSocket> {
228        Err("WebSocket support requires tokio-tungstenite (not yet implemented)".to_string())
229    }
230
231    pub fn send(&self, _message: String) -> NetResult<()> {
232        Err("WebSocket not connected".to_string())
233    }
234
235    pub fn receive(&self) -> NetResult<String> {
236        Err("WebSocket not connected".to_string())
237    }
238
239    pub fn close(self) -> NetResult<()> {
240        Ok(())
241    }
242}
243
244// ============================================================================
245// HTTP SERVER IMPLEMENTATION
246// ============================================================================
247
248use std::io::{Read, Write};
249use std::net::{TcpListener, TcpStream};
250
251/// HTTP Server Request (received by server)
252#[derive(Debug, Clone)]
253pub struct ServerRequest {
254    pub method: String,
255    pub path: String,
256    pub headers: Vec<(String, String)>,
257    pub body: String,
258}
259
260/// HTTP Server Response (sent by server)
261#[derive(Debug, Clone)]
262pub struct ServerResponse {
263    pub status: i32,
264    pub headers: Vec<(String, String)>,
265    pub body: String,
266}
267
268impl ServerResponse {
269    pub fn new(status: i32, body: String) -> Self {
270        Self {
271            status,
272            headers: Vec::new(),
273            body,
274        }
275    }
276
277    pub fn html(body: String) -> Self {
278        Self {
279            status: 200,
280            headers: vec![("Content-Type".to_string(), "text/html".to_string())],
281            body,
282        }
283    }
284
285    pub fn json(body: String) -> Self {
286        Self {
287            status: 200,
288            headers: vec![("Content-Type".to_string(), "application/json".to_string())],
289            body,
290        }
291    }
292
293    pub fn error(status: i32, message: String) -> Self {
294        Self {
295            status,
296            headers: vec![("Content-Type".to_string(), "text/plain".to_string())],
297            body: message,
298        }
299    }
300
301    pub fn header(mut self, key: String, value: String) -> Self {
302        self.headers.push((key, value));
303        self
304    }
305}
306
307/// HTTP Server
308#[derive(Debug, Clone)]
309pub struct Server {
310    pub address: String,
311    pub port: i32,
312}
313
314impl Server {
315    pub fn new(address: String, port: i32) -> Self {
316        Self { address, port }
317    }
318
319    pub fn serve<F>(self, handler: F) -> NetResult<()>
320    where
321        F: Fn(ServerRequest) -> ServerResponse + Send + Sync + 'static,
322    {
323        let addr = format!("{}:{}", self.address, self.port);
324        let listener =
325            TcpListener::bind(&addr).map_err(|e| format!("Failed to bind to {}: {}", addr, e))?;
326
327        println!("🚀 Server listening on http://{}", addr);
328
329        for stream in listener.incoming() {
330            match stream {
331                Ok(stream) => {
332                    if let Err(e) = handle_connection(stream, &handler) {
333                        eprintln!("❌ Error handling connection: {}", e);
334                    }
335                }
336                Err(e) => {
337                    eprintln!("❌ Error accepting connection: {}", e);
338                }
339            }
340        }
341
342        Ok(())
343    }
344}
345
346fn handle_connection<F>(mut stream: TcpStream, handler: &F) -> NetResult<()>
347where
348    F: Fn(ServerRequest) -> ServerResponse,
349{
350    let mut buffer = [0; 4096];
351    let size = stream
352        .read(&mut buffer)
353        .map_err(|e| format!("Failed to read from stream: {}", e))?;
354
355    let request_str = String::from_utf8_lossy(&buffer[..size]);
356
357    // Parse request
358    let request = parse_request(&request_str)?;
359
360    println!("📄 {} {}", request.method, request.path);
361
362    // Call handler
363    let response = handler(request);
364
365    // Send response
366    send_response(&mut stream, response)?;
367
368    Ok(())
369}
370
371fn parse_request(request_str: &str) -> NetResult<ServerRequest> {
372    let mut lines = request_str.lines();
373
374    // Parse request line
375    let first_line = lines.next().ok_or("Empty request")?;
376    let parts: Vec<&str> = first_line.split_whitespace().collect();
377
378    if parts.len() < 2 {
379        return Err("Invalid request line".to_string());
380    }
381
382    let method = parts[0].to_string();
383    let path = parts[1].to_string();
384
385    // Parse headers
386    let mut headers = Vec::new();
387    for line in lines {
388        if line.is_empty() {
389            break;
390        }
391        if let Some((key, value)) = line.split_once(':') {
392            headers.push((key.trim().to_string(), value.trim().to_string()));
393        }
394    }
395
396    Ok(ServerRequest {
397        method,
398        path,
399        headers,
400        body: String::new(),
401    })
402}
403
404fn send_response(stream: &mut TcpStream, response: ServerResponse) -> NetResult<()> {
405    let status_text = match response.status {
406        200 => "OK",
407        404 => "Not Found",
408        500 => "Internal Server Error",
409        _ => "Unknown",
410    };
411
412    let mut response_str = format!("HTTP/1.1 {} {}\r\n", response.status, status_text);
413
414    // Add headers
415    for (key, value) in &response.headers {
416        response_str.push_str(&format!("{}: {}\r\n", key, value));
417    }
418
419    // Add content length
420    response_str.push_str(&format!("Content-Length: {}\r\n", response.body.len()));
421    response_str.push_str("Access-Control-Allow-Origin: *\r\n");
422    response_str.push_str("\r\n");
423    response_str.push_str(&response.body);
424
425    stream
426        .write_all(response_str.as_bytes())
427        .map_err(|e| format!("Failed to write response: {}", e))?;
428
429    stream
430        .flush()
431        .map_err(|e| format!("Failed to flush stream: {}", e))?;
432
433    Ok(())
434}