This repository has been archived on 2025-08-25. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
Alexandria/src/main.rs

112 lines
4.3 KiB
Rust

use std::{net::SocketAddr, sync::Arc};
use axum::{extract::State, http::HeaderMap, routing::get};
use reqwest::{header::USER_AGENT};
use sea_orm::{ConnectionTrait, Database, DatabaseConnection, EntityTrait, PaginatorTrait, Schema};
use tokio::{sync::broadcast::{self, Sender}};
use utoipa::openapi::{ContactBuilder, InfoBuilder, LicenseBuilder};
use utoipa_axum::router::OpenApiRouter;
use utoipa_redoc::{Redoc, Servable};
use utoipa_swagger_ui::{Config, SwaggerUi};
use utoipa_axum::routes;
use crate::{entities::prelude::BookInstance, utils::events::Event};
pub mod entities;
pub mod utils;
pub mod routes;
pub struct AppState {
app_name: String,
db_conn: Arc<DatabaseConnection>,
event_bus: Sender<Event>,
web_client: reqwest::Client
}
async fn index(
State(state): State<Arc<AppState>>
) ->String {
let app_name = &state.app_name;
let db_conn = &state.db_conn;
let status: &str = match db_conn.ping().await {
Ok(_) => "working",
Err(_) => "erroring"
};
let book_count = BookInstance::find().count(db_conn.as_ref()).await.unwrap();
format!("Hello from {app_name}! Database is {status}. We currently have {book_count} books in stock !")
}
#[tokio::main]
async fn main() {
pretty_env_logger::init();
let db: Arc<DatabaseConnection> = Arc::new(Database::connect(String::from("sqlite://./alexandria.db?mode=rwc")).await.unwrap());
let builder = db.get_database_backend();
let schema = Schema::new(builder);
if let Err(err) = db.execute(builder.build(schema.create_table_from_entity(crate::entities::prelude::Book).if_not_exists())).await {
log::error!(target: "database", "Error while creating book table: {err:?}");
return;
}
if let Err(err) = db.execute(builder.build(schema.create_table_from_entity(crate::entities::prelude::BookInstance).if_not_exists())).await {
log::error!(target: "database", "Error while creating book_instance table: {err:?}");
return;
}
if let Err(err) = db.execute(builder.build(schema.create_table_from_entity(crate::entities::prelude::Owner).if_not_exists())).await {
log::error!(target: "database", "Error while creating owner table: {err:?}");
return;
}
let (event_bus, _) = broadcast::channel(16);
let mut default_headers = HeaderMap::new();
default_headers.append(USER_AGENT, "Alexandria/1.0 (unionetudianteauvergne@gmail.com)".parse().unwrap());
let shared_state = Arc::new(AppState {
app_name: "Alexandria".to_string(),
db_conn: db,
event_bus,
web_client: reqwest::Client::builder().default_headers(default_headers).build().expect("creating the reqwest client failed")
});
let (router, mut api) = OpenApiRouter::new()
.routes(routes!(routes::book::get_book_by_ean))
.routes(routes!(routes::book::get_book_by_id))
.routes(routes!(routes::book_instance::get_book_instance_by_id))
.routes(routes!(routes::book_instance::create_book_instance))
.routes(routes!(routes::owner::get_owner_by_id))
.routes(routes!(routes::owner::create_owner))
.route("/ws", get(routes::websocket::ws_handler))
.route("/", get(index))
.with_state(shared_state)
.split_for_parts();
api.info = InfoBuilder::new()
.title("Alexandria")
.description(Some("Alexandria is a server that manages books and users for Union Étudiante's book exchange"))
.contact(Some(ContactBuilder::new()
.url(Some("https://ueauvergne.fr"))
.name(Some("Union Étudiante Auvergne"))
.email(Some("unionetudianteauvergne@gmail.com"))
.build()))
.license(Some(LicenseBuilder::new().name("MIT").url(Some("https://spdx.org/licenses/MIT.html")).build()))
.version("1.0.0")
.build();
let redoc = Redoc::with_url("/docs/", api.clone());
let swagger = SwaggerUi::new("/docs2/")
.url("/docs2/openapi.json", api)
.config(Config::default()
.try_it_out_enabled(true)
);
let router = router.merge(redoc);
let router = router.merge(swagger);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
log::info!("Running on http://{}", listener.local_addr().unwrap());
axum::serve(
listener,
router.into_make_service_with_connect_info::<SocketAddr>()
).await.unwrap();
}