Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions cmd/ethrex/ethrex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ use ethrex::{
utils::{NodeConfigFile, get_client_version, store_node_config_file},
};
use ethrex_p2p::{discv4::peer_table::PeerTable, types::NodeRecord};
use serde::Deserialize;
use std::{path::Path, time::Duration};
use tokio::signal::unix::{SignalKind, signal};
use tokio_util::sync::CancellationToken;
use tracing::info;

const LATEST_VERSION_URL: &str = "https://api.github.com/repos/lambdaclass/ethrex/releases/latest";

#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
#[global_allocator]
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
Expand Down Expand Up @@ -45,6 +48,80 @@ async fn server_shutdown(
info!("Server shutting down!");
}

/// Fetches the latest release version on github
/// Returns None if there was an error when requesting the latest version
async fn latest_release_version() -> Option<String> {
#[derive(Deserialize)]
struct Release {
tag_name: String,
}
let client = reqwest::Client::new();
let response = client
.get(LATEST_VERSION_URL)
.header("User-Agent", "ethrex")
.send()
.await
.ok()?;
if !response.status().is_success() {
None
} else {
Some(
response
.json::<Release>()
.await
.ok()?
.tag_name
.trim_start_matches("v")
.to_string(),
)
}
}

/// Reads current crate version
fn current_version() -> &'static str {
env!("CARGO_PKG_VERSION")
}

/// Returns true if the received latest version is higher than the current ethrex version
fn is_higher_than_current(latest_version: &str) -> bool {
let current_version_numbers = current_version()
.split(".")
.map(|c| c.parse::<u64>().unwrap_or_default());
let latest_version_numbers = latest_version
.split(".")
.map(|c| c.parse::<u64>().unwrap_or_default());
for (current, latest) in current_version_numbers.zip(latest_version_numbers) {
match current.cmp(&latest) {
std::cmp::Ordering::Less => return true,
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => return false,
};
}
false
}

/// Checks if the latest released version is higher than the current version and emits an info log
/// Won't emit a log line if the current version is newer or equal, or if there was a problem reading either version
async fn check_version_update() {
if let Some(latest_version) = latest_release_version().await
&& is_higher_than_current(&latest_version)
{
info!(
"There is a newer ethrex version available, current version: {} vs latest version: {latest_version}",
current_version()
);
}
}

/// Checks if there is a newer ethrex verison available every hour
async fn periodically_check_version_update() {
let mut interval = tokio::time::interval(Duration::from_secs(60 * 60));
loop {
interval.tick().await;
check_version_update().await;
}
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
let CLI { opts, command } = CLI::parse();
Expand All @@ -61,6 +138,7 @@ async fn main() -> eyre::Result<()> {
let log_filter_handler = init_tracing(&opts);

info!("ethrex version: {}", get_client_version());
tokio::spawn(periodically_check_version_update());

let (datadir, cancel_token, peer_table, local_node_record) =
init_l1(opts, Some(log_filter_handler)).await?;
Expand Down