Skip to content

Commit

Permalink
Removed all threading and switched everything to async. >2x speedup 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
sergi0g committed Sep 15, 2024
1 parent 38bf187 commit 0c9ad61
Show file tree
Hide file tree
Showing 8 changed files with 800 additions and 279 deletions.
769 changes: 646 additions & 123 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ edition = "2021"
[dependencies]
clap = { version = "4.5.7", features = ["derive"] }
indicatif = { version = "0.17.8", optional = true }
tokio = {version = "1.38.0", features = ["rt", "rt-multi-thread", "macros"]}
ureq = { version = "2.9.7", features = ["tls"] }
rayon = "1.10.0"
tokio = {version = "1.38.0", features = ["macros"]}
xitca-web = { version = "0.5.0", optional = true, features = ["logger"] }
liquid = { version = "0.26.6", optional = true }
bollard = "0.16.1"
once_cell = "1.19.0"
http-auth = { version = "0.1.9", features = [] }
http-auth = { version = "0.1.9", default-features = false, features = [] }
termsize = { version = "0.1.8", optional = true }
regex = "1.10.5"
chrono = { version = "0.4.38", default-features = false, features = ["std", "alloc", "clock"], optional = true }
json = "0.12.4"
reqwest = "0.12.7"
futures = "0.3.30"
reqwest-retry = "0.6.1"
reqwest-middleware = "0.3.3"

[features]
default = ["server", "cli"]
Expand Down
50 changes: 23 additions & 27 deletions src/check.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
use std::{
collections::{HashMap, HashSet},
sync::Mutex,
};
use std::collections::{HashMap, HashSet};

use json::JsonValue;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

use crate::{
docker::get_images_from_docker_daemon,
image::Image,
registry::{check_auth, get_latest_digests, get_token},
utils::unsplit_image,
utils::{new_reqwest_client, unsplit_image},
};

#[cfg(feature = "cli")]
Expand All @@ -37,49 +33,48 @@ pub async fn get_all_updates(
socket: Option<String>,
config: &JsonValue,
) -> Vec<(String, Option<bool>)> {
let image_map_mutex: Mutex<HashMap<String, &Option<String>>> = Mutex::new(HashMap::new());
let local_images = get_images_from_docker_daemon(socket).await;
local_images.par_iter().for_each(|image| {
let mut image_map: HashMap<String, Option<String>> = HashMap::with_capacity(local_images.len());
for image in &local_images {
let img = unsplit_image(&image.registry, &image.repository, &image.tag);
image_map_mutex.lock().unwrap().insert(img, &image.digest);
});
let image_map = image_map_mutex.lock().unwrap().clone();
image_map.insert(img, image.digest.clone());
};
let mut registries: Vec<&String> = local_images
.par_iter()
.iter()
.map(|image| &image.registry)
.collect();
registries.unique();
let mut remote_images: Vec<Image> = Vec::new();
let mut remote_images: Vec<Image> = Vec::with_capacity(local_images.len());
let client = new_reqwest_client();
for registry in registries {
let images: Vec<&Image> = local_images
.par_iter()
.iter()
.filter(|image| &image.registry == registry)
.collect();
let credentials = config["authentication"][registry]
.clone()
.take_string()
.or(None);
let mut latest_images = match check_auth(registry, config) {
let mut latest_images = match check_auth(registry, config, &client).await {
Some(auth_url) => {
let token = get_token(images.clone(), &auth_url, &credentials);
get_latest_digests(images, Some(&token), config)
let token = get_token(images.clone(), &auth_url, &credentials, &client).await;
get_latest_digests(images, Some(&token), config, &client).await
}
None => get_latest_digests(images, None, config),
None => get_latest_digests(images, None, config, &client).await,
};
remote_images.append(&mut latest_images);
}
let result_mutex: Mutex<Vec<(String, Option<bool>)>> = Mutex::new(Vec::new());
remote_images.par_iter().for_each(|image| {
let mut result: Vec<(String, Option<bool>)> = Vec::new();
remote_images.iter().for_each(|image| {
let img = unsplit_image(&image.registry, &image.repository, &image.tag);
match &image.digest {
Some(d) => {
let r = d != image_map.get(&img).unwrap().as_ref().unwrap();
result_mutex.lock().unwrap().push((img, Some(r)))
result.push((img, Some(r)))
}
None => result_mutex.lock().unwrap().push((img, None)),
None => result.push((img, None)),
}
});
let result = result_mutex.lock().unwrap().clone();
result
}

Expand All @@ -90,13 +85,14 @@ pub async fn get_update(image: &str, socket: Option<String>, config: &JsonValue)
.clone()
.take_string()
.or(None);
let token = match check_auth(&local_image.registry, config) {
Some(auth_url) => get_token(vec![&local_image], &auth_url, &credentials),
let client = new_reqwest_client();
let token = match check_auth(&local_image.registry, config, &client).await {
Some(auth_url) => get_token(vec![&local_image], &auth_url, &credentials, &client).await,
None => String::new(),
};
let remote_image = match token.as_str() {
"" => get_latest_digest(&local_image, None, config),
_ => get_latest_digest(&local_image, Some(&token), config),
"" => get_latest_digest(&local_image, None, config, &client).await,
_ => get_latest_digest(&local_image, Some(&token), config, &client).await,
};
match &remote_image.digest {
Some(d) => Some(d != &local_image.digest.unwrap()),
Expand Down
28 changes: 9 additions & 19 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bollard::{secret::ImageSummary, ClientVersion, Docker};

#[cfg(feature = "cli")]
use bollard::secret::ImageInspect;
use futures::future::join_all;

use crate::{error, image::Image, utils::split_image};

Expand Down Expand Up @@ -32,27 +33,16 @@ pub async fn get_images_from_docker_daemon(socket: Option<String>) -> Vec<Image>
error!("Failed to retrieve list of images available!\n{}", e)
}
};
let mut result: Vec<Image> = Vec::new();
let mut handles = Vec::new();
for image in images {
if !image.repo_tags.is_empty() && !image.repo_digests.is_empty() {
for t in &image.repo_tags {
let (registry, repository, tag) = split_image(t);
result.push(Image {
registry,
repository,
tag,
digest: Some(
image.repo_digests[0]
.clone()
.split('@')
.collect::<Vec<&str>>()[1]
.to_string(),
),
});
}
handles.push(Image::from(image))
};
join_all(handles).await.iter().filter(|img| {
match img {
Some(_) => true,
None => false
}
}
result
}).map(|img| img.clone().unwrap()).collect()
}

#[cfg(feature = "cli")]
Expand Down
2 changes: 1 addition & 1 deletion src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::utils::{sort_update_vec, to_json};
pub fn print_updates(updates: &[(String, Option<bool>)], icons: &bool) {
let sorted_updates = sort_update_vec(updates);
let term_width: usize = termsize::get()
.unwrap_or(termsize::Size { rows: 24, cols: 80 })
.unwrap_or_else(|| termsize::Size { rows: 24, cols: 80 })
.cols as usize;
for update in sorted_updates {
let description = match update.1 {
Expand Down
28 changes: 28 additions & 0 deletions src/image.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,35 @@
use bollard::secret::ImageSummary;

use crate::utils::split_image;

#[derive(Clone, Debug)]
pub struct Image {
pub registry: String,
pub repository: String,
pub tag: String,
pub digest: Option<String>,
}

impl Image {
pub async fn from(image: ImageSummary) -> Option<Self> {
if !image.repo_tags.is_empty() && !image.repo_digests.is_empty() {
for t in &image.repo_tags {
let (registry, repository, tag) = split_image(t);
let image = Image {
registry,
repository,
tag,
digest: Some(
image.repo_digests[0]
.clone()
.split('@')
.collect::<Vec<&str>>()[1]
.to_string(),
),
};
return Some(image)
}
}
None
}
}
Loading

0 comments on commit 0c9ad61

Please sign in to comment.