3
\$\begingroup\$

This is my first rocket web-app. It serves images from a directory and thumbnails from a sub-directory. if no thumbnail is found for an existing image it is created on the fly.

Before I launch this thing into production/space, it would be calming to have some experts' eyes on it and be made aware of any glaring holes as well as things that would work, but can be optimized.

Question

In particular I am not sure what happens, if the app is run in multiple workers and multiple requests to thumbnail the same image are handled simultaneously.

Would I have to place locks on files and how would i do that?

Code

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;
extern crate image;

use std::fs::File;
use std::path::PathBuf;
use rocket::{Request, response::content, response::NamedFile};
use self::image::{FilterType, JPEG};


const IMAGE_DIR: &str = "images/";


pub fn resize_and_crop_to(filename: &PathBuf, cached: &PathBuf, width: u32, height: u32) -> Option<()> {
    let i = image::open(filename);
    match i {
        Ok(img) => {
            let scaled = img.resize_to_fill(width, height, FilterType::CatmullRom);
            let mut output = File::create(cached).expect("Could not open cache file");
            scaled.write_to(&mut output, JPEG).ok()
        },
        Err(_error) => None
    }
}

pub fn get_filename(name: &str) -> PathBuf {
    let filename: PathBuf = [ IMAGE_DIR, name ].iter().collect();
    filename
}

pub fn get_cache_filename(name: &str, format: &str) -> PathBuf {
    let filename = [ IMAGE_DIR, format, name ].iter().collect();
    filename
}

#[get("/<image>")]
fn original(image: String) -> Option<NamedFile> {
    let filename = get_filename(image.as_str());
    NamedFile::open(filename.as_os_str()).ok()
}

#[get("/thumb/<image>")]
fn scaled(image: String) -> Option<NamedFile> {
    let format = "thumb";
    let cached = get_cache_filename(image.as_str(), format);
    let f = NamedFile::open(&cached);
    match f {
        Ok(file) => Some(file),
        Err(_error) => {
            let filename = get_filename(image.as_str());
            resize_and_crop_to(&filename, &cached, 280, 180)?;
            NamedFile::open(cached).ok()
       }
    }
}

#[catch(404)]
fn not_found(request: &Request) -> content::Html<String> {
    let html = format!(
        "<p>{} not found</p>",
         request.uri()
    );
    content::Html(html)
}

fn main() {
    rocket::ignite()
        .mount("/", routes![original, scaled])
        .register(catchers![not_found])
        .launch();
}

(I could not add tags #rocket, nor #rust-rocket for lack of reputation points)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.