Notify the user if there is a new version of lprs

This commit is contained in:
TheAwiteb 2024-01-02 21:59:53 +03:00
parent 44fa47d953
commit 4f263aa28e
No known key found for this signature in database
GPG key ID: ABF818BD15DC2D34
2 changed files with 85 additions and 19 deletions

View file

@ -30,15 +30,37 @@ pub mod utils;
mod macros; mod macros;
mod traits; mod traits;
pub use errors::{Error as LprsError, Result as LprsResult};
pub use traits::*; pub use traits::*;
pub use errors::{Error as LprsError, Result as LprsResult};
pub const STANDARDBASE: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, PAD); pub const STANDARDBASE: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, PAD);
pub const DEFAULT_PASSWORD_FILE: &str = "passwords.json";
#[cfg(feature = "update-notify")]
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(feature = "update-notify")]
pub const LAST_VERSION_CHECK_FILE: &str = ".last_version_check";
fn main() -> ExitCode { fn main() -> ExitCode {
pretty_env_logger::init(); pretty_env_logger::init();
#[cfg(feature = "update-notify")]
{
match utils::lprs_version() {
Ok(Some(new_version)) => {
println!(
"Warning: The version you are using of lprs is outdated. There is a newer version, which is `{new_version}`, and your version is `{VERSION}`
\rYou can update via: `cargo install lprs -F update-notify --locked`\n\n"
)
}
Err(err) => {
eprintln!("{err}");
return ExitCode::FAILURE;
}
_ => {}
}
}
if let Err(err) = cli::Cli::parse().run() { if let Err(err) = cli::Cli::parse().run() {
eprintln!("{err}"); eprintln!("{err}");
err.exit_code() err.exit_code()

View file

@ -18,21 +18,65 @@ use std::{fs, path::PathBuf};
use crate::{LprsError, LprsResult}; use crate::{LprsError, LprsResult};
/// Return the default passwords json file /// Returns the local project dir joined with the given file name
pub fn passwords_file() -> LprsResult<PathBuf> { pub fn local_project_file(filename: &str) -> LprsResult<PathBuf> {
if let Some(path) = directories::ProjectDirs::from("", "", "lprs") directories::ProjectDirs::from("", "", "lprs")
.map(|d| d.data_local_dir().to_path_buf().join("passwords.json")) .map(|d| d.data_local_dir().to_path_buf().join(filename))
{ .ok_or_else(|| {
if let Some(parent) = path.parent() { LprsError::ProjectDir("Can't extract the project_dir from this OS".to_owned())
std::fs::create_dir_all(parent)?; })
} }
if !path.exists() {
fs::write(&path, "[]")?; /// Returns the default passwords json file
} pub fn passwords_file() -> LprsResult<PathBuf> {
Ok(path) let password_file = local_project_file(crate::DEFAULT_PASSWORD_FILE)?;
} else { if let Some(parent) = password_file.parent() {
Err(LprsError::ProjectDir( std::fs::create_dir_all(parent)?;
"Can't extract the project_dir from this OS".to_owned(), }
)) if !password_file.exists() {
} fs::write(&password_file, "[]")?;
}
Ok(password_file)
}
/// Retuns the current lprs version from `crates.io`
#[cfg(feature = "update-notify")]
pub fn lprs_version() -> LprsResult<Option<String>> {
use std::time::SystemTime;
let last_version_check_file = local_project_file(crate::LAST_VERSION_CHECK_FILE)?;
let current_time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map_err(|_| LprsError::Other("The system time is before UNIX EPOCH!".to_owned()))?
.as_secs();
let last_check: u64 = fs::read_to_string(&last_version_check_file)
.unwrap_or_else(|_| current_time.to_string())
.parse()
.map_err(|err| {
LprsError::Other(format!(
"Check update file content is invalid time `{}`: {err}",
last_version_check_file.display()
))
})?;
fs::write(last_version_check_file, current_time.to_string())?;
// Check if the last check is before one hour or not
if (current_time - last_check) >= (60 * 60) || current_time == last_check {
if let Ok(Ok(response)) = reqwest::blocking::Client::new()
.get("https://crates.io/api/v1/crates/lprs")
.header(
"User-Agent",
format!("Lprs <{current_time}> (https://github.com/theawiteb/lprs)"),
)
.send()
.map(|r| r.text())
{
let re =
regex::Regex::new(r#""max_stable_version":"(?<version>\d+\.\d+\.\d+)""#).unwrap();
if let Some(cap) = re.captures(&response) {
return Ok(cap.name("version").map(|m| m.as_str().to_string()));
}
}
}
Ok(None)
} }