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モデルにしたい…