racoon 0.1.3

Racoon is a fast, fully customizable web framework for Rust focusing on simplicity.
Documentation
# Racoon

<p align="center" style="text-align: center;">
    <img src="logo.png" width="300">
    <br>
    <a href="https://github.com/racoonframework/racoon/actions/workflows/build.yml">
        <img src="https://github.com/racoonframework/racoon/actions/workflows/build.yml/badge.svg" alt="Racoon">
    </a>
</p>


Racoon is a fast, fully customizable web framework for Rust focusing on simplicity.

To use Racoon, you need minimal Rust version `1.75.0` and `Tokio` runtime.


[Learn Racoon](https://racoonframework.github.io)

## Installation

You will need `tokio` runtime to run Racoon. Run `cargo add tokio` to install tokio crate.

```toml
[dependencies]
racoon = "0.1.3"
```

## Basic Usage

```rust
use racoon::core::path::Path;
use racoon::core::request::Request;
use racoon::core::response::{HttpResponse, Response};
use racoon::core::response::status::ResponseStatus;
use racoon::core::server::Server;

use racoon::view;

async fn home(request: Request) -> Response {
    HttpResponse::ok().body("Home")
}

#[tokio::main]
async fn main() {
    let paths = vec![
        Path::new("/", view!(home))
    ];

    let result = Server::bind("127.0.0.1:8080")
        .urls(paths)
        .run().await;

    println!("Failed to run server: {:?}", result);
}
```

### File Handling

There are multiple ways to handle files in Racoon. The simple way is to use `request.parse()` method.

```rust
use racoon::core::request::Request;
use racoon::core::response::{HttpResponse, Response};
use racoon::core::response::status::ResponseStatus;
use racoon::core::forms::FileField;
use racoon::core::shortcuts::SingleText;

async fn upload_form(request: Request) -> Response {
    if request.method == "POST" {
        // Parses request body
        let (form_data, files) = request.parse().await;
        println!("Name: {:?}", form_data.value("name"));

        let file = files.value("file");
        println!("File: {:?}", file);
        return HttpResponse::ok().body("Uploaded");
    }

    HttpResponse::bad_request().body("Use POST method to upload file.")
}
```

For more information check [form handling guide](https://racoonframework.github.io/reading-form-data/).

## WebSocket example

```rust
use racoon::core::path::Path;
use racoon::core::request::Request;
use racoon::core::response::Response;
use racoon::core::server::Server;
use racoon::core::websocket::{Message, WebSocket};

use racoon::view;

async fn ws(request: Request) -> Response {
    let (websocket, connected) = WebSocket::from(&request).await;
    if !connected {
        // WebSocket connection didn't success
        return websocket.bad_request().await;
    }

    println!("WebSocket client connected.");

    // Receive incoming messages
    while let Some(message) = websocket.message().await {
        match message {
            Message::Text(text) => {
                println!("Message: {}", text);

                // Sends received message back
                let _ = websocket.send_text(text.as_str()).await;
            }
            _ => {}
        }
    }
    websocket.exit()
}

#[tokio::main]
async fn main() {
    let paths = vec![
        Path::new("/ws/", view!(ws))
        ];

    let _ = Server::bind("127.0.0.1:8080")
            .urls(paths)
            .run().await;
}
```


## Benchmark

```shell
wrk -c200 -d8s -t8 http://127.0.0.1:8080
```

Result on AMD Ryzen 5 7520U with Radeon Graphics.

```text
Running 8s test @ http://127.0.0.1:8080
  8 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.12ms  671.82us  13.10ms   76.52%
    Req/Sec    22.05k     2.80k   29.14k    73.44%
  1406346 requests in 8.02s, 256.17MB read
Requests/sec: 175380.14
Transfer/sec:     31.95MB
```

This benchmark does not make sense in real world.