1use crate::method::*;
2use crate::status::*;
3use async_ringbuf::{AsyncHeapRb, AsyncProducer, AsyncRb};
4use async_std::sync::{Arc as AsyncArc, Barrier as AsyncBarrier, RwLock as AsyncRwLock};
5use core::{fmt::Debug, mem::MaybeUninit};
6use melodium_core::{common::executive::ResultStatus, *};
7use melodium_macro::{mel_context, mel_model, mel_treatment};
8use net_mel::ip::*;
9use ringbuf::SharedRb;
10use routefinder::RouteSpec;
11use routefinder::Segment;
12use std::sync::Arc;
13use std::{
14 collections::HashMap,
15 sync::{RwLock, Weak},
16};
17use std_mel::data::string_map::*;
18use trillium::HeaderName;
19use trillium::HeaderValue;
20use trillium::KnownHeaderName;
21use trillium::{Body, Conn};
22use trillium::{Method, Status};
23use trillium_router::{Router, RouterConnExt};
24use uuid::Uuid;
25
26pub const SERVER: &str = concat!("http-mel/", env!("CARGO_PKG_VERSION"));
27
28#[mel_context]
36pub struct HttpRequest {
37 pub id: u128,
38 pub route: string,
39 pub path: string,
40 pub parameters: StringMap,
41 pub method: HttpMethod,
42}
43
44type AsyncProducerStatus =
45 AsyncProducer<Status, Arc<AsyncRb<Status, SharedRb<Status, Vec<MaybeUninit<Status>>>>>>;
46type AsyncProducerHeaders = AsyncProducer<
47 StringMap,
48 Arc<AsyncRb<StringMap, SharedRb<StringMap, Vec<MaybeUninit<StringMap>>>>>,
49>;
50type AsyncProducerOutgoing =
51 AsyncProducer<u8, Arc<AsyncRb<u8, SharedRb<u8, Vec<MaybeUninit<u8>>>>>>;
52
53#[mel_model(
67 param host Ip none
68 param port u16 none
69 source incoming (HttpRequest) (
70 param method HttpMethod none
71 param route string none
72 ) (
73 started Block<void>
74 headers Block<StringMap>
75 data Stream<byte>
76 finished Block<void>
77 completed Block<void>
78 failed Block<void>
79 error Block<string>
80 )
81 source failedBinding () () (
82 failed Block<void>
83 error Block<string>
84 )
85 continuous (continuous)
86 shutdown shutdown
87)]
88pub struct HttpServer {
89 model: Weak<HttpServerModel>,
90 launch_barrier: AsyncArc<AsyncBarrier>,
91 routes: RwLock<Vec<(Arc<HttpMethod>, String)>>,
92 status: AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerStatus>>>,
93 headers: AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerHeaders>>>,
94 outgoing: AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerOutgoing>>>,
95 #[cfg(feature = "real")]
96 shutdown: trillium_async_std::Stopper,
97}
98
99impl Debug for HttpServer {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 #[cfg(feature = "real")]
102 {
103 f.debug_struct("HttpServer")
104 .field("model", &self.model)
105 .field("routes", &self.routes)
106 .field("shutdown", &self.shutdown)
107 .finish()
108 }
109
110 #[cfg(not(feature = "real"))]
111 {
112 f.debug_struct("HttpServer")
113 .field("model", &self.model)
114 .field("routes", &self.routes)
115 .finish()
116 }
117 }
118}
119
120impl HttpServer {
121 pub fn new(model: Weak<HttpServerModel>) -> Self {
122 Self {
123 model,
124 launch_barrier: AsyncArc::new(AsyncBarrier::new(2)),
125 routes: RwLock::new(Vec::new()),
126 status: AsyncArc::new(AsyncRwLock::new(HashMap::new())),
127 headers: AsyncArc::new(AsyncRwLock::new(HashMap::new())),
128 outgoing: AsyncArc::new(AsyncRwLock::new(HashMap::new())),
129 #[cfg(feature = "real")]
130 shutdown: trillium_async_std::Stopper::new(),
131 }
132 }
133
134 pub fn statuses(&self) -> AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerStatus>>> {
135 AsyncArc::clone(&self.status)
136 }
137
138 pub fn headers(&self) -> AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerHeaders>>> {
139 AsyncArc::clone(&self.headers)
140 }
141
142 pub fn outgoing(&self) -> AsyncArc<AsyncRwLock<HashMap<Uuid, AsyncProducerOutgoing>>> {
143 AsyncArc::clone(&self.outgoing)
144 }
145
146 #[cfg(feature = "real")]
147 async fn continuous(&self) {
148 let model = self.model.upgrade().unwrap();
149
150 self.launch_barrier.wait().await;
151
152 let routes = self.routes.read().unwrap().clone();
153
154 let status = self.status.clone();
155 let headers = self.headers.clone();
156 let outgoing = self.outgoing.clone();
157
158 let mut router = Router::new();
159 for (method, route) in routes {
160 let route = match RouteSpec::try_from(route.as_str()) {
161 Ok(route) => route,
162 Err(_) => continue,
163 };
164
165 let handler = {
166 let route = Arc::new(route.clone());
167 let status = Arc::clone(&status);
168 let headers = Arc::clone(&headers);
169 let outgoing = Arc::clone(&outgoing);
170 let model = Arc::clone(&model);
171 let method = Arc::clone(&method);
172
173 move |mut conn: Conn| {
174 let route = Arc::clone(&route);
175 let status = Arc::clone(&status);
176 let headers = Arc::clone(&headers);
177 let outgoing = Arc::clone(&outgoing);
178 let model = Arc::clone(&model);
179 let method = Arc::clone(&method);
180
181 async move {
182 let id = Uuid::new_v4();
183 let http_request = HttpRequest {
184 id: id.as_u128(),
185 route: conn.route().map(|r| r.to_string()).unwrap_or_default(),
186 path: conn.path().to_string(),
187 parameters: StringMap::new_with(
188 route
189 .segments()
190 .iter()
191 .filter_map(|seg| {
192 if let Segment::Param(param) = seg {
193 conn.param(param)
194 .map(|v| (param.to_string(), v.to_string()))
195 } else {
196 None
197 }
198 })
199 .collect(),
200 ),
201 method: (*method).clone(),
202 };
203
204 let params = {
205 let mut params = HashMap::new();
206 params.insert(
207 "method".to_string(),
208 Value::Data(Arc::clone(&method) as Arc<dyn Data>),
209 );
210 params.insert("route".to_string(), route.to_string().into());
211 params
212 };
213
214 let status_buf = AsyncHeapRb::<Status>::new(1);
215 let (status_prod, mut status_cons) = status_buf.split();
216 let headers_buf = AsyncHeapRb::<StringMap>::new(1);
217 let (headers_prod, mut headers_cons) = headers_buf.split();
218 let outgoing_buf = AsyncHeapRb::<u8>::new(2usize.pow(20));
219 let (prod, cons) = outgoing_buf.split();
220
221 status.write().await.insert(id, status_prod);
222 headers.write().await.insert(id, headers_prod);
223 outgoing.write().await.insert(id, prod);
224
225 let incoming_headers = conn
226 .request_headers()
227 .iter()
228 .filter_map(|(name, value)| {
229 value
230 .as_str()
231 .map(|value| (name.to_string(), value.to_string()))
232 })
233 .collect();
234
235 let body = conn.request_body().await;
237 let (content, occured_failure) = match body.read_bytes().await {
238 Ok(content) => (content, None),
239 Err(err) => (Vec::new(), Some(err.to_string())),
240 };
241
242 model
243 .new_incoming(
244 None,
245 http_request,
246 ¶ms,
247 Some(Box::new(move |mut outputs| {
248 let started = outputs.get("started");
249 let headers = outputs.get("headers");
250 let data = outputs.get("data");
251 let completed = outputs.get("completed");
252 let failed = outputs.get("failed");
253 let finished = outputs.get("finished");
254 let error = outputs.get("error");
255
256 vec![Box::new(Box::pin(async move {
257 if let Some(occured_failure) = occured_failure {
258 let _ = failed.send_one_as(()).await;
259 let _ = error.send_one_as(occured_failure).await;
260 } else {
261 let _ = started.send_one_as(()).await;
262 started.close().await;
263 let _ = headers
264 .send_one_as(Arc::new(StringMap::new_with(
265 incoming_headers,
266 ))
267 as Arc<dyn Data>)
268 .await;
269 headers.close().await;
270 let _ = data
271 .send_many(TransmissionValue::Byte(content.into()))
272 .await;
273 let _ = completed.send_one_as(()).await;
274 }
275 let _ = finished.send_one_as(()).await;
276
277 headers.close().await;
278 data.close().await;
279 completed.close().await;
280 finished.close().await;
281 failed.close().await;
282 error.close().await;
283 ResultStatus::Ok
284 }))]
285 })),
286 )
287 .await;
288
289 if let (Some(status), Some(headers)) =
290 futures::join!(status_cons.pop(), headers_cons.pop())
291 {
292 conn.set_status(status);
293 conn.response_headers_mut()
294 .insert(KnownHeaderName::Server, SERVER);
295
296 for (name, content) in &headers.map {
297 let header_name = HeaderName::from(name.to_string());
298 if header_name.is_valid() {
299 let header_content = HeaderValue::from(content.clone());
300 if header_content.is_valid() {
301 conn.response_headers_mut()
302 .insert(header_name.to_owned(), header_content);
303 }
304 }
305 }
306
307 conn.set_body(Body::new_streaming(cons, None));
308 } else {
309 conn.set_status(Status::InternalServerError);
310 }
311
312 conn.halt()
313 }
314 }
315 };
316
317 match method.0 {
318 Method::Delete => router = router.delete(route, handler),
319 Method::Get => router = router.get(route, handler),
320 Method::Patch => router = router.patch(route, handler),
321 Method::Post => router = router.post(route, handler),
322 Method::Put => router = router.put(route, handler),
323 _ => {}
324 }
325 }
326
327 match async_std::net::TcpListener::bind((model.get_host().0, model.get_port())).await {
328 Ok(listener) => {
329 trillium_async_std::config()
330 .without_signals()
331 .with_stopper(self.shutdown.clone())
332 .with_prebound_server(listener)
333 .run_async(router)
334 .await
335 }
336 Err(err) => {
337 model
338 .new_failedBinding(
339 None,
340 &HashMap::new(),
341 Some(Box::new(move |mut outputs| {
342 let error = outputs.get("error");
343 let failed = outputs.get("failed");
344 vec![Box::new(Box::pin(async move {
345 let _ = failed.send_one_as(()).await;
346 let _ = error.send_one_as(err.to_string()).await;
347 failed.close().await;
348 error.close().await;
349 ResultStatus::Ok
350 }))]
351 })),
352 )
353 .await
354 }
355 }
356 }
357
358 #[cfg(not(feature = "real"))]
359 async fn continuous(&self) {}
360
361 fn invoke_source(&self, source: &str, params: HashMap<String, Value>) {
362 match source {
363 "incoming" => {
364 let method = params
365 .get("method")
366 .unwrap()
367 .clone()
368 .try_data::<Arc<HttpMethod>>()
369 .unwrap();
370 let route = params
371 .get("route")
372 .unwrap()
373 .clone()
374 .try_data::<String>()
375 .unwrap();
376
377 self.routes.write().unwrap().push((method, route));
378 }
379 _ => {}
380 }
381 }
382
383 fn shutdown(&self) {
384 #[cfg(feature = "real")]
385 self.shutdown.stop();
386 }
387}
388
389#[mel_treatment(
404 model http_server HttpServer
405 input trigger Block<void>
406)]
407pub async fn start() {
408 let model = HttpServerModel::into(http_server);
409 let http_server = model.inner();
410
411 if let Ok(_) = trigger.recv_one().await {
412 http_server.launch_barrier.wait().await;
413 }
414}
415
416#[mel_treatment(
438 input status Block<HttpStatus>
439 input headers Block<StringMap>
440 input data Stream<byte>
441 model http_server HttpServer
442)]
443pub async fn outgoing(id: u128) {
444 let id = Uuid::from_u128(id);
445 let model = HttpServerModel::into(http_server);
446 let http_server = model.inner();
447
448 let out_status;
449 let out_headers;
450 let output;
451 {
452 let statuses = http_server.statuses();
453 let mut lock = statuses.write().await;
454 out_status = lock.remove(&id);
455 }
456 {
457 let headers = http_server.headers();
458 let mut lock = headers.write().await;
459 out_headers = lock.remove(&id);
460 }
461 {
462 let outputs = http_server.outgoing();
463 let mut lock = outputs.write().await;
464 output = lock.remove(&id);
465 }
466 if let (Some(mut out_status), Some(mut out_headers), Some(mut output)) =
467 (out_status, out_headers, output)
468 {
469 if let Ok((status, headers)) = futures::try_join!(
470 status.recv_one_as::<Arc<HttpStatus>>(),
471 headers.recv_one_as::<Arc<StringMap>>(),
472 ) {
473 match futures::join!(
474 out_status.push(status.0),
475 out_headers.push(Arc::unwrap_or_clone(headers))
476 ) {
477 (Ok(_), Ok(_)) => {
478 while let (Ok(data), false) =
479 (data.recv_many_as::<byte>().await, output.is_closed())
480 {
481 match output.push_iter(data.into_iter()).await {
482 Ok(_) => {}
483 Err(_) => break,
484 }
485 }
486 }
487 (_, _) => {}
488 }
489 }
490 }
491}