2024-06-24 22:46:04 +02:00
|
|
|
// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
|
2024-07-13 13:41:23 +02:00
|
|
|
use actix_identity::IdentityMiddleware;
|
|
|
|
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
|
|
|
use actix_web::middleware::ErrorHandlers;
|
2024-07-14 18:31:08 +02:00
|
|
|
use actix_web::{cookie::Key, http::StatusCode, web, App, HttpResponse, HttpServer};
|
2024-07-13 13:41:23 +02:00
|
|
|
use base64::prelude::{Engine as _, BASE64_STANDARD};
|
2024-07-24 11:45:06 +02:00
|
|
|
use clap::Parser;
|
2024-07-25 17:49:19 +02:00
|
|
|
use li7y::database::item_events::ItemEventRepository;
|
|
|
|
use li7y::database::item_states::ItemStateRepository;
|
|
|
|
use li7y::database::items::ItemRepository;
|
|
|
|
use li7y::database::ItemClassRepository;
|
2024-07-14 18:31:08 +02:00
|
|
|
use log::{info, warn};
|
|
|
|
use mime_guess::from_path;
|
|
|
|
use rust_embed::Embed;
|
|
|
|
|
2024-07-24 11:45:06 +02:00
|
|
|
use li7y::Config;
|
|
|
|
|
2024-07-14 18:31:08 +02:00
|
|
|
#[derive(Embed)]
|
|
|
|
#[folder = "static"]
|
|
|
|
struct Static;
|
2024-06-24 22:46:04 +02:00
|
|
|
|
|
|
|
#[actix_web::main]
|
|
|
|
async fn main() -> std::io::Result<()> {
|
2024-07-13 11:33:46 +02:00
|
|
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
2024-06-24 22:46:04 +02:00
|
|
|
|
2024-07-24 11:45:06 +02:00
|
|
|
let config = Config::parse();
|
|
|
|
|
|
|
|
let secret_key = match config.secret_key {
|
|
|
|
Some(ref encoded) => Key::from(
|
2024-07-13 13:41:23 +02:00
|
|
|
&BASE64_STANDARD
|
|
|
|
.decode(encoded)
|
|
|
|
.expect("failed to decode base64 in SECRET_KEY"),
|
|
|
|
),
|
2024-07-24 11:45:06 +02:00
|
|
|
None => {
|
2024-07-13 13:41:23 +02:00
|
|
|
warn!("SECRET_KEY was not specified, using randomly generated key");
|
|
|
|
Key::generate()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-07-24 11:45:06 +02:00
|
|
|
let pool: sqlx::PgPool = sqlx::Pool::<sqlx::postgres::Postgres>::connect(&config.database_url)
|
|
|
|
.await
|
|
|
|
.expect("failed to connect to database");
|
2024-06-24 22:46:04 +02:00
|
|
|
|
2024-07-11 17:25:01 +02:00
|
|
|
sqlx::migrate!()
|
|
|
|
.run(&pool)
|
|
|
|
.await
|
|
|
|
.expect("failed to run migrations");
|
2024-06-24 22:46:04 +02:00
|
|
|
|
2024-07-24 11:45:06 +02:00
|
|
|
let address = config.listen_address;
|
|
|
|
let port = config.listen_port;
|
2024-06-24 22:46:04 +02:00
|
|
|
|
2024-07-14 18:31:08 +02:00
|
|
|
info!("Starting on {address}:{port}");
|
2024-06-24 22:46:04 +02:00
|
|
|
|
|
|
|
HttpServer::new(move || {
|
|
|
|
App::new()
|
2024-07-24 11:45:06 +02:00
|
|
|
.app_data(web::Data::new(config.clone()))
|
2024-06-24 22:46:04 +02:00
|
|
|
.app_data(web::Data::new(pool.clone()))
|
2024-07-25 17:49:19 +02:00
|
|
|
.app_data(web::Data::new(ItemClassRepository::new(pool.clone())))
|
|
|
|
.app_data(web::Data::new(ItemEventRepository::new(pool.clone())))
|
|
|
|
.app_data(web::Data::new(ItemStateRepository::new(pool.clone())))
|
|
|
|
.app_data(web::Data::new(ItemRepository::new(pool.clone())))
|
2024-07-14 18:31:08 +02:00
|
|
|
.service(web::scope("/static").route(
|
|
|
|
"/{_:.*}",
|
|
|
|
web::get().to(|path: web::Path<String>| async {
|
|
|
|
Static::get(&path)
|
|
|
|
.map(|embedded_file| match from_path(path.into_inner()).first() {
|
|
|
|
Some(mime_type) => HttpResponse::Ok()
|
|
|
|
.content_type(mime_type)
|
|
|
|
.body(embedded_file.data),
|
|
|
|
None => HttpResponse::Ok().body(embedded_file.data),
|
|
|
|
})
|
|
|
|
.unwrap_or(HttpResponse::NotFound().body(()))
|
|
|
|
}),
|
|
|
|
))
|
2024-07-03 14:19:58 +02:00
|
|
|
.configure(li7y::frontend::config)
|
2024-07-13 13:41:23 +02:00
|
|
|
.wrap(ErrorHandlers::new().handler(
|
|
|
|
StatusCode::UNAUTHORIZED,
|
|
|
|
li7y::middleware::error_handlers::redirect_to_login,
|
|
|
|
))
|
|
|
|
.wrap(IdentityMiddleware::default())
|
|
|
|
.wrap(SessionMiddleware::new(
|
|
|
|
CookieSessionStore::default(),
|
|
|
|
secret_key.clone(),
|
|
|
|
))
|
2024-06-24 22:46:04 +02:00
|
|
|
})
|
|
|
|
.bind((address, port))?
|
|
|
|
.run()
|
|
|
|
.await
|
|
|
|
}
|