rusty boio finished
This commit is contained in:
parent
6bea3bf2ef
commit
8536e41c64
8 changed files with 72 additions and 26 deletions
|
@ -9,9 +9,9 @@ axum = { version = "0.6.4", features = ["headers"] }
|
||||||
tower-http = { version = "0.3.5", features = ["fs"] }
|
tower-http = { version = "0.3.5", features = ["fs"] }
|
||||||
tower-cookies = "0.8.0"
|
tower-cookies = "0.8.0"
|
||||||
tower = "0.4.13"
|
tower = "0.4.13"
|
||||||
|
bytes = "1.3.0"
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
time = "0.3.17"
|
time = "0.3.17"
|
||||||
bytes = "1.3.0"
|
|
|
@ -25,7 +25,6 @@ function parseComment(comment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePost(post) {
|
function parsePost(post) {
|
||||||
console.log(post.likes)
|
|
||||||
const author = data.users[post.user_id]
|
const author = data.users[post.user_id]
|
||||||
if (author === undefined) {
|
if (author === undefined) {
|
||||||
author = {}
|
author = {}
|
||||||
|
@ -125,7 +124,7 @@ async function post() {
|
||||||
}
|
}
|
||||||
error.innerHTML = '';
|
error.innerHTML = '';
|
||||||
data.posts.unshift({
|
data.posts.unshift({
|
||||||
post_id: response.msg,
|
post_id: response.json.post_id,
|
||||||
user_id: data.user.user_id,
|
user_id: data.user.user_id,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
content: text,
|
content: text,
|
||||||
|
|
|
@ -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_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.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.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ use axum::{Router, response::{Response, Redirect, IntoResponse}, routing::get};
|
||||||
use crate::types::{extract::AuthorizedUser, response::ResponseCode};
|
use crate::types::{extract::AuthorizedUser, response::ResponseCode};
|
||||||
|
|
||||||
async fn root(user: Option<AuthorizedUser>) -> Response {
|
async fn root(user: Option<AuthorizedUser>) -> Response {
|
||||||
println!("{}", user.is_some());
|
|
||||||
if user.is_some() {
|
if user.is_some() {
|
||||||
return Redirect::to("/home").into_response()
|
return Redirect::to("/home").into_response()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,11 +18,15 @@ impl Check for PostCreateRequest {
|
||||||
|
|
||||||
async fn create(AuthorizedUser(user): AuthorizedUser, Json(body): Json<PostCreateRequest>) -> Response {
|
async fn create(AuthorizedUser(user): AuthorizedUser, Json(body): Json<PostCreateRequest>) -> 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")
|
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)]
|
#[derive(Deserialize)]
|
||||||
|
|
13
src/console.rs
Normal file
13
src/console.rs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
38
src/main.rs
38
src/main.rs
|
@ -1,13 +1,14 @@
|
||||||
use std::net::SocketAddr;
|
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 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 api;
|
||||||
mod database;
|
mod database;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod console;
|
||||||
|
|
||||||
async fn serve<B>(req: Request<B>, next: Next<B>) -> Response {
|
async fn serve<B>(req: Request<B>, next: Next<B>) -> Response {
|
||||||
let Ok(file) = ResponseCode::Success.file(&req.uri().to_string()).await else {
|
let Ok(file) = ResponseCode::Success.file(&req.uri().to_string()).await else {
|
||||||
|
@ -16,6 +17,19 @@ async fn serve<B>(req: Request<B>, next: Next<B>) -> Response {
|
||||||
file
|
file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn log<B>(mut req: Request<B>, next: Next<B>) -> Response where
|
||||||
|
B: Send + Sync + 'static + HttpBody,
|
||||||
|
{
|
||||||
|
|
||||||
|
let Ok(ConnectInfo(info)) = req.extract_parts::<ConnectInfo<SocketAddr>>().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 {
|
async fn not_found() -> Response {
|
||||||
match ResponseCode::NotFound.file("/404.html").await {
|
match ResponseCode::NotFound.file("/404.html").await {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
|
@ -30,18 +44,22 @@ async fn main() {
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.fallback(not_found)
|
.fallback(not_found)
|
||||||
.layer(middleware::from_fn(serve))
|
|
||||||
.nest("/", pages::router())
|
.nest("/", pages::router())
|
||||||
.nest("/api/auth", auth::router())
|
.layer(middleware::from_fn(log))
|
||||||
.nest("/api/users", users::router())
|
.layer(middleware::from_fn(serve))
|
||||||
.nest("/api/posts", posts::router())
|
.nest("/api/auth", auth::router()
|
||||||
.layer(CookieManagerLayer::new());
|
.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::<std::net::SocketAddr>().unwrap();
|
||||||
println!("Listening on {}", addr);
|
println!("Listening on {}", addr);
|
||||||
|
|
||||||
axum::Server::bind(&addr)
|
axum::Server::bind(&addr)
|
||||||
.serve(app.into_make_service())
|
.serve(app.into_make_service_with_connect_info::<SocketAddr>())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -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 bytes::Bytes;
|
||||||
use serde::de::DeserializeOwned;
|
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);
|
pub struct AuthorizedUser(pub User);
|
||||||
|
|
||||||
|
@ -39,24 +39,33 @@ pub struct Json<T>(pub T);
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T, S, B> FromRequest<S, B> for Json<T> where
|
impl<T, S, B> FromRequest<S, B> for Json<T> where
|
||||||
T: DeserializeOwned + Check,
|
T: DeserializeOwned + Check,
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Sync + Send + 'static,
|
||||||
B::Data: Send,
|
B::Data: Send,
|
||||||
B::Error: Into<BoxError>,
|
B::Error: Into<BoxError>,
|
||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
{
|
{
|
||||||
type Rejection = Response;
|
type Rejection = Response;
|
||||||
|
|
||||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self> {
|
async fn from_request(mut req: Request<B>, state: &S) -> Result<Self> {
|
||||||
|
|
||||||
|
let Ok(ConnectInfo(info)) = req.extract_parts::<ConnectInfo<SocketAddr>>().await else {
|
||||||
|
return Err(ResponseCode::InternalServerError.msg("Failed to read connection info"));
|
||||||
|
};
|
||||||
|
let method = req.method().clone();
|
||||||
|
let path = req.extensions().get::<RouterURI>().unwrap().0;
|
||||||
|
let uri = req.uri().clone();
|
||||||
|
|
||||||
let Ok(bytes) = Bytes::from_request(req, state).await else {
|
let Ok(bytes) = Bytes::from_request(req, state).await else {
|
||||||
return Err(ResponseCode::InternalServerError.msg("Failed to read request body"));
|
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"))
|
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::<T>(&string) else {
|
let Ok(value) = serde_json::from_str::<T>(&body) else {
|
||||||
return Err(ResponseCode::BadRequest.msg("Invalid request body"))
|
return Err(ResponseCode::BadRequest.msg("Invalid request body"))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,4 +96,8 @@ pub trait Check {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RouterURI(pub &'static str);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue