|
|
|
use std::{
|
|
|
|
env, io,
|
|
|
|
net::{SocketAddrV4},
|
|
|
|
sync::Arc,
|
|
|
|
};
|
|
|
|
|
|
|
|
use actix_identity::IdentityMiddleware;
|
|
|
|
use actix_session::{config::PersistentSession, storage::CookieSessionStore, SessionMiddleware};
|
|
|
|
use actix_web::{
|
|
|
|
cookie::{time::Duration, Key},
|
|
|
|
middleware,
|
|
|
|
web::{self},
|
|
|
|
App, HttpServer,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Define our model module
|
|
|
|
mod model;
|
|
|
|
use model::user::User;
|
|
|
|
// Define our repo module
|
|
|
|
mod repo;
|
|
|
|
use repo::todo_repository::TodoRepository;
|
|
|
|
use repo::user_repository::UserRepository;
|
|
|
|
// Define our routes module
|
|
|
|
mod routes;
|
|
|
|
use routes::{todo_routes, user_routes};
|
|
|
|
|
|
|
|
/// Server address if none is given via ENV: WEBSERVER_ADDRESS
|
|
|
|
static DEFAULT_WEBSERVER_ADDRESS: &str = "127.0.0.1";
|
|
|
|
/// Server port if none is given via ENV: WEBSERVER_PORT
|
|
|
|
static DEFAULT_WEBSERVER_PORT: &str = "6969";
|
|
|
|
|
|
|
|
/// Starts the webserver and initializes required repos, etc.
|
|
|
|
#[actix_web::main]
|
|
|
|
async fn main() -> io::Result<()> {
|
|
|
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("debug"));
|
|
|
|
|
|
|
|
// TODO: Currently I do not handle the case where the cassandra server is
|
|
|
|
// rebooted during the lifetime of the webserver and loses its configuration.
|
|
|
|
// Normally this is not a real scenario because the tables should be persistent
|
|
|
|
// througout reboots but idk, it would still be cool to handle this gracefully.
|
|
|
|
// What would have to happen is a reinit of the repo classes after the connection
|
|
|
|
// is regained to reinitialize the perhaps missing keyspaces/tables
|
|
|
|
let cassandra_session = Arc::new(repo::init());
|
|
|
|
|
|
|
|
// TODO: web::Data is already an Arc
|
|
|
|
//-> Investigate if we really need the session as an Arc as well
|
|
|
|
let user = User::new("admin", "init_pw_hash", "init_salt");
|
|
|
|
let user_repo = web::Data::new(UserRepository::new(Arc::clone(&cassandra_session)));
|
|
|
|
if let Err(err) = user_repo.create(&user) {
|
|
|
|
log::debug!("Default user already exists: {err}");
|
|
|
|
}
|
|
|
|
|
|
|
|
let todo_repo = web::Data::new(TodoRepository::new(Arc::clone(&cassandra_session)));
|
|
|
|
|
|
|
|
// Secret key used to init session storage
|
|
|
|
let key = Key::generate();
|
|
|
|
|
|
|
|
// External ENV params
|
|
|
|
let socket_addr: SocketAddrV4 = format!(
|
|
|
|
"{}:{}",
|
|
|
|
env::var("WEBSERVER_ADDRESS").unwrap_or(DEFAULT_WEBSERVER_ADDRESS.to_string()),
|
|
|
|
env::var("WEBSERVER_PORT").unwrap_or(DEFAULT_WEBSERVER_PORT.to_string())
|
|
|
|
).parse().expect("A valid socket address. Check your ENV variables!");
|
|
|
|
|
|
|
|
log::info!("Starting HTTP server: http://{}:{}", socket_addr.ip(), socket_addr.port());
|
|
|
|
|
|
|
|
HttpServer::new(move || {
|
|
|
|
App::new()
|
|
|
|
.wrap(middleware::Compress::default())
|
|
|
|
.wrap(IdentityMiddleware::default())
|
|
|
|
.wrap(
|
|
|
|
SessionMiddleware::builder(CookieSessionStore::default(), key.clone())
|
|
|
|
.cookie_secure(false)
|
|
|
|
// Session lifetime
|
|
|
|
.session_lifecycle(PersistentSession::default().session_ttl(Duration::days(7)))
|
|
|
|
.build(),
|
|
|
|
)
|
|
|
|
.wrap(middleware::Logger::default())
|
|
|
|
.app_data(user_repo.clone())
|
|
|
|
.app_data(todo_repo.clone())
|
|
|
|
.service(user_routes::get_user)
|
|
|
|
.service(user_routes::put_user)
|
|
|
|
.service(user_routes::post_user)
|
|
|
|
.service(todo_routes::get_todo)
|
|
|
|
.service(todo_routes::put_todo)
|
|
|
|
.service(todo_routes::delete_todo)
|
|
|
|
.service(routes::post_login)
|
|
|
|
.service(routes::delete_logout)
|
|
|
|
.default_service(web::to(routes::index))
|
|
|
|
})
|
|
|
|
.bind(socket_addr)?
|
|
|
|
.workers(2) // number of workers per bind default ist #cpus
|
|
|
|
.run()
|
|
|
|
.await
|
|
|
|
}
|