Skip to content

Commit

Permalink
Client downloads are now async
Browse files Browse the repository at this point in the history
  • Loading branch information
Urpagin committed Aug 31, 2024
1 parent d4283b1 commit 8328c43
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 11 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
members = ["client", "server"]
resolver = "2"

[profile.release]
opt-level = 'z' # Optimize for size
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations
panic = 'abort' # Abort on panic
strip = true # Strip symbols from binary
2 changes: 2 additions & 0 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ edition = "2021"
clap = { version = "4.5.16", features = ["derive"] }
clap_derive = "4.5.13"
env_logger = "0.11.5"
futures = "0.3.30"
log = "0.4.22"
openssl = { version = "0.10.66", features = ["vendored"] }
reqwest = { version = "0.12.7", features = ["blocking", "json"] }
serde_json = "1.0.127"
tokio = { version = "1.39.3", features = ["full"] }
59 changes: 48 additions & 11 deletions client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ struct Args {
#[arg(short, long)]
directory: String,

/// If you used the default NGINX proxy config specify user and password.
/// (optional) If you used the default NGINX proxy config specify user and password.
#[arg(short, long)]
user: Option<String>,

/// If you used the default NGINX proxy config specify user and password.
/// (optional) If you used the default NGINX proxy config specify user and password.
#[arg(short, long)]
password: Option<String>,
}
Expand All @@ -40,12 +40,12 @@ async fn main() {

let image_endpoint: String = format!("{endpoint}/images");

match fetch_image_links(&image_endpoint, auth).await {
match fetch_image_links(&image_endpoint, &auth).await {
Ok(images) => {
for img in &images {
info!("{:?}", img);
}
if let Err(e) = sync_local(image_directory, images).await {
if let Err(e) = sync_local(image_directory, images, &auth).await {
error!("Failed to sync local with remote: {e}");
}
}
Expand Down Expand Up @@ -104,6 +104,7 @@ fn init_logging() {

/// If the server side is password-protected by the provided NGINX proxy config file,
/// any request to the server asks for a user and a password.
#[derive(Clone)]
struct Authentication {
user: String,
password: String,
Expand All @@ -112,7 +113,7 @@ struct Authentication {
/// Returns a vec of `Image`s that it fetches from the image endpoint.
async fn fetch_image_links(
image_endpoint: &str,
auth: Option<Authentication>,
auth: &Option<Authentication>,
) -> Result<Vec<Image>, Box<dyn std::error::Error>> {
debug!("Fetching images with endpoint: '{image_endpoint}'");

Expand All @@ -121,7 +122,7 @@ async fn fetch_image_links(
if let Some(auth) = auth {
response = Client::new()
.get(image_endpoint)
.basic_auth(auth.user, Some(auth.password))
.basic_auth(auth.user.clone(), Some(auth.password.clone()))
.send()
.await?;
} else {
Expand Down Expand Up @@ -157,7 +158,11 @@ struct Image {
}

/// Synchronizes the remote images with the local directory.
async fn sync_local<P>(directory: P, images: Vec<Image>) -> Result<(), Box<dyn std::error::Error>>
async fn sync_local<P>(
directory: P,
images: Vec<Image>,
auth: &Option<Authentication>,
) -> Result<(), Box<dyn std::error::Error>>
where
P: AsRef<Path> + std::fmt::Debug,
{
Expand All @@ -176,15 +181,31 @@ where
.collect();

// Add images
let mut tasks: Vec<_> = Vec::new();

let mut images_filenames: HashSet<String> = HashSet::new();
for img in images {
images_filenames.insert(img.filename.clone());
if !local_filenames.contains(&img.filename) {
let path = Path::new(directory.as_ref()).join(img.filename);
download_file(path, &img.download_link).await?;
let path = Path::new(directory.as_ref()).join(&img.filename);
let auth_clone = auth.clone();
tasks.push(tokio::spawn(async move {
match download_file(&path, &img.download_link, &auth_clone).await {
Ok(_) => {
info!("Successfully downloaded: {:?}", path);
}
Err(e) => {
error!("Failed to download: {:?} at {}: {}", path, &img.filename, e);
}
}
}))
//download_file(path, &img.download_link, auth).await?;
}
}

// Download images asynchronously (nice)
futures::future::join_all(tasks).await;

// Remove images
for local_filename in local_filenames {
if !images_filenames.contains(&local_filename) {
Expand All @@ -206,11 +227,27 @@ fn ensure_directory_exists<P: AsRef<Path>>(directory: P) -> std::io::Result<()>
}

/// Downloads a file from a URL and saves it at `path` which also contains the file name
async fn download_file<P>(path: P, url: &str) -> Result<(), Box<dyn std::error::Error>>
async fn download_file<P>(
path: P,
url: &str,
auth: &Option<Authentication>,
) -> Result<(), Box<dyn std::error::Error>>
where
P: AsRef<Path> + std::fmt::Debug,
{
let response = reqwest::get(url).await?;
let client = Client::new();
let mut request = client.get(url);

if let Some(auth) = auth {
request = request.basic_auth(&auth.user, Some(&auth.password));
}

let response = request.send().await?;

if !response.status().is_success() {
return Err(format!("Failed to download file: HTTP {}", response.status()).into());
}

let mut file = std::fs::File::create(&path)?;
let mut content = Cursor::new(response.bytes().await?);
std::io::copy(&mut content, &mut file)?;
Expand Down
28 changes: 28 additions & 0 deletions scripts/update_wallpaper_feh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash

# 1. Install dependencies: feh
# 2. Download or compile client side program and put the binary next to this script. (chmod +x it too)
# 3. Populate the variables
# 4. Run script (you may run it at your computer's startup)

# BINARY NAME (the client-side binary's name)
BINARY_FILE_NAME=client_x86_64_linux

# SERVER URL
ENDPOINT=https://domain.ext

# DIRECTORY (where the images will be saved)
WALLPAPERS_PATH=./wallpapers

# NGINX
USER=user
PASSWORD=password



# Fetch wallpapers
./"$BINARY_FILE_NAME" --endpoint "$ENDPOINT" --directory "$WALLPAPERS_PATH" --user "$USER" --password "$PASSWORD"

# Set a random wallpaper
feh --bg-fill --randomize "$WALLPAPERS_PATH"/*

0 comments on commit 8328c43

Please sign in to comment.