From 8536e41c64811630ce8c99eb49d81f89bfb69456 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Fri, 27 Jan 2023 16:04:04 -0500 Subject: [PATCH] rusty boio finished --- Cargo.toml | 4 ++-- public/js/home.js | 3 +-- src/api/auth.rs | 2 +- src/api/pages.rs | 1 - src/api/posts.rs | 8 ++++++-- src/console.rs | 13 +++++++++++++ src/main.rs | 38 ++++++++++++++++++++++++++++---------- src/types/extract.rs | 29 +++++++++++++++++++++-------- 8 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 src/console.rs diff --git a/Cargo.toml b/Cargo.toml index ce2f3f3..1d3a937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,9 @@ axum = { version = "0.6.4", features = ["headers"] } tower-http = { version = "0.3.5", features = ["fs"] } tower-cookies = "0.8.0" tower = "0.4.13" +bytes = "1.3.0" serde = { version = "1.0.152", features = ["derive"] } serde_json = "1.0" rusqlite = { version = "0.28.0", features = ["bundled"] } rand = "0.8.5" -time = "0.3.17" -bytes = "1.3.0" \ No newline at end of file +time = "0.3.17" \ No newline at end of file diff --git a/public/js/home.js b/public/js/home.js index fd40ebf..23f0d01 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -25,7 +25,6 @@ function parseComment(comment) { } function parsePost(post) { - console.log(post.likes) const author = data.users[post.user_id] if (author === undefined) { author = {} @@ -125,7 +124,7 @@ async function post() { } error.innerHTML = ''; data.posts.unshift({ - post_id: response.msg, + post_id: response.json.post_id, user_id: data.user.user_id, date: Date.now(), content: text, diff --git a/src/api/auth.rs b/src/api/auth.rs index b469d4d..54c4e06 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -26,7 +26,7 @@ impl Check for RegistrationRequet { Self::assert_length(&self.gender, 1, 100, "Gender can only by 1-100 characters long")?; Self::assert_range(self.day as u64, 1, 255, "Birthday day can only be between 1-255")?; Self::assert_range(self.month as u64, 1, 255, "Birthday month can only be between 1-255")?; - Self::assert_range(self.year as u64, 1, 2147483647, "Birthday year can only be between 1-2147483647")?; + Self::assert_range(self.year as u64, 1, 4294967295, "Birthday year can only be between 1-4294967295")?; Ok(()) } } diff --git a/src/api/pages.rs b/src/api/pages.rs index 749a686..4701795 100644 --- a/src/api/pages.rs +++ b/src/api/pages.rs @@ -3,7 +3,6 @@ use axum::{Router, response::{Response, Redirect, IntoResponse}, routing::get}; use crate::types::{extract::AuthorizedUser, response::ResponseCode}; async fn root(user: Option) -> Response { - println!("{}", user.is_some()); if user.is_some() { return Redirect::to("/home").into_response() } else { diff --git a/src/api/posts.rs b/src/api/posts.rs index 85ff2b2..6830c1a 100644 --- a/src/api/posts.rs +++ b/src/api/posts.rs @@ -18,11 +18,15 @@ impl Check for PostCreateRequest { async fn create(AuthorizedUser(user): AuthorizedUser, Json(body): Json) -> Response { - let Ok(_post) = Post::new(user.user_id, body.content) else { + let Ok(post) = Post::new(user.user_id, body.content) else { return ResponseCode::InternalServerError.msg("Failed to create post") }; - ResponseCode::Created.msg("Successfully created new post") + let Ok(json) = serde_json::to_string(&post) else { + return ResponseCode::InternalServerError.msg("Failed to create post") + }; + + ResponseCode::Created.json(&json) } #[derive(Deserialize)] diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..5a3c60b --- /dev/null +++ b/src/console.rs @@ -0,0 +1,13 @@ +use std::net::IpAddr; +use axum::http::{Method, Uri}; + +pub async fn log(ip: &IpAddr, method: &Method, uri: &Uri, path: Option<&str>, body: Option<&str>) { + + if path.is_some() && body.is_some() { + println!("{} {} {}{} {}", ip, method, path.unwrap(), uri, body.unwrap()); + } else { + println!("{} {} {}", ip, method, uri); + } + + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9ad772d..64abf68 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ use std::net::SocketAddr; -use axum::{Router, response::Response, http::Request, middleware::{Next, self}}; +use axum::{Router, response::Response, http::Request, middleware::{Next, self}, extract::ConnectInfo, RequestExt, body::HttpBody, Extension}; use tower_cookies::CookieManagerLayer; -use types::response::ResponseCode; +use types::{response::ResponseCode}; -use crate::api::{pages, auth, users, posts}; +use crate::{api::{pages, auth, users, posts}, types::extract::RouterURI}; mod api; mod database; mod types; +mod console; async fn serve(req: Request, next: Next) -> Response { let Ok(file) = ResponseCode::Success.file(&req.uri().to_string()).await else { @@ -16,6 +17,19 @@ async fn serve(req: Request, next: Next) -> Response { file } +async fn log(mut req: Request, next: Next) -> Response where + B: Send + Sync + 'static + HttpBody, +{ + + let Ok(ConnectInfo(info)) = req.extract_parts::>().await else { + return next.run(req).await + }; + + console::log(&info.ip(), req.method(), req.uri(), None, None).await; + + return next.run(req).await +} + async fn not_found() -> Response { match ResponseCode::NotFound.file("/404.html").await { Ok(file) => file, @@ -30,18 +44,22 @@ async fn main() { let app = Router::new() .fallback(not_found) - .layer(middleware::from_fn(serve)) .nest("/", pages::router()) - .nest("/api/auth", auth::router()) - .nest("/api/users", users::router()) - .nest("/api/posts", posts::router()) - .layer(CookieManagerLayer::new()); + .layer(middleware::from_fn(log)) + .layer(middleware::from_fn(serve)) + .nest("/api/auth", auth::router() + .layer(Extension(RouterURI("/api/auth"))) + ).nest("/api/users", users::router() + .layer(Extension(RouterURI("/api/users"))) + ).nest("/api/posts", posts::router() + .layer(Extension(RouterURI("/api/posts"))) + ).layer(CookieManagerLayer::new()); - let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); + let addr = "[::]:8080".parse::().unwrap(); println!("Listening on {}", addr); axum::Server::bind(&addr) - .serve(app.into_make_service()) + .serve(app.into_make_service_with_connect_info::()) .await .unwrap(); diff --git a/src/types/extract.rs b/src/types/extract.rs index bb50aa7..1379828 100644 --- a/src/types/extract.rs +++ b/src/types/extract.rs @@ -1,10 +1,10 @@ -use std::io::Read; +use std::{io::Read, net::SocketAddr}; -use axum::{extract::{FromRequestParts, FromRequest}, async_trait, response::Response, http::{request::Parts, Request}, TypedHeader, headers::Cookie, body::HttpBody, BoxError}; +use axum::{extract::{FromRequestParts, FromRequest, ConnectInfo}, async_trait, response::Response, http::{request::Parts, Request}, TypedHeader, headers::Cookie, body::HttpBody, BoxError, RequestExt}; use bytes::Bytes; use serde::de::DeserializeOwned; -use crate::types::{user::User, response::{ResponseCode, Result}, session::Session}; +use crate::{types::{user::User, response::{ResponseCode, Result}, session::Session}, console}; pub struct AuthorizedUser(pub User); @@ -39,24 +39,33 @@ pub struct Json(pub T); #[async_trait] impl FromRequest for Json where T: DeserializeOwned + Check, - B: HttpBody + Send + 'static, + B: HttpBody + Sync + Send + 'static, B::Data: Send, B::Error: Into, S: Send + Sync, { type Rejection = Response; - async fn from_request(req: Request, state: &S) -> Result { + async fn from_request(mut req: Request, state: &S) -> Result { + + let Ok(ConnectInfo(info)) = req.extract_parts::>().await else { + return Err(ResponseCode::InternalServerError.msg("Failed to read connection info")); + }; + let method = req.method().clone(); + let path = req.extensions().get::().unwrap().0; + let uri = req.uri().clone(); let Ok(bytes) = Bytes::from_request(req, state).await else { return Err(ResponseCode::InternalServerError.msg("Failed to read request body")); }; - let Ok(string) = String::from_utf8(bytes.bytes().flatten().collect()) else { + let Ok(body) = String::from_utf8(bytes.bytes().flatten().collect()) else { return Err(ResponseCode::BadRequest.msg("Invalid utf8 body")) }; + + console::log(&info.ip(), &method, &uri, Some(path), Some(&body)).await; - let Ok(value) = serde_json::from_str::(&string) else { + let Ok(value) = serde_json::from_str::(&body) else { return Err(ResponseCode::BadRequest.msg("Invalid request body")) }; @@ -87,4 +96,8 @@ pub trait Check { } Ok(()) } -} \ No newline at end of file +} + +#[derive(Clone)] +pub struct RouterURI(pub &'static str); +