This makes integration testing much easier as it can reuse the app instance.
This commit is contained in:
parent
79c4ab6c2b
commit
b22588cd0d
76
src/lib.rs
76
src/lib.rs
|
@ -11,3 +11,79 @@ pub mod middleware;
|
||||||
mod test_utils;
|
mod test_utils;
|
||||||
|
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
|
|
||||||
|
use actix_identity::IdentityMiddleware;
|
||||||
|
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
||||||
|
use actix_web::middleware::ErrorHandlers;
|
||||||
|
use actix_web::{cookie::Key, http::StatusCode, web, App, HttpResponse};
|
||||||
|
use base64::prelude::{Engine as _, BASE64_STANDARD};
|
||||||
|
use log::warn;
|
||||||
|
use mime_guess::from_path;
|
||||||
|
use rust_embed::Embed;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::database::{
|
||||||
|
ItemClassRepository, ItemEventRepository, ItemRepository, ItemStateRepository,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Embed)]
|
||||||
|
#[folder = "static"]
|
||||||
|
struct Static;
|
||||||
|
|
||||||
|
pub fn app(
|
||||||
|
config: &Config,
|
||||||
|
pool: &PgPool,
|
||||||
|
) -> App<
|
||||||
|
impl actix_web::dev::ServiceFactory<
|
||||||
|
actix_web::dev::ServiceRequest,
|
||||||
|
Config = (),
|
||||||
|
Response = actix_web::dev::ServiceResponse<
|
||||||
|
actix_web::body::EitherBody<actix_web::body::BoxBody>,
|
||||||
|
>,
|
||||||
|
Error = actix_web::Error,
|
||||||
|
InitError = (),
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
let secret_key = match config.secret_key {
|
||||||
|
Some(ref encoded) => Key::from(
|
||||||
|
&BASE64_STANDARD
|
||||||
|
.decode(encoded)
|
||||||
|
.expect("failed to decode base64 in SECRET_KEY"),
|
||||||
|
),
|
||||||
|
None => {
|
||||||
|
warn!("SECRET_KEY was not specified, using randomly generated key");
|
||||||
|
Key::generate()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
App::new()
|
||||||
|
.app_data(web::Data::new(config.clone()))
|
||||||
|
.app_data(web::Data::new(pool.clone()))
|
||||||
|
.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())))
|
||||||
|
.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(()))
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.configure(frontend::config)
|
||||||
|
.wrap(ErrorHandlers::new().handler(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
middleware::error_handlers::redirect_to_login,
|
||||||
|
))
|
||||||
|
.wrap(IdentityMiddleware::default())
|
||||||
|
.wrap(SessionMiddleware::new(
|
||||||
|
CookieSessionStore::default(),
|
||||||
|
secret_key.clone(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -2,45 +2,20 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
use actix_identity::IdentityMiddleware;
|
use actix_web::HttpServer;
|
||||||
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
|
||||||
use actix_web::middleware::ErrorHandlers;
|
|
||||||
use actix_web::{cookie::Key, http::StatusCode, web, App, HttpResponse, HttpServer};
|
|
||||||
use base64::prelude::{Engine as _, BASE64_STANDARD};
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use li7y::database::item_events::ItemEventRepository;
|
use log::info;
|
||||||
use li7y::database::item_states::ItemStateRepository;
|
|
||||||
use li7y::database::items::ItemRepository;
|
|
||||||
use li7y::database::ItemClassRepository;
|
|
||||||
use log::{info, warn};
|
|
||||||
use mime_guess::from_path;
|
|
||||||
use rust_embed::Embed;
|
|
||||||
|
|
||||||
use li7y::Config;
|
use li7y::Config;
|
||||||
|
|
||||||
#[derive(Embed)]
|
|
||||||
#[folder = "static"]
|
|
||||||
struct Static;
|
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||||
|
|
||||||
let config = Config::parse();
|
let config = Config::parse();
|
||||||
|
|
||||||
let secret_key = match config.secret_key {
|
// This can’t be included in app, because app gets called in a (non-async) closure
|
||||||
Some(ref encoded) => Key::from(
|
let pool = sqlx::Pool::<sqlx::postgres::Postgres>::connect(&config.database_url)
|
||||||
&BASE64_STANDARD
|
|
||||||
.decode(encoded)
|
|
||||||
.expect("failed to decode base64 in SECRET_KEY"),
|
|
||||||
),
|
|
||||||
None => {
|
|
||||||
warn!("SECRET_KEY was not specified, using randomly generated key");
|
|
||||||
Key::generate()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool: sqlx::PgPool = sqlx::Pool::<sqlx::postgres::Postgres>::connect(&config.database_url)
|
|
||||||
.await
|
.await
|
||||||
.expect("failed to connect to database");
|
.expect("failed to connect to database");
|
||||||
|
|
||||||
|
@ -54,38 +29,7 @@ async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
info!("Starting on {address}:{port}");
|
info!("Starting on {address}:{port}");
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || li7y::app(&config, &pool))
|
||||||
App::new()
|
|
||||||
.app_data(web::Data::new(config.clone()))
|
|
||||||
.app_data(web::Data::new(pool.clone()))
|
|
||||||
.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())))
|
|
||||||
.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(()))
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.configure(li7y::frontend::config)
|
|
||||||
.wrap(ErrorHandlers::new().handler(
|
|
||||||
StatusCode::UNAUTHORIZED,
|
|
||||||
li7y::middleware::error_handlers::redirect_to_login,
|
|
||||||
))
|
|
||||||
.wrap(IdentityMiddleware::default())
|
|
||||||
.wrap(SessionMiddleware::new(
|
|
||||||
CookieSessionStore::default(),
|
|
||||||
secret_key.clone(),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.bind((address, port))?
|
.bind((address, port))?
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Reference in a new issue