2024-03-11 22:37:59 +05:00
|
|
|
pub mod api;
|
|
|
|
pub mod config;
|
|
|
|
pub mod db;
|
|
|
|
pub mod error_handle;
|
|
|
|
pub mod state;
|
|
|
|
|
|
|
|
use axum::{
|
|
|
|
extract::State,
|
2024-03-15 01:26:18 +05:00
|
|
|
http::{
|
2024-03-15 11:28:55 +05:00
|
|
|
header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, ORIGIN},
|
|
|
|
HeaderValue, Method, StatusCode, Uri,
|
2024-03-15 01:26:18 +05:00
|
|
|
},
|
2024-03-11 22:37:59 +05:00
|
|
|
middleware,
|
2024-03-15 11:28:55 +05:00
|
|
|
response::{IntoResponse, Json, Response},
|
2024-03-11 22:37:59 +05:00
|
|
|
routing::{get, post},
|
|
|
|
Router,
|
|
|
|
};
|
2024-03-07 01:02:24 +05:00
|
|
|
use diesel::RunQueryDsl;
|
|
|
|
use std::net::SocketAddr;
|
2024-03-11 22:37:59 +05:00
|
|
|
use std::sync::Arc;
|
2024-03-07 01:02:24 +05:00
|
|
|
use std::{env, net::Ipv4Addr};
|
2024-03-15 01:26:18 +05:00
|
|
|
use tower_http::{
|
|
|
|
cors::{Any, CorsLayer},
|
|
|
|
trace::{self, TraceLayer},
|
|
|
|
};
|
|
|
|
use tracing::Level;
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
use crate::config::Config;
|
2024-03-11 22:37:59 +05:00
|
|
|
use crate::db::{create_user, models::User};
|
|
|
|
use crate::error_handle::*;
|
|
|
|
use crate::state::AppState;
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
2024-03-15 01:26:18 +05:00
|
|
|
//init_tracing();
|
|
|
|
tracing_subscriber::fmt()
|
|
|
|
.with_target(false)
|
|
|
|
.compact()
|
|
|
|
.init();
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
let config = Config::new();
|
|
|
|
let database_url = format!(
|
|
|
|
"postgres://{}:{}@{}:{}/{}",
|
|
|
|
config.database.user,
|
|
|
|
config.database.password,
|
|
|
|
config.database.host,
|
|
|
|
config.database.port,
|
|
|
|
config.database.name
|
|
|
|
);
|
|
|
|
|
|
|
|
let pool = db::create_pool(database_url);
|
|
|
|
|
|
|
|
db::run_migrations(&pool).await;
|
|
|
|
|
2024-03-11 22:37:59 +05:00
|
|
|
let state = Arc::new(AppState {
|
2024-03-07 01:02:24 +05:00
|
|
|
database: pool.clone(),
|
|
|
|
config: config.clone(),
|
2024-03-11 22:37:59 +05:00
|
|
|
});
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
let address: SocketAddr = format!("{}:{}", config.server.address, config.server.port)
|
|
|
|
.parse()
|
|
|
|
.unwrap(); //SocketAddr::from((Ipv4Addr::UNSPECIFIED, 54600));
|
|
|
|
|
|
|
|
let lister = tokio::net::TcpListener::bind(&address).await.unwrap();
|
|
|
|
|
2024-03-15 01:26:18 +05:00
|
|
|
let cors = CorsLayer::new()
|
|
|
|
.allow_methods([Method::GET, Method::POST])
|
|
|
|
.allow_headers(Any) //vec![ORIGIN, AUTHORIZATION, ACCEPT])
|
|
|
|
.allow_origin(Any);
|
|
|
|
//.allow_credentials(true); //"http://localhost:5173".parse::<HeaderValue>().unwrap());
|
|
|
|
|
2024-03-07 01:02:24 +05:00
|
|
|
let app = Router::new()
|
2024-03-15 11:28:55 +05:00
|
|
|
.route("/", get(home))
|
|
|
|
.route("/assets/*file", get(static_handler))
|
2024-03-11 22:37:59 +05:00
|
|
|
.route("/api/v1/register_user", post(api::v1::register_user))
|
|
|
|
.route("/api/v1/login_user", post(api::v1::login_user))
|
2024-03-15 01:26:18 +05:00
|
|
|
.layer(cors)
|
|
|
|
.route("/api/v1/healthcheck", get(api::v1::healthcheck))
|
|
|
|
.route("/api/v1/users", get(users))
|
2024-03-11 22:37:59 +05:00
|
|
|
.route("/api/v1/logout_user", get(api::v1::logout_user))
|
|
|
|
.route(
|
|
|
|
"/api/v1/me",
|
|
|
|
get(api::v1::me).route_layer(middleware::from_fn_with_state(
|
|
|
|
state.clone(),
|
|
|
|
api::v1::jwt_auth,
|
|
|
|
)),
|
|
|
|
)
|
2024-03-15 01:26:18 +05:00
|
|
|
.layer(
|
|
|
|
TraceLayer::new_for_http()
|
|
|
|
.make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO))
|
|
|
|
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
|
|
|
|
)
|
2024-03-11 22:37:59 +05:00
|
|
|
.with_state(state);
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
println!("listening on http://{}", address);
|
|
|
|
|
|
|
|
axum::serve(lister, app.into_make_service())
|
|
|
|
.await
|
|
|
|
.map_err(internal_error)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-03-15 11:28:55 +05:00
|
|
|
async fn home() -> impl IntoResponse {
|
|
|
|
frontend::HomeTemplate
|
|
|
|
}
|
|
|
|
|
2024-03-11 22:37:59 +05:00
|
|
|
async fn users(
|
|
|
|
State(state): State<Arc<AppState>>,
|
|
|
|
) -> Result<Json<Vec<User>>, (StatusCode, Json<serde_json::Value>)> {
|
2024-03-07 01:02:24 +05:00
|
|
|
use db::schema::users::dsl::*;
|
|
|
|
|
2024-03-11 22:37:59 +05:00
|
|
|
let conn = state.database.get().await.unwrap();
|
2024-03-07 01:02:24 +05:00
|
|
|
|
|
|
|
let result = conn
|
|
|
|
.interact(move |conn| users.load(conn))
|
|
|
|
.await
|
|
|
|
.map_err(internal_error)?
|
|
|
|
.map_err(internal_error)?;
|
|
|
|
|
|
|
|
Ok(Json(result))
|
|
|
|
}
|
|
|
|
|
2024-03-15 11:28:55 +05:00
|
|
|
async fn static_handler(uri: Uri) -> impl IntoResponse {
|
|
|
|
let mut path = uri.path().trim_start_matches('/').to_string();
|
|
|
|
|
|
|
|
if path.starts_with("assets/") {
|
|
|
|
path = path.replace("assets/", "");
|
|
|
|
}
|
|
|
|
|
|
|
|
StaticFile(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct StaticFile<T>(pub T);
|
|
|
|
|
|
|
|
impl<T> IntoResponse for StaticFile<T>
|
|
|
|
where
|
|
|
|
T: Into<String>,
|
|
|
|
{
|
|
|
|
fn into_response(self) -> Response {
|
|
|
|
let path = self.0.into();
|
|
|
|
|
|
|
|
match frontend::Assets::get(path.as_str()) {
|
|
|
|
Some(content) => {
|
|
|
|
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
|
|
|
([(CONTENT_TYPE, mime.as_ref())], content.data).into_response()
|
|
|
|
}
|
|
|
|
None => (StatusCode::NOT_FOUND, "404 Not Found").into_response(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-07 01:02:24 +05:00
|
|
|
/*
|
|
|
|
create_user(
|
|
|
|
connection,
|
|
|
|
"L-Nafaryus",
|
|
|
|
"asdasd",
|
|
|
|
"L-Nafaryus",
|
|
|
|
"l.nafaryus@elnafo.ru",
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
|
|
|
|
let results = users
|
|
|
|
.select(User::as_select())
|
|
|
|
.load(connection)
|
|
|
|
.expect("Error loading users");
|
|
|
|
|
|
|
|
println!("Found {} users", results.len());
|
|
|
|
*/
|