afast/
lib.rs

1//! # AFast
2//!
3//! **AFast** is a high-performance asynchronous Rust backend framework designed
4//! to simplify building networked applications. It supports multiple protocols
5//! via feature flags and provides automatic code generation for clients
6//! (TypeScript and JavaScript), API documentation, and field validation.
7//!
8//! ## Instructions
9//!
10//! ### Supported Protocol Features
11//!
12//! You can enable the following features in your `Cargo.toml`:
13//!
14//! - `http` - enable HTTP support
15//!   - `/` - Document path (feature flag `doc`)
16//!   - `/api` - HTTP API endpoints
17//!   - `/code/{service}/{lang}` - Client code (feature flag `js`|`ts` ...)
18//!   - `/doc` - Service list (feature flag `doc`)
19//!   - `/doc/{service}` - Handler defintions and documentation (feature flag `doc`)
20//! - `ws` - enable WebSocket support
21//!   - `/ws` - WebSocket endpoint
22//! - `tcp` - enable TCP support
23//! - `doc` - enable API documentation generation
24//! - `js` - enable JavaScript client generation (auto enabled `code`)
25//! - `ts` - enable TypeScript client generation (auto enabled `code`)
26//! - `code` - enable code generation
27//!
28//! **Note on TCP usage:**  
29//!
30//! If the `tcp` feature is enabled, the `AFast::serve` method takes two arguments:
31//!
32//! 1. The TCP address to listen on (`"127.0.0.1:8080"`).  
33//! 2. The HTTP/WS address (`"127.0.0.1:8081"`) for web clients and generated JS/TS clients.
34//!
35//! This allows you to run TCP and HTTP/WS servers simultaneously in the same application.
36//!
37//! ### Key Features
38//!
39//! - **`handler` Macro**: Declare HTTP endpoints with minimal boilerplate
40//!   - Automatic TypeScript/JavaScript client generation
41//!   - Namespace support for organized API structure (`ns("api.v1.user")`)
42//!   - Descriptive API documentation generation (`desc("Get user info")`)
43//! - Automatic field validation with custom rules
44//! - Async handler functions with state management
45//! - Flexible multi-protocol support: HTTP, WS, TCP
46//!
47//! #### Handler Macro Overview
48//!
49//! The `#[handler]` attribute macro transforms async functions into full-featured API endpoints:
50//!
51//! ```rust
52//! #[handler(desc("Get user information"), ns("api.v1.user"))]
53//! async fn get_user(state: String, header: Header, req: Request) -> Result<Response, Error> {
54//!     // Your business logic
55//! }
56//! ```
57//!
58//! **Macro Parameters:**
59//!
60//! - `desc("description")` - API description for documentation
61//! - `ns("api.v1.user")` - Namespace for nested JS client generation
62//!
63//! **Generated Output:**
64//!
65//! - Type-safe HTTP endpoints
66//! - Nested JavaScript client structure
67//! - TypeScript type definitions  
68//! - OpenAPI documentation
69//!
70//! ### Upcoming Features / Development Plan
71//!
72//! - Nested structure validation for complex types
73//! - Enable or disable js / ts / document by feature flags
74//! - Add command for generating client code
75//! - Generate client code for additional languages: Java, Kotlin, C#, Rust, etc.
76//! - Improved code generation templates for easier integration
77//! - Enhanced error handling and validation reporting
78//!
79//! ## Example
80//!
81//! ```rust
82//! use afast::{AFast, AFastData, AFastKind, Error, handler, middleware, register};
83//!
84//! #[derive(Debug, Clone, AFastData, AFastKind)]
85//! enum Sex {
86//!     Other,
87//!     Custom(#[validate(desc("Custom user sex 0"))] i32, String),
88//!     Male {
89//!         #[validate(desc("Male user id"))]
90//!         id: i64,
91//!     },
92//!     Female {
93//!         #[validate(desc("Female user name"))]
94//!         name: String,
95//!     },
96//! }
97//!
98//! #[derive(Debug, Clone, AFastData, AFastKind)]
99//! struct Request {
100//!     #[validate(desc("User ID"))]
101//!     id: i64,
102//!     #[validate(desc("User name"))]
103//!     name: String,
104//!     #[validate(
105//!         desc("User age"),
106//!         required("age is required"),
107//!         min(1, "age must be at least 1"),
108//!         max(256, "age must be at most 256")
109//!     )]
110//!     age: u32,
111//!     #[validate(desc("User hobbies"))]
112//!     hobbies: Vec<Hobby>,
113//!     #[validate(desc("User tags"))]
114//!     tags: Vec<String>,
115//!     #[validate(desc("User gender"))]
116//!     gender: Option<bool>,
117//!     #[validate(desc("User sex"))]
118//!     sex: Sex,
119//! }
120//!
121//! #[derive(Debug, Clone, AFastData, AFastKind)]
122//! struct Hobby {
123//!     id: i64,
124//!     name: String,
125//! }
126//!
127//! #[derive(Debug, AFastData, AFastKind)]
128//! pub struct Response {
129//!     sex: Sex,
130//!     id: i64,
131//!     name: String,
132//!     age: u32,
133//!     hobbies: Vec<Hobby>,
134//!     tags: Vec<String>,
135//!     gender: Option<bool>,
136//! }
137//!
138//! #[handler(desc("Get user information"), ns("api.user"))]
139//! async fn get_user(_state: String, _header: Header, req: Request) -> Result<Response, Error> {
140//!     Ok(Response {
141//!         id: req.id,
142//!         name: req.name.clone(),
143//!         age: req.age,
144//!         hobbies: req.hobbies.clone(),
145//!         tags: req.tags.clone(),
146//!         gender: req.gender,
147//!         sex: req.sex.clone(),
148//!     })
149//! }
150//!
151//! #[derive(Debug, AFastData, AFastKind)]
152//! struct Req2 {
153//!     id: i64,
154//! }
155//!
156//! #[derive(Debug, AFastData, AFastKind)]
157//! struct Resp2 {
158//!     id: i64,
159//!     name: String,
160//! }
161//!
162//! #[handler(desc("Get user by id"), ns("api"))]
163//! async fn get_id(_state: String, _header: Header, req: Req2) -> Result<Resp2, Error> {
164//!     Ok(Resp2 {
165//!         id: req.id,
166//!         name: "John".to_string(),
167//!     })
168//! }
169//!
170//! #[derive(Debug, Clone, AFastData, AFastKind)]
171//! struct Header {
172//!     token: String,
173//! }
174//!
175//! #[middleware]
176//! async fn auth(_state: String, header: Header) -> Result<Header, Error> {
177//!     println!("Token: {:?}", header);
178//!     Ok(header)
179//! }
180//!
181//! #[tokio::main]
182//! async fn main() {
183//!     let state = "".to_string();
184//!
185//!     let server = AFast::<String, Header>::new(state)
186//!         .service("user", "User service", register! { get_user, get_id })
187//!         .middleware(auth);
188//!
189//!     server
190//!         .serve(
191//!             #[cfg(feature = "tcp")]
192//!             &"127.0.0.1:8080",
193//!             #[cfg(any(feature = "http", feature = "ws"))]
194//!             &"127.0.0.1:8081",
195//!         )
196//!         .await
197//!         .unwrap();
198//! }
199//! ```
200//!
201
202use std::sync::Arc;
203
204pub use afast_macros::*;
205use tokio::net::ToSocketAddrs;
206
207#[cfg(feature = "doc")]
208mod doc;
209mod error;
210#[cfg(feature = "js")]
211mod js;
212#[cfg(feature = "ts")]
213mod ts;
214pub use error::Error;
215
216pub trait AFastData: Sized {
217    fn to_bytes(&self) -> Vec<u8>;
218    fn from_bytes(buf: &[u8]) -> Result<(Self, usize), Error>;
219    fn validate(&self) -> Result<(), Vec<&'static str>>;
220}
221
222/// The type of a handler function.
223///
224/// Each handler receives shared state `Arc<T>` and a binary request slice `&[u8]`,
225/// and returns a Future that resolves to a binary response `Vec<u8>` or an `Error`.
226pub type Handler<T, H> = dyn Fn(
227        T,
228        H,
229        &[u8],
230    ) -> std::pin::Pin<
231        Box<dyn std::future::Future<Output = Result<Vec<u8>, Error>> + Send + 'static>,
232    > + Send
233    + Sync;
234
235pub type Middleware<T, H> = dyn Fn(
236        T,
237        H,
238    )
239        -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<H, Error>> + Send + 'static>>
240    + Send
241    + Sync;
242
243/// Generic handler struct that wraps a user-defined handler function.
244///
245/// Contains a handler ID, name, JS request code, TS request code, and the processing function.
246pub struct HandlerGeneric<T, H>
247where
248    T: Clone + Send + Sync + 'static,
249    H: AFastKind + AFastData,
250{
251    /// Unique handler ID
252    pub id: u32,
253    /// Handler name
254    pub name: &'static str,
255
256    /// JS client
257    #[cfg(feature = "js")]
258    pub js: String,
259
260    /// TS client
261    #[cfg(feature = "ts")]
262    pub ts: String,
263
264    /// API documentation
265    #[cfg(feature = "doc")]
266    pub doc: String,
267
268    /// Namespace for this handler
269    pub namespace: Vec<String>,
270    /// Actual processing function
271    pub func: Box<Handler<T, H>>,
272}
273
274/// Core AFast service struct.
275///
276/// Maintains shared state and registered handlers.
277pub struct AFast<T, H>
278where
279    T: Clone + Send + Sync + 'static,
280    H: AFastKind + AFastData + Send + Sync + 'static,
281{
282    /// Shared application state
283    state: T,
284    /// Middleware function
285    pub middleware: Arc<Box<Middleware<T, H>>>,
286    /// Registered handler list
287    handlers: Arc<Vec<HandlerGeneric<T, H>>>,
288
289    /// Client code
290    #[cfg(feature = "code")]
291    codes: std::collections::HashMap<String, String>,
292
293    services: std::collections::HashSet<(String, String, usize)>,
294
295    /// Includs JS util
296    #[cfg(feature = "js")]
297    js_util: bool,
298
299    /// Includs TS util
300    #[cfg(feature = "ts")]
301    ts_util: bool,
302}
303
304impl<T, H> AFast<T, H>
305where
306    T: Clone + Send + Sync + 'static,
307    H: AFastKind + AFastData + Send + Sync + 'static,
308{
309    /// Create a new AFast service instance
310    ///
311    /// # Arguments
312    /// * `state` - Shared application state
313    /// * `handlers` - List of registered handlers
314    ///
315    /// # Returns
316    /// A new AFast instance
317    pub fn new(state: T) -> Self {
318        Self {
319            state,
320            middleware: Arc::new(Box::new(|_state, header| Box::pin(async { Ok(header) }))),
321            handlers: Arc::new(vec![]),
322            #[cfg(feature = "code")]
323            codes: std::collections::HashMap::new(),
324            services: std::collections::HashSet::new(),
325            #[cfg(feature = "js")]
326            js_util: true,
327            #[cfg(feature = "ts")]
328            ts_util: true,
329        }
330    }
331
332    pub fn middleware(mut self, middleware: fn() -> Box<Middleware<T, H>>) -> Self {
333        self.middleware = Arc::new(middleware());
334        self
335    }
336
337    #[cfg(feature = "js")]
338    /// Enable or disable JS util
339    /// The service will take effect after this
340    pub fn disable_js_util(mut self) -> Self {
341        self.js_util = false;
342        self
343    }
344
345    #[cfg(feature = "ts")]
346    /// Enable or disable TS util
347    /// The service will take effect after this
348    pub fn disable_ts_util(mut self) -> Self {
349        self.ts_util = false;
350        self
351    }
352
353    /// Register a service with additional handlers
354    pub fn service(mut self, name: &str, desc: &str, handlers: Vec<HandlerGeneric<T, H>>) -> Self {
355        if handlers.is_empty() {
356            println!("No handlers found for service {}", name);
357            return self;
358        }
359
360        if self.services.iter().any(|s| s.0 == name) {
361            panic!("Service {} already registered", name);
362        }
363
364        self.services
365            .insert((name.to_string(), desc.to_string(), handlers.len()));
366
367        #[cfg(feature = "js")]
368        self.codes.insert(
369            format!("code/{}/js", name),
370            js::gen_js_code(self.js_util, self.handlers.len(), &handlers),
371        );
372
373        #[cfg(feature = "ts")]
374        self.codes.insert(
375            format!("code/{}/ts", name),
376            ts::gen_ts_code(self.js_util, self.handlers.len(), &handlers),
377        );
378
379        #[cfg(feature = "doc")]
380        self.codes.insert(
381            format!("doc/{}", name),
382            doc::gen_doc(self.handlers.len(), &handlers),
383        );
384
385        let existing_handlers = Arc::get_mut(&mut self.handlers).unwrap();
386        existing_handlers.extend(handlers);
387        self.handlers = Arc::clone(&self.handlers);
388
389        self
390    }
391
392    /// Start the server
393    ///
394    /// Depending on feature flags, this will start TCP, HTTP, and/or WebSocket services.
395    ///
396    /// # Arguments
397    /// * `addr_tcp` - TCP listening address (only active if `tcp` feature enabled)
398    /// * `addr_http` - HTTP/WebSocket listening address (only active if `http` or `ws` feature enabled)
399    ///
400    /// # Returns
401    /// Result<(), Error>
402    pub async fn serve<A: ToSocketAddrs>(
403        &self,
404        #[cfg(feature = "tcp")] addr_tcp: A,
405        #[cfg(any(feature = "http", feature = "ws"))] addr_http: A,
406    ) -> Result<(), Error> {
407        #[cfg(feature = "tcp")]
408        {
409            // Clone shared state and handler list for TCP processing
410            let state = self.state.clone();
411            let handlers = Arc::clone(&self.handlers);
412
413            // Bind TCP listener
414            let listener = tokio::net::TcpListener::bind(addr_tcp).await.unwrap();
415
416            #[cfg(any(feature = "http", feature = "ws"))]
417            {
418                // Spawn TCP listener task if HTTP/WS is also enabled
419                let mw = Arc::clone(&self.middleware);
420                tokio::spawn(async move {
421                    loop {
422                        let (mut socket, _) = listener.accept().await.unwrap();
423
424                        // Read 4-byte length prefix
425                        let mut body = [0u8; 4];
426                        tokio::io::AsyncReadExt::read_exact(&mut socket, &mut body)
427                            .await
428                            .unwrap();
429                        let len = u32::from_be_bytes(body) as usize;
430
431                        // Read message body
432                        let mut body = vec![0u8; len];
433                        tokio::io::AsyncReadExt::read_exact(&mut socket, &mut body)
434                            .await
435                            .unwrap();
436
437                        let (header, size) = match H::from_bytes(&body) {
438                            Ok(h) => h,
439                            Err(_) => {
440                                continue;
441                            }
442                        };
443
444                        // Parse sequence number and handler ID
445                        let seq: usize = u32::from_be_bytes([
446                            body[size + 0],
447                            body[size + 1],
448                            body[size + 2],
449                            body[size + 3],
450                        ]) as usize;
451                        let id: usize = u32::from_be_bytes([
452                            body[size + 4],
453                            body[size + 5],
454                            body[size + 6],
455                            body[size + 7],
456                        ]) as usize;
457
458                        // Call handler
459                        let handler = &handlers[id];
460
461                        let fut = mw(state.clone(), header);
462                        let header = match fut.await {
463                            Ok(r) => r,
464                            Err(_) => {
465                                continue;
466                            }
467                        };
468                        let h = header.to_bytes();
469                        let fut = (handler.func)(state.clone(), header, &body[size + 8..]);
470                        let res = fut.await.unwrap();
471
472                        // Build response: len + seq + id + response
473                        let mut final_res = Vec::with_capacity(12 + res.len() + h.len());
474                        final_res.extend_from_slice(&final_res.len().to_be_bytes());
475                        final_res.extend_from_slice(&seq.to_be_bytes());
476                        final_res.extend_from_slice(&id.to_be_bytes());
477                        final_res.extend_from_slice(&h);
478                        final_res.extend_from_slice(&res);
479
480                        tokio::io::AsyncWriteExt::write_all(&mut socket, &final_res)
481                            .await
482                            .unwrap();
483                    }
484                });
485            }
486
487            #[cfg(not(any(feature = "http", feature = "ws")))]
488            {
489                // Blocking TCP loop if HTTP/WS is disabled
490                let mw = Arc::clone(&self.middleware);
491                loop {
492                    let (mut socket, _) = listener.accept().await.unwrap();
493
494                    // Read 4-byte length prefix
495                    let mut body = [0u8; 4];
496                    tokio::io::AsyncReadExt::read_exact(&mut socket, &mut body)
497                        .await
498                        .unwrap();
499                    let len = u32::from_be_bytes(body) as usize;
500
501                    // Read message body
502                    let mut body = vec![0u8; len];
503                    tokio::io::AsyncReadExt::read_exact(&mut socket, &mut body)
504                        .await
505                        .unwrap();
506
507                    let (header, size) = match H::from_bytes(&body) {
508                        Ok(h) => h,
509                        Err(_) => {
510                            continue;
511                        }
512                    };
513
514                    // Parse sequence number and handler ID
515                    let seq: usize = u32::from_be_bytes([
516                        body[size + 0],
517                        body[size + 1],
518                        body[size + 2],
519                        body[size + 3],
520                    ]) as usize;
521                    let id: usize = u32::from_be_bytes([
522                        body[size + 4],
523                        body[size + 5],
524                        body[size + 6],
525                        body[size + 7],
526                    ]) as usize;
527
528                    // Call handler
529                    let handler = &handlers[id];
530
531                    let fut = mw(state.clone(), header);
532                    let header = match fut.await {
533                        Ok(r) => r,
534                        Err(_) => {
535                            continue;
536                        }
537                    };
538                    let h = header.to_bytes();
539                    let fut = (handler.func)(state.clone(), header, &body[size + 8..]);
540                    let res = fut.await.unwrap();
541
542                    // Build response: len + seq + id + response
543                    let mut final_res = Vec::with_capacity(12 + res.len() + h.len());
544                    final_res.extend_from_slice(&final_res.len().to_be_bytes());
545                    final_res.extend_from_slice(&seq.to_be_bytes());
546                    final_res.extend_from_slice(&id.to_be_bytes());
547                    final_res.extend_from_slice(&h);
548                    final_res.extend_from_slice(&res);
549
550                    tokio::io::AsyncWriteExt::write_all(&mut socket, &final_res)
551                        .await
552                        .unwrap();
553                }
554            }
555        }
556
557        #[cfg(any(feature = "http", feature = "ws", feature = "code", feature = "doc"))]
558        {
559            #[cfg(feature = "code")]
560            let codes = Arc::new(self.codes.clone());
561
562            #[cfg(any(feature = "http", feature = "ws"))]
563            let state = self.state.clone();
564
565            #[cfg(any(feature = "http", feature = "ws"))]
566            let listener = tokio::net::TcpListener::bind(addr_http).await.unwrap();
567            loop {
568                let (stream, _) = listener.accept().await.unwrap();
569                let io = hyper_util::rt::TokioIo::new(stream);
570                let state = state.clone();
571                let mw = Arc::clone(&self.middleware);
572                let handlers = Arc::clone(&self.handlers);
573
574                #[cfg(feature = "code")]
575                let codes = Arc::clone(&codes);
576                #[cfg(feature = "doc")]
577                let services = Arc::new(self.services.clone());
578
579                tokio::spawn(async move {
580                    let state = state.clone();
581                    let mw = Arc::clone(&mw);
582                    let handlers = Arc::clone(&handlers);
583                    #[cfg(feature = "code")]
584                    let codes = Arc::clone(&codes);
585                    #[cfg(feature = "doc")]
586                    let services = Arc::clone(&services);
587                    if let Err(err) = hyper::server::conn::http1::Builder::new(
588                        // hyper_util::rt::TokioExecutor::new(),
589                    )
590                    .serve_connection(
591                        io,
592                        hyper::service::service_fn(|req: hyper::Request<_>| {
593                            let state = state.clone();
594                            let mw = Arc::clone(&mw);
595                            let handlers = Arc::clone(&handlers);
596                            #[cfg(feature = "code")]
597                            let codes = Arc::clone(&codes);
598                            #[cfg(feature = "doc")]
599                            let services = Arc::clone(&services);
600
601                            async move {
602                                let path = req.uri().path();
603                                let method = req.method();
604                                #[cfg(feature = "ws")]
605                                let upgrade = req
606                                    .headers()
607                                    .get("Upgrade")
608                                    .map(|v| v == "websocket")
609                                    .unwrap_or(false);
610                                #[cfg(feature = "ws")]
611                                let sec_ws_key = req.headers().contains_key("Sec-WebSocket-Key");
612                                #[cfg(feature = "ws")]
613                                if path == "/ws"
614                                    && method == hyper::Method::GET
615                                    && upgrade
616                                    && sec_ws_key
617                                {
618                                    let upgraded = hyper::upgrade::on(req).await.unwrap();
619                                    let stream = hyper_util::rt::TokioIo::new(upgraded);
620                                    println!("WebSocket client connected!");
621
622                                    let mut ws =
623                                        tokio_tungstenite::WebSocketStream::from_raw_socket(
624                                            stream,
625                                            tokio_tungstenite::tungstenite::protocol::Role::Server,
626                                            None,
627                                        )
628                                        .await;
629
630                                    while let Some(msg) =
631                                        futures_util::StreamExt::next(&mut ws).await
632                                    {
633                                        let msg = msg.unwrap();
634
635                                        match msg {
636                                            tokio_tungstenite::tungstenite::Message::Binary(
637                                                body,
638                                            ) => {
639                                                if body.len() < 8 {
640                                                    continue;
641                                                }
642
643                                                let (header, size) = match H::from_bytes(&body) {
644                                                    Ok(h) => h,
645                                                    Err(_) => {
646                                                        continue;
647                                                    }
648                                                };
649
650                                                let seq: usize = u32::from_be_bytes([
651                                                    body[size + 0],
652                                                    body[size + 1],
653                                                    body[size + 2],
654                                                    body[size + 3],
655                                                ])
656                                                    as usize;
657                                                let id: usize = u32::from_be_bytes([
658                                                    body[size + 4],
659                                                    body[size + 5],
660                                                    body[size + 6],
661                                                    body[size + 7],
662                                                ])
663                                                    as usize;
664
665                                                let handler = &handlers[id];
666
667                                                let fut = mw(state.clone(), header);
668                                                let header = match fut.await {
669                                                    Ok(r) => r,
670                                                    Err(_) => {
671                                                        continue;
672                                                    }
673                                                };
674                                                let h = header.to_bytes();
675                                                let fut = (handler.func)(
676                                                    state.clone(),
677                                                    header,
678                                                    &body[size + 8..],
679                                                );
680                                                let res = fut.await.unwrap();
681                                                let mut final_res =
682                                                    Vec::with_capacity(8 + res.len() + h.len());
683                                                final_res.extend_from_slice(&seq.to_be_bytes());
684                                                final_res.extend_from_slice(&id.to_be_bytes());
685                                                final_res.extend_from_slice(&h);
686                                                final_res.extend_from_slice(&res);
687                                                futures_util::SinkExt::send(
688                                                    &mut ws,
689                                                    tokio_tungstenite::tungstenite::Message::Binary(
690                                                        final_res.into(),
691                                                    ),
692                                                )
693                                                .await
694                                                .unwrap();
695                                            }
696                                            tokio_tungstenite::tungstenite::Message::Close(_) => {
697                                                println!("Client disconnected");
698                                                break;
699                                            }
700                                            _ => {}
701                                        }
702                                    }
703
704                                    return Ok::<_, std::convert::Infallible>(
705                                        hyper::Response::builder()
706                                            .status(400)
707                                            .body(http_body_util::Full::<hyper::body::Bytes>::new(
708                                                "".into(),
709                                            ))
710                                            .unwrap(),
711                                    );
712                                }
713
714                                #[cfg(feature = "http")]
715                                if method == hyper::Method::POST && path == "/api" {
716                                    let body = http_body_util::BodyExt::collect(req)
717                                        .await
718                                        .unwrap()
719                                        .to_bytes();
720                                    let (header, size) = match H::from_bytes(&body[..]) {
721                                        Ok(h) => h,
722                                        Err(e) => {
723                                            return Ok::<_, std::convert::Infallible>(
724                                                hyper::Response::builder()
725                                                    .status(400)
726                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
727                                                        e.to_string().into(),
728                                                    ))
729                                                    .unwrap(),
730                                            );
731                                        }
732                                    };
733
734                                    if body.len() < size + 4 {
735                                        return Ok::<_, std::convert::Infallible>(
736                                            hyper::Response::builder()
737                                                .status(400)
738                                                .body(http_body_util::Full::<hyper::body::Bytes>::new(
739                                                    "Invalid request".into(),
740                                                ))
741                                                .unwrap(),
742                                        );
743                                    }
744
745                                    let id = u32::from_be_bytes([
746                                        body[size + 0],
747                                        body[size + 1],
748                                        body[size + 2],
749                                        body[size + 3],
750                                    ]);
751                                    let handler = &handlers[id as usize];
752
753                                    let fut = mw(state.clone(), header);
754                                    let header = match fut.await {
755                                        Ok(r) => r,
756                                        Err(e) => {
757                                            return Ok::<_, std::convert::Infallible>(
758                                                hyper::Response::builder()
759                                                    .status(400)
760                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
761                                                        e.to_string().into(),
762                                                    ))
763                                                    .unwrap(),
764                                            );
765                                        }
766                                    };
767                                    let h = header.to_bytes();
768                                    let fut =
769                                        (handler.func)(state.clone(), header, &body[size + 4..]);
770                                    match fut.await {
771                                        Ok(res) => {
772                                            let mut final_res =
773                                                Vec::with_capacity(4 + res.len() + h.len());
774                                            final_res.extend_from_slice(&id.to_be_bytes());
775                                            final_res.extend_from_slice(&h);
776                                            final_res.extend_from_slice(&res);
777                                            return Ok::<_, std::convert::Infallible>(
778                                                hyper::Response::builder()
779                                                    .status(200)
780                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
781                                                        final_res.into(),
782                                                    ))
783                                                    .unwrap(),
784                                            );
785                                        }
786                                        Err(e) => {
787                                            let (c, m) = match e {
788                                                Error::DecodeError => {
789                                                    (400, "Invalid request".to_string())
790                                                }
791                                                Error::EncodeError => {
792                                                    (500, "Invalid response".to_string())
793                                                }
794                                                Error::ClientError => {
795                                                    (400, "Bad request".to_string())
796                                                }
797                                                Error::ServerError => {
798                                                    (500, "Internal Server Error".to_string())
799                                                }
800                                                Error::CustomError(c, m) => (c, m.to_string()),
801                                            };
802                                            return Ok::<_, std::convert::Infallible>(
803                                                hyper::Response::builder()
804                                                    .status(c)
805                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(m.into()))
806                                                    .unwrap(),
807                                            );
808                                        }
809                                    }
810                                }
811
812                                #[cfg(any(feature = "code", feature = "doc"))]
813                                if method == hyper::Method::GET {
814                                    #[cfg(feature = "code")]
815                                    if path.starts_with("/code") {
816                                        let parts: Vec<&str> = path
817                                            .trim_start_matches('/')
818                                            .trim_end_matches('/')
819                                            .split('/')
820                                            .collect();
821                                        let len = parts.len();
822                                        if len != 3 {
823                                            return Ok::<_, std::convert::Infallible>(
824                                                hyper::Response::builder()
825                                                    .status(404)
826                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
827                                                        "404 Not Found".into(),
828                                                    ))
829                                                    .unwrap(),
830                                            );
831                                        }
832                                        let (service, lang) = (parts[1], parts[2]);
833                                        let code = if let Some(code) =
834                                            codes.get(&format!("code/{}/{}", service, lang))
835                                        {
836                                            code.to_string()
837                                        } else {
838                                            return Ok::<_, std::convert::Infallible>(
839                                                hyper::Response::builder()
840                                                    .status(404)
841                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
842                                                        "404 Not Found".into(),
843                                                    ))
844                                                    .unwrap(),
845                                            );
846                                        };
847
848                                        return Ok::<_, std::convert::Infallible>(
849                                            hyper::Response::builder()
850                                                .status(200)
851                                                .header(
852                                                    hyper::http::header::CONTENT_TYPE,
853                                                    "text/javascript; charset=utf-8",
854                                                )
855                                                .body(http_body_util::Full::<hyper::body::Bytes>::new(code.into()))
856                                                .unwrap(),
857                                        );
858                                    }
859
860                                    #[cfg(feature = "doc")]
861                                    if path.starts_with("/doc") {
862                                        let parts: Vec<&str> = path
863                                            .trim_start_matches('/')
864                                            .trim_end_matches('/')
865                                            .split('/')
866                                            .collect();
867                                        let len = parts.len();
868                                        if len == 2 {
869                                            let code = if let Some(code) =
870                                                codes.get(&format!("doc/{}", parts[1]))
871                                            {
872                                                code.to_string()
873                                            } else {
874                                                return Ok::<_, std::convert::Infallible>(
875                                                    hyper::Response::builder()
876                                                        .status(404)
877                                                        .body(http_body_util::Full::<hyper::body::Bytes>::new(
878                                                            "404 Not Found".into(),
879                                                        ))
880                                                        .unwrap(),
881                                                );
882                                            };
883                                            return Ok::<_, std::convert::Infallible>(
884                                                hyper::Response::builder()
885                                                    .status(200)
886                                                    .header(
887                                                        hyper::http::header::CONTENT_TYPE,
888                                                        "application/json; charset=utf-8",
889                                                    )
890                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(code.into()))
891                                                    .unwrap(),
892                                            );
893                                        } else if len == 1 {
894                                            let code = format!(
895                                                r#"{{"services":[{}]}}"#,
896                                                services
897                                                    .iter()
898                                                    .map(|(n, d, c)| format!(
899                                                        r#"{{"name":"{}","desc":"{}","count":{}}}"#,
900                                                        n, d, c
901                                                    ))
902                                                    .collect::<Vec<String>>()
903                                                    .join(",")
904                                            );
905                                            return Ok::<_, std::convert::Infallible>(
906                                                hyper::Response::builder()
907                                                    .status(200)
908                                                    .header(
909                                                        hyper::http::header::CONTENT_TYPE,
910                                                        "application/json; charset=utf-8",
911                                                    )
912                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(code.into()))
913                                                    .unwrap(),
914                                            );
915                                        } else {
916                                            return Ok::<_, std::convert::Infallible>(
917                                                hyper::Response::builder()
918                                                    .status(404)
919                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
920                                                        "404 Not Found".into(),
921                                                    ))
922                                                    .unwrap(),
923                                            );
924                                        }
925                                    } else {
926                                        static DIST_DIR: include_dir::Dir =
927                                            include_dir::include_dir!("$CARGO_MANIFEST_DIR/dist");
928
929                                        let path = req.uri().path().trim_start_matches('/');
930
931                                        let mut final_path = path;
932                                        if path.is_empty() || !DIST_DIR.get_file(path).is_some() {
933                                            final_path = "index.html";
934                                        }
935
936                                        let file = DIST_DIR.get_file(final_path);
937
938                                        if let Some(file) = file {
939                                            let mime = mime_guess::from_path(final_path)
940                                                .first_or_octet_stream();
941                                            return Ok::<_, std::convert::Infallible>(
942                                                hyper::Response::builder()
943                                                    .status(200)
944                                                    .header(
945                                                        hyper::http::header::CONTENT_TYPE,
946                                                        format!("{}; charset=utf-8", mime.as_ref()),
947                                                    )
948                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
949                                                        hyper::body::Bytes::from(file.contents()),
950                                                    ))
951                                                    .unwrap(),
952                                            );
953                                        } else {
954                                            return Ok::<_, std::convert::Infallible>(
955                                                hyper::Response::builder()
956                                                    .status(404)
957                                                    .body(http_body_util::Full::<hyper::body::Bytes>::new(
958                                                        "404 Not Found".into(),
959                                                    ))
960                                                    .unwrap(),
961                                            );
962                                        }
963                                    }
964
965                                    #[cfg(all(feature = "code", not(feature = "doc")))]
966                                    return Ok::<_, std::convert::Infallible>(
967                                        hyper::Response::builder()
968                                            .status(404)
969                                            .body(http_body_util::Full::<hyper::body::Bytes>::new("404 Not Found".into()))
970                                            .unwrap(),
971                                    );
972                                } else {
973                                    return Ok::<_, std::convert::Infallible>(
974                                        hyper::Response::builder()
975                                            .status(405)
976                                            .body(http_body_util::Full::<hyper::body::Bytes>::new(
977                                                "405 Method Not Allowed".into(),
978                                            ))
979                                            .unwrap(),
980                                    );
981                                }
982
983                                #[cfg(any(not(feature = "code"), not(feature = "doc")))]
984                                return Ok::<_, std::convert::Infallible>(
985                                    hyper::Response::builder()
986                                        .status(404)
987                                        .body(http_body_util::Full::<hyper::body::Bytes>::new("404 Not Found".into()))
988                                        .unwrap(),
989                                );
990                            }
991                        }),
992                    )
993                    .await
994                    {
995                        eprintln!("Error serving connection: {:?}", err);
996                    }
997                });
998            }
999        }
1000    }
1001}
1002
1003pub trait AFastKind: Sized {
1004    fn kind() -> Kind;
1005
1006    fn field(name: &str) -> Field;
1007}
1008
1009#[derive(Debug)]
1010pub struct Tag {
1011    pub name: Option<String>,
1012    pub description: Option<String>,
1013    pub required: Option<String>,
1014    pub min: Option<(i64, String)>,
1015    pub max: Option<(i64, String)>,
1016}
1017
1018#[derive(Debug)]
1019pub struct Field {
1020    pub name: String,
1021    pub kind: Kind,
1022    pub tag: Option<Tag>,
1023}
1024
1025#[derive(Debug)]
1026pub enum Kind {
1027    Unit,
1028    I8,
1029    I16,
1030    I32,
1031    I64,
1032    I128,
1033    U8,
1034    U16,
1035    U32,
1036    U64,
1037    U128,
1038    F32,
1039    F64,
1040    Bool,
1041    String,
1042    Vec(Box<Kind>),
1043    Enum { variants: Vec<(Kind, String)> },
1044    Struct { fields: Vec<Field> },
1045    Tuple(Vec<Kind>),
1046    Nullable(Box<Kind>),
1047}