embedded_wg_display/runtime/
http_sync.rs1use crate::{http_client::EspHttpClient, runtime::widget::widget::http};
16use alloc::string::String;
17use alloc::vec::Vec;
18use defmt::{error, info};
19use embassy_net::Stack;
20use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
21use embassy_sync::channel::Channel;
22use embassy_time::{Duration, with_timeout};
23use esp_hal::time::Duration as HalDuration;
24use esp_rtos::CurrentThreadHandle;
25
26#[derive(Clone)]
29pub struct HttpRequest {
30 pub method: reqwless::request::Method,
31 pub url: String,
32 pub body: Option<Vec<u8>>,
33}
34
35pub type HttpResponse = Result<http::Response, ()>;
36
37static HTTP_REQUEST_CHANNEL: Channel<CriticalSectionRawMutex, HttpRequest, 1> = Channel::new();
38static HTTP_RESPONSE_CHANNEL: Channel<CriticalSectionRawMutex, HttpResponse, 1> = Channel::new();
39const ASYNC_BRIDGE_TIMEOUT: Duration = Duration::from_secs(30);
40
41pub async fn http_request_async(request: HttpRequest) -> Result<http::Response, ()> {
43 match with_timeout(ASYNC_BRIDGE_TIMEOUT, HTTP_REQUEST_CHANNEL.send(request)).await {
44 Ok(()) => {}
45 Err(_) => {
46 error!("HTTP async bridge timed out while enqueueing request");
47 return Err(());
48 }
49 }
50
51 match with_timeout(ASYNC_BRIDGE_TIMEOUT, HTTP_RESPONSE_CHANNEL.receive()).await {
52 Ok(response) => response,
53 Err(_) => {
54 error!("HTTP async bridge timed out while waiting for response");
55 Err(())
56 }
57 }
58}
59
60pub fn http_request_sync(request: HttpRequest) -> Result<http::Response, ()> {
63 info!(
64 "http_request_sync: sending request to {}",
65 request.url.as_str()
66 );
67
68 match HTTP_REQUEST_CHANNEL.try_send(request) {
70 Ok(_) => {
71 info!("HTTP request sent to channel, waiting for response...");
72
73 let mut iterations = 0u32;
74 let current_thread = CurrentThreadHandle::get();
75 const MAX_WAIT_ITERATIONS: u32 = 3000; loop {
78 match HTTP_RESPONSE_CHANNEL.try_receive() {
79 Ok(response) => {
80 info!("HTTP response received after {} iterations", iterations);
81 return response;
82 }
83 Err(_) => {
84 iterations += 1;
85 if iterations >= MAX_WAIT_ITERATIONS {
86 error!("HTTP request timed out while waiting for handler response");
87 return Err(());
88 }
89 if iterations.is_multiple_of(20) {
90 info!("Still waiting... iteration {}", iterations);
91 }
92 current_thread.delay(HalDuration::from_millis(10));
93 }
94 }
95 }
96 }
97 Err(_) => {
98 error!("HTTP request channel full");
99 Err(())
100 }
101 }
102}
103
104#[embassy_executor::task]
107pub async fn http_handler_task(stack: Stack<'static>, _tls_seed: u64) {
108 defmt::info!("HTTP handler task started");
109 let http_client = EspHttpClient::new(stack, _tls_seed);
110
111 loop {
112 defmt::debug!("HTTP handler: waiting for request...");
113
114 let request = HTTP_REQUEST_CHANNEL.receive().await;
116
117 defmt::info!("Processing HTTP request to: {=str}", request.url.as_str());
118
119 defmt::info!("HTTP handler: executing request");
121 let response_result = http_client
122 .request(request.method, &request.url, request.body.as_deref())
123 .await
124 .map_err(|e| {
125 defmt::error!("HTTP handler request failed: {:?}", defmt::Debug2Format(&e));
126 });
127
128 HTTP_RESPONSE_CHANNEL.send(response_result).await;
130 defmt::info!("HTTP response sent back to caller");
131 }
132}