Rustで簡単なフレームワークを自作したい5

main.rs

use std::collections::HashMap;
mod ares;

fn main() {
    
    let mut content = HashMap::new();
    content.insert(
        "title",
        "index page",
    );
    content.insert(
        "data1",
        "10000",
    );

    let _ = ares::Router::new("index", Some(content));
    
}

### フレームワーク側
ares.rs

use std::fs;
use std::io;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

pub struct Router;

impl Router {
    pub fn new(path: &str, content: Option<HashMap<&str, &str>>) {

        let mut routes = HashMap::new();
        let temp_path = format!("./templates/{}.html", path);
        let mut html = fs::read_to_string(temp_path).unwrap();

        match content {
            Some(data) => {
                for (key, value) in data {
                    let k = format!("{{{{ {} }}}}", key);
                    html = html.replace(&k, value);
                }
            },
            None => {},
        }
        let route_path = format!("/{}", path);
        routes.insert(
            route_path, html,
        );
        println!("{:?}", routes);


        let listenr = TcpListener::bind("192.168.33.10:8000").unwrap();
        for stream in listenr.incoming() {
            match stream {
                Ok(stream) => {
                    let _ = handle_connection(stream, routes.clone());
                }
                Err(e) => {
                    println!("Connection failed: {}", e);
                }
            }
        }
    }
}

fn handle_connection(mut stream: TcpStream, routes: HashMap<String, String>)  {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
 
    let request = String::from_utf8_lossy(&buffer);
    let request_line = request.lines().next().unwrap_or("");
    println!("Received request:\n{}", request);
 
    let path = request_line
         .split_whitespace()
         .nth(1)
         .unwrap_or("/");
    
    let response_body = routes.get(path)
         .cloned()
         .unwrap_or_else(|| "<h1>404 Not Found</h1>".to_string());
 
    let response = http_response(200, "text/html", &response_body);
 
    stream.write_all(response.as_bytes()).unwrap();
    stream.flush().unwrap();
 }
 
 fn http_response(status_code: u16, content_type: &str, body: &str) -> String {
    format!(
        "HTTP/1.1 {} {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n{}",
        status_code,
        get_status_text(status_code),
        content_type,
        body.len(),
        body
    )
 }
 
 fn get_status_text(code: u16) -> &'static str {
    match code {
        200 => "OK",
        404 => "Not Found",
        _ => "Unknown",
    }
 }

複数パスに対応できるようにしたい。

### 複数パスに対応
hashmapにパスとコンテンツを追加するように実装する

use std::collections::HashMap;
mod ares;

fn main() {
    let mut router = ares::Router::new();

    let mut content1 = HashMap::new();
    content1.insert(
        "title",
        "index page",
    );

    let mut content2 = HashMap::new();
    content2.insert(
        "title",
        "this is title",
    );

    router.add("index", Some(content1));
    router.add("hello", None);
    router.add("world", Some(content2));

    router.up("192.168.33.10:8000");   
}
pub struct Router {
    route: HashMap<String, String>,
}

impl Router {

    pub fn new() -> Self {
        Router {
            route: HashMap::new(),
        }
    }

    pub fn add(&mut self, path: &str, content: Option<HashMap<&str, &str>>){
        let temp_path = format!("./templates/{}.html", path);
        let mut html = fs::read_to_string(temp_path).unwrap();

        match content {
            Some(data) => {
                for (key, value) in data {
                    let k = format!("{{{{ {} }}}}", key);
                    html = html.replace(&k, value);
                }
            },
            None => {},
        }
        let route_path = format!("/{}", path);
        self.route.insert(route_path, html);
    }

    pub fn up(&self, ip: &str) {
        let listenr = TcpListener::bind(ip).unwrap();
        for stream in listenr.incoming() {
            match stream {
                Ok(stream) => {
                    let _ = handle_connection(stream, self.route.clone());
                }
                Err(e) => {
                    println!("Connection failed: {}", e);
                }
            }
        }
    }
}

MVCモデルにしたい…