fmt
Showing
1 changed file
with
85 additions
and
37 deletions
1 | use anyhow::{Result, Context}; | 1 | use anyhow::{Context, Result}; |
2 | use tokio_postgres::{Client, NoTls}; | ||
3 | use log::{error, info, warn, trace}; | ||
4 | use std::{fs,env}; | ||
5 | use std::path::Path; | ||
6 | use chrono::Utc; | 2 | use chrono::Utc; |
7 | use clap::{Arg, Command}; | 3 | use clap::{Arg, Command}; |
8 | use dotenv::dotenv; | 4 | use dotenv::dotenv; |
5 | use log::{error, info, trace, warn}; | ||
6 | use std::path::Path; | ||
7 | use std::{env, fs}; | ||
8 | use tokio_postgres::{Client, NoTls}; | ||
9 | 9 | ||
10 | #[tokio::main] | 10 | #[tokio::main] |
11 | async fn main() { | 11 | async fn main() { |
... | @@ -22,7 +22,7 @@ async fn main() { | ... | @@ -22,7 +22,7 @@ async fn main() { |
22 | .long("data-dir") | 22 | .long("data-dir") |
23 | .env("MATTERMOST_DATA_DIRECTORY") | 23 | .env("MATTERMOST_DATA_DIRECTORY") |
24 | .help("Path to the Mattermost data directory") | 24 | .help("Path to the Mattermost data directory") |
25 | .required(true) | 25 | .required(true), |
26 | ) | 26 | ) |
27 | .arg( | 27 | .arg( |
28 | Arg::new("db_name") | 28 | Arg::new("db_name") |
... | @@ -30,7 +30,7 @@ async fn main() { | ... | @@ -30,7 +30,7 @@ async fn main() { |
30 | .long("db-name") | 30 | .long("db-name") |
31 | .env("DATABASE_NAME") | 31 | .env("DATABASE_NAME") |
32 | .help("Database name") | 32 | .help("Database name") |
33 | .required(true) | 33 | .required(true), |
34 | ) | 34 | ) |
35 | .arg( | 35 | .arg( |
36 | Arg::new("db_user") | 36 | Arg::new("db_user") |
... | @@ -38,7 +38,7 @@ async fn main() { | ... | @@ -38,7 +38,7 @@ async fn main() { |
38 | .long("db-user") | 38 | .long("db-user") |
39 | .env("DATABASE_USER") | 39 | .env("DATABASE_USER") |
40 | .help("Database user") | 40 | .help("Database user") |
41 | .required(true) | 41 | .required(true), |
42 | ) | 42 | ) |
43 | .arg( | 43 | .arg( |
44 | Arg::new("db_password") | 44 | Arg::new("db_password") |
... | @@ -54,7 +54,7 @@ async fn main() { | ... | @@ -54,7 +54,7 @@ async fn main() { |
54 | .long("db-host") | 54 | .long("db-host") |
55 | .env("DATABASE_HOST") | 55 | .env("DATABASE_HOST") |
56 | .help("Database host") | 56 | .help("Database host") |
57 | .required(true) | 57 | .required(true), |
58 | ) | 58 | ) |
59 | .arg( | 59 | .arg( |
60 | Arg::new("db_port") | 60 | Arg::new("db_port") |
... | @@ -62,7 +62,7 @@ async fn main() { | ... | @@ -62,7 +62,7 @@ async fn main() { |
62 | .long("db-port") | 62 | .long("db-port") |
63 | .env("DATABASE_PORT") | 63 | .env("DATABASE_PORT") |
64 | .help("Database port") | 64 | .help("Database port") |
65 | .required(true) | 65 | .required(true), |
66 | ) | 66 | ) |
67 | .arg( | 67 | .arg( |
68 | Arg::new("retention_days") | 68 | Arg::new("retention_days") |
... | @@ -70,7 +70,7 @@ async fn main() { | ... | @@ -70,7 +70,7 @@ async fn main() { |
70 | .long("retention-days") | 70 | .long("retention-days") |
71 | .env("RETENTION_DAYS") | 71 | .env("RETENTION_DAYS") |
72 | .help("Number of days to retain data") | 72 | .help("Number of days to retain data") |
73 | .required(true) | 73 | .required(true), |
74 | ) | 74 | ) |
75 | .arg( | 75 | .arg( |
76 | Arg::new("file_batch_size") | 76 | Arg::new("file_batch_size") |
... | @@ -84,13 +84,13 @@ async fn main() { | ... | @@ -84,13 +84,13 @@ async fn main() { |
84 | Arg::new("remove_posts") | 84 | Arg::new("remove_posts") |
85 | .long("remove-posts") | 85 | .long("remove-posts") |
86 | .help("Wipe posts older than timestamp") | 86 | .help("Wipe posts older than timestamp") |
87 | .required(false) | 87 | .required(false), |
88 | ) | 88 | ) |
89 | .arg( | 89 | .arg( |
90 | Arg::new("dry_run") | 90 | Arg::new("dry_run") |
91 | .long("dry-run") | 91 | .long("dry-run") |
92 | .help("Perform a dry run without making any changes") | 92 | .help("Perform a dry run without making any changes") |
93 | .required(false) | 93 | .required(false), |
94 | ) | 94 | ) |
95 | .get_matches(); | 95 | .get_matches(); |
96 | 96 | ||
... | @@ -105,9 +105,13 @@ async fn main() { | ... | @@ -105,9 +105,13 @@ async fn main() { |
105 | let remove_posts = matches.contains_id("remove_posts"); | 105 | let remove_posts = matches.contains_id("remove_posts"); |
106 | let dry_run = matches.contains_id("dry_run"); | 106 | let dry_run = matches.contains_id("dry_run"); |
107 | 107 | ||
108 | let retention_days = retention_days.parse::<i64>().expect("fucking hell retention"); | 108 | let retention_days = retention_days |
109 | let file_batch_size = file_batch_size.parse::<usize>().expect("fucking hell retention"); | 109 | .parse::<i64>() |
110 | //let file_batch_size = file_batch_size.parse::<usize>().expect("fucking hell retention"); | 110 | .expect("fucking hell retention"); |
111 | let file_batch_size = file_batch_size | ||
112 | .parse::<usize>() | ||
113 | .expect("fucking hell batch size"); | ||
114 | |||
111 | if let Err(err) = clean( | 115 | if let Err(err) = clean( |
112 | mattermost_data_directory, | 116 | mattermost_data_directory, |
113 | database_name, | 117 | database_name, |
... | @@ -119,7 +123,9 @@ async fn main() { | ... | @@ -119,7 +123,9 @@ async fn main() { |
119 | file_batch_size, | 123 | file_batch_size, |
120 | remove_posts, | 124 | remove_posts, |
121 | dry_run, | 125 | dry_run, |
122 | ).await { | 126 | ) |
127 | .await | ||
128 | { | ||
123 | error!("Cleaning operation failed: {}", err); | 129 | error!("Cleaning operation failed: {}", err); |
124 | } else { | 130 | } else { |
125 | info!("Cleaning operation completed successfully."); | 131 | info!("Cleaning operation completed successfully."); |
... | @@ -152,7 +158,9 @@ pub async fn clean( | ... | @@ -152,7 +158,9 @@ pub async fn clean( |
152 | database_user, database_password, database_host, database_port, database_name | 158 | database_user, database_password, database_host, database_port, database_name |
153 | ); | 159 | ); |
154 | trace!("Connection string: {}", &connection_string); | 160 | trace!("Connection string: {}", &connection_string); |
155 | let (client, connection) = tokio_postgres::connect(&connection_string, NoTls).await.context("Failed to connect to the database")?; | 161 | let (client, connection) = tokio_postgres::connect(&connection_string, NoTls) |
162 | .await | ||
163 | .context("Failed to connect to the database")?; | ||
156 | 164 | ||
157 | tokio::spawn(async move { | 165 | tokio::spawn(async move { |
158 | if let Err(e) = connection.await { | 166 | if let Err(e) = connection.await { |
... | @@ -163,7 +171,14 @@ pub async fn clean( | ... | @@ -163,7 +171,14 @@ pub async fn clean( |
163 | info!("Connection established: OK"); | 171 | info!("Connection established: OK"); |
164 | let millisecond_epoch = (Utc::now() - chrono::Duration::days(retention_days)).timestamp_millis(); | 172 | let millisecond_epoch = (Utc::now() - chrono::Duration::days(retention_days)).timestamp_millis(); |
165 | 173 | ||
166 | clean_files(&client, millisecond_epoch, mattermost_data_directory, file_batch_size, dry_run).await?; | 174 | clean_files( |
175 | &client, | ||
176 | millisecond_epoch, | ||
177 | mattermost_data_directory, | ||
178 | file_batch_size, | ||
179 | dry_run, | ||
180 | ) | ||
181 | .await?; | ||
167 | delete_file_info_rows(&client, millisecond_epoch, dry_run).await?; | 182 | delete_file_info_rows(&client, millisecond_epoch, dry_run).await?; |
168 | if remove_posts { | 183 | if remove_posts { |
169 | delete_post_rows(&client, millisecond_epoch, dry_run).await?; | 184 | delete_post_rows(&client, millisecond_epoch, dry_run).await?; |
... | @@ -192,7 +207,8 @@ async fn clean_files( | ... | @@ -192,7 +207,8 @@ async fn clean_files( |
192 | file_batch_size, | 207 | file_batch_size, |
193 | batch, | 208 | batch, |
194 | dry_run, | 209 | dry_run, |
195 | ).await?; | 210 | ) |
211 | .await?; | ||
196 | batch += 1; | 212 | batch += 1; |
197 | } | 213 | } |
198 | 214 | ||
... | @@ -214,13 +230,14 @@ async fn clean_files_batch( | ... | @@ -214,13 +230,14 @@ async fn clean_files_batch( |
214 | OFFSET $2 | 230 | OFFSET $2 |
215 | LIMIT $3; | 231 | LIMIT $3; |
216 | "; | 232 | "; |
217 | trace!("Querying: {}",&query); | 233 | trace!("Querying: {}", &query); |
218 | let offset = (batch * file_batch_size) as i64; | 234 | let offset = (batch * file_batch_size) as i64; |
219 | let limit = file_batch_size as i64; | 235 | let limit = file_batch_size as i64; |
220 | trace!("params: {} {} {}",&millisecond_epoch, &offset, &limit); | 236 | trace!("params: {} {} {}", &millisecond_epoch, &offset, &limit); |
221 | let rows = client | 237 | let rows = client |
222 | .query(query, &[&millisecond_epoch, &offset, &limit]) | 238 | .query(query, &[&millisecond_epoch, &offset, &limit]) |
223 | .await.context("Failed to fetch file info rows")?; | 239 | .await |
240 | .context("Failed to fetch file info rows")?; | ||
224 | 241 | ||
225 | let mut more_results = false; | 242 | let mut more_results = false; |
226 | 243 | ||
... | @@ -231,23 +248,38 @@ async fn clean_files_batch( | ... | @@ -231,23 +248,38 @@ async fn clean_files_batch( |
231 | let preview_path: String = row.get("previewpath"); | 248 | let preview_path: String = row.get("previewpath"); |
232 | 249 | ||
233 | if dry_run { | 250 | if dry_run { |
234 | info!("[DRY RUN] Would remove: {:?}, {:?}, {:?}", path, thumbnail_path, preview_path); | 251 | info!( |
252 | "[DRY RUN] Would remove: {:?}, {:?}, {:?}", | ||
253 | path, thumbnail_path, preview_path | ||
254 | ); | ||
235 | } else { | 255 | } else { |
236 | remove_files(mattermost_data_directory, &path, &thumbnail_path, &preview_path).context("Failed to remove files")?; | 256 | remove_files( |
257 | mattermost_data_directory, | ||
258 | &path, | ||
259 | &thumbnail_path, | ||
260 | &preview_path, | ||
261 | ) | ||
262 | .context("Failed to remove files")?; | ||
237 | } | 263 | } |
238 | } | 264 | } |
239 | 265 | ||
240 | Ok(more_results) | 266 | Ok(more_results) |
241 | } | 267 | } |
242 | 268 | ||
243 | fn remove_files(base_dir: &str, path: &str, thumbnail_path: &str, preview_path: &str) -> Result<()> { | 269 | fn remove_files( |
270 | base_dir: &str, | ||
271 | path: &str, | ||
272 | thumbnail_path: &str, | ||
273 | preview_path: &str, | ||
274 | ) -> Result<()> { | ||
244 | let files = [path, thumbnail_path, preview_path]; | 275 | let files = [path, thumbnail_path, preview_path]; |
245 | let mut num_deleted = 0; | 276 | let mut num_deleted = 0; |
246 | for file in files { | 277 | for file in files { |
247 | if !file.is_empty() { | 278 | if !file.is_empty() { |
248 | let full_path = Path::new(base_dir).join(file); | 279 | let full_path = Path::new(base_dir).join(file); |
249 | if full_path.exists() { | 280 | if full_path.exists() { |
250 | fs::remove_file(full_path.clone()).context(format!("Failed to delete file: {:?}", &full_path))?; | 281 | fs::remove_file(full_path.clone()) |
282 | .context(format!("Failed to delete file: {:?}", &full_path))?; | ||
251 | trace!("Removed: {:#?} ", &full_path); | 283 | trace!("Removed: {:#?} ", &full_path); |
252 | num_deleted += 1; | 284 | num_deleted += 1; |
253 | } else { | 285 | } else { |
... | @@ -256,25 +288,35 @@ fn remove_files(base_dir: &str, path: &str, thumbnail_path: &str, preview_path: | ... | @@ -256,25 +288,35 @@ fn remove_files(base_dir: &str, path: &str, thumbnail_path: &str, preview_path: |
256 | } | 288 | } |
257 | } | 289 | } |
258 | if num_deleted > 0 { | 290 | if num_deleted > 0 { |
259 | info!("Deleted: {} files. Main file: {}",num_deleted,path); | 291 | info!("Deleted: {} files. Main file: {}", num_deleted, path); |
260 | } else { | 292 | } else { |
261 | trace!("No files to be deleted"); | 293 | trace!("No files to be deleted"); |
262 | } | 294 | } |
263 | Ok(()) | 295 | Ok(()) |
264 | } | 296 | } |
265 | 297 | ||
266 | async fn delete_file_info_rows(client: &Client, millisecond_epoch: i64, dry_run: bool) -> Result<()> { | 298 | async fn delete_file_info_rows( |
299 | client: &Client, | ||
300 | millisecond_epoch: i64, | ||
301 | dry_run: bool, | ||
302 | ) -> Result<()> { | ||
267 | let query = " | 303 | let query = " |
268 | DELETE FROM fileinfo | 304 | DELETE FROM fileinfo |
269 | WHERE createat < $1; | 305 | WHERE createat < $1; |
270 | "; | 306 | "; |
271 | trace!("Querying: {}",&query); | 307 | trace!("Querying: {}", &query); |
272 | trace!("Params: {:#?}",&millisecond_epoch); | 308 | trace!("Params: {:#?}", &millisecond_epoch); |
273 | if dry_run { | 309 | if dry_run { |
274 | info!("[DRY RUN] Would delete file info rows older than {}", millisecond_epoch); | 310 | info!( |
311 | "[DRY RUN] Would delete file info rows older than {}", | ||
312 | millisecond_epoch | ||
313 | ); | ||
275 | return Ok(()); | 314 | return Ok(()); |
276 | } | 315 | } |
277 | let result = client.execute(query, &[&millisecond_epoch]).await.context("Failed to delete file info rows")?; | 316 | let result = client |
317 | .execute(query, &[&millisecond_epoch]) | ||
318 | .await | ||
319 | .context("Failed to delete file info rows")?; | ||
278 | info!("Removed {} file information rows", result); | 320 | info!("Removed {} file information rows", result); |
279 | Ok(()) | 321 | Ok(()) |
280 | } | 322 | } |
... | @@ -284,13 +326,19 @@ async fn delete_post_rows(client: &Client, millisecond_epoch: i64, dry_run: bool | ... | @@ -284,13 +326,19 @@ async fn delete_post_rows(client: &Client, millisecond_epoch: i64, dry_run: bool |
284 | DELETE FROM posts | 326 | DELETE FROM posts |
285 | WHERE createat < $1; | 327 | WHERE createat < $1; |
286 | "; | 328 | "; |
287 | trace!("Querying: {}",&query); | 329 | trace!("Querying: {}", &query); |
288 | trace!("Params: {:#?}",&millisecond_epoch); | 330 | trace!("Params: {:#?}", &millisecond_epoch); |
289 | if dry_run { | 331 | if dry_run { |
290 | info!("[DRY RUN] Would delete post rows older than {}", millisecond_epoch); | 332 | info!( |
333 | "[DRY RUN] Would delete post rows older than {}", | ||
334 | millisecond_epoch | ||
335 | ); | ||
291 | return Ok(()); | 336 | return Ok(()); |
292 | } | 337 | } |
293 | let result = client.execute(query, &[&millisecond_epoch]).await.context("Failed to delete post rows")?; | 338 | let result = client |
339 | .execute(query, &[&millisecond_epoch]) | ||
340 | .await | ||
341 | .context("Failed to delete post rows")?; | ||
294 | info!("Removed {} post rows", result); | 342 | info!("Removed {} post rows", result); |
295 | Ok(()) | 343 | Ok(()) |
296 | } | 344 | } | ... | ... |
-
Please register or sign in to post a comment