diff --git a/src/cleanup_thread.rs b/src/cleanup_thread.rs new file mode 100644 index 0000000..7f294f3 --- /dev/null +++ b/src/cleanup_thread.rs @@ -0,0 +1,42 @@ +//! # Cleanup thread +//! +//! This module manage a thread that automatically delete old data +//! +//! @author Pierre Hubert + +use crate::constants::CLEAN_UP_INTERVAL; +use crate::data::error::Res; +use crate::helpers::account_helper; + +/// Start the maintenance thread +pub fn start() -> Res { + std::thread::spawn(clean_up_thread_handler); + Ok(()) +} + +/// Clean up thread handler +fn clean_up_thread_handler() { + loop { + println!("Start clean up operation"); + match do_clean() { + Ok(_) => { + println!("Clean thread executed successfully!"); + } + + Err(e) => { + eprintln!("Failed to clean data! {:#?}", e); + } + } + + std::thread::sleep(CLEAN_UP_INTERVAL); + } +} + +/// Do the cleanup +fn do_clean() -> Res { + + // Clean old login tokens + account_helper::clean_up_old_access_tokens()?; + + Ok(()) +} \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index 61ea9ea..c4f2659 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -111,4 +111,7 @@ pub const SUPPORTED_LANGUAGES: &'static [&'static str] = &["en", "fr"]; pub const USER_LAST_ACTIVITY_REFRESH: Duration = Duration::from_secs(60); /// Interval at which last activity of an access token should be recorded -pub const USER_ACCESS_TOKEN_ACTIVITY_REFRESH: Duration = Duration::from_secs(60*60); \ No newline at end of file +pub const USER_ACCESS_TOKEN_ACTIVITY_REFRESH: Duration = Duration::from_secs(60 * 60); + +/// Interval between each cleanup operation (every hour) +pub const CLEAN_UP_INTERVAL: Duration = Duration::from_secs(60 * 60); \ No newline at end of file diff --git a/src/helpers/account_helper.rs b/src/helpers/account_helper.rs index dace58c..20f06c1 100644 --- a/src/helpers/account_helper.rs +++ b/src/helpers/account_helper.rs @@ -13,7 +13,7 @@ use crate::data::security_settings::SecuritySettings; use crate::data::user::{AccountImageVisibility, User, UserID, UserPageStatus}; use crate::data::user_token::UserAccessToken; use crate::helpers::{comments_helper, conversations_helper, custom_emojies_helper, database, events_helper, friends_helper, groups_helper, likes_helper, notifications_helper, posts_helper, survey_helper, user_helper}; -use crate::helpers::database::{DeleteQuery, InsertQuery, QueryInfo, UpdateInfo}; +use crate::helpers::database::{DeleteQuery, InsertQuery, QueryInfo, RowResult, UpdateInfo}; use crate::helpers::events_helper::Event; use crate::helpers::likes_helper::LikeType; use crate::utils::crypt_utils::{legacy_crypt_pass, rand_str}; @@ -76,16 +76,7 @@ pub fn find_user_by_login_token(token: &str, client: &APIClient) -> ResultBoxErr .cond("token", token) .set_custom_where("last_refresh + timeout > ?") .add_custom_where_argument_u64(time()) - .query_row(|res| { - Ok(UserAccessToken { - id: res.get_u64("id")?, - client_id: res.get_u64("client_id")?, - user_id: res.get_user_id("user_id")?, - token: res.get_str("token")?, - last_refresh: res.get_u64("last_refresh")?, - timeout: res.get_u64("timeout")?, - }) - }) + .query_row(db_to_user_access_token) } /// Check out whether an email address exists or not @@ -116,6 +107,20 @@ pub fn destroy_login_tokens(access_tokens: &UserAccessToken) -> Res { Ok(()) } +/// Clean up old access tokens +pub fn clean_up_old_access_tokens() -> Res { + let to_delete = QueryInfo::new(USER_ACCESS_TOKENS_TABLE) + .set_custom_where("last_refresh + timeout < ?") + .add_custom_where_argument_u64(time()) + .exec(db_to_user_access_token)?; + + for token in to_delete { + destroy_login_tokens(&token)?; + } + + Ok(()) +} + /// Destroy all login tokens of a user pub fn destroy_all_user_tokens(id: &UserID) -> ResultBoxError { user_ws_controller::disconnect_user_from_all_sockets(id)?; @@ -379,4 +384,15 @@ fn validate_password(user: &User, password: &str) -> Res { change_password(&user.id, password)?; Ok(true) +} + +fn db_to_user_access_token(res: &RowResult) -> Res { + Ok(UserAccessToken { + id: res.get_u64("id")?, + client_id: res.get_u64("client_id")?, + user_id: res.get_user_id("user_id")?, + token: res.get_str("token")?, + last_refresh: res.get_u64("last_refresh")?, + timeout: res.get_u64("timeout")?, + }) } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 696580c..6eee740 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,4 +14,5 @@ pub mod utils; pub mod constants; pub mod server; pub mod user_ws_routes; -pub mod routes; \ No newline at end of file +pub mod routes; +pub mod cleanup_thread; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6b8e3c7..aad276a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ +use comunic_server::{cleanup_thread, server}; use comunic_server::data::config::{conf, Config}; use comunic_server::helpers::database; -use comunic_server::server; #[actix_rt::main] async fn main() -> std::io::Result<()> { @@ -15,6 +15,9 @@ async fn main() -> std::io::Result<()> { // Connect to the database database::connect(&conf().database).expect("Could not connect to database!"); + // Start cleanup thread + cleanup_thread::start().expect("Failed to start cleanup thread!"); + // Start the server server::start_server(conf()).await }