diff --git a/Cargo.lock b/Cargo.lock index 97ac18c..7354095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,6 +390,17 @@ dependencies = [ "syn", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -856,6 +867,19 @@ dependencies = [ "syn", ] +[[package]] +name = "env_logger" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -1169,6 +1193,12 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "idna" version = "0.2.0" @@ -1213,10 +1243,12 @@ dependencies = [ "chrono", "diesel", "dotenv", + "env_logger", "futures", "hmac", "image", "jsonwebtoken", + "log", "notify", "path-absolutize", "rayon", @@ -2200,6 +2232,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.22" diff --git a/Cargo.toml b/Cargo.toml index a1565e5..a52af6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,5 @@ rayon = "1.3" notify = "4.0" tokio = "0.2" path-absolutize = "3.0.6" +log="0.4" +env_logger="0.8" diff --git a/README.md b/README.md index f15cdcf..429e3d6 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,5 @@ They should be defined where the binary is located or above it in an `.env` file - `THUMBNAILS` is a path where generated thumbnails should be stored - `BIND_URL` is the url and port to bind to (typically your own IP address) - `SECRET_KEY` is the *hopefully* random string to sign Tokens with +- `RUST_LOG` is one of `off, error, warn, info, debug, trace`, from least to most noisy [error is default] diff --git a/src/auth.rs b/src/auth.rs index 9cd1609..818da18 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,6 +2,7 @@ use actix_web::web::{HttpResponse, Json}; use actix_web::{post, Responder}; use chrono::{Duration, Utc}; use jsonwebtoken::{encode, EncodingKey, Header}; +use log::debug; use crate::data::LoginRequest; use crate::data::{secret_key, Claims, CreateAccountRequest, Token}; @@ -24,7 +25,7 @@ async fn register(user: Json) -> impl Responder { #[post("/login")] async fn login(creds: Json) -> impl Responder { - println!("Logging in: {}", creds.username); + debug!("Logging in: {}", creds.username); if let Some(user) = get_user(&creds.username, &creds.password) { let claims = Claims { sub: user.id.to_string(), diff --git a/src/data/mod.rs b/src/data/mod.rs index d21cd6d..1aed598 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,5 +1,7 @@ use std::str::FromStr; +use log::error; + use actix_web::error::ErrorUnauthorized; use actix_web::{dev, http::header, Error, FromRequest, HttpRequest}; use futures::future::{err, ok, Ready}; @@ -21,7 +23,6 @@ pub fn secret_key() -> String { if cfg!(test) { String::from("test_key") } else { - println!("USING REAL KEY"); dotenv::var("SECRET_KEY").expect("SECRET_KEY env not set!") } } @@ -39,7 +40,7 @@ impl FromStr for Claims { ) { Ok(data) => Ok(data.claims), Err(other) => { - println!("DecodeError: {}", other); + error!("DecodeError: {}", other); Err(other) } } diff --git a/src/main.rs b/src/main.rs index de79c5c..b3035c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ use rayon::prelude::*; use serde::Serialize; use data::{AddFavoriteRequest, ThumbnailRequest}; +use log::{debug, error, info}; use crate::data::Claims; use crate::database::{add_favorite, get_favorites}; @@ -34,7 +35,7 @@ mod video; #[post("/photos")] async fn list_photos(_claims: Claims, req: Json) -> impl Responder { - println!("{}", req.path); + info!("{}", req.path); let path = &req.path; if let Some(path) = is_valid_path(path) { @@ -54,6 +55,7 @@ async fn list_photos(_claims: Claims, req: Json) -> impl Respo HttpResponse::Ok().json(PhotosResponse { photos, dirs }) } else { + error!("Bad photos request: {}", req.path); HttpResponse::BadRequest().finish() } } @@ -78,7 +80,7 @@ async fn get_image( .expect("Error stripping prefix"); let thumb_path = Path::new(&thumbs).join(relative_path); - println!("{:?}", thumb_path); + debug!("{:?}", thumb_path); if let Ok(file) = NamedFile::open(&thumb_path) { file.into_response(&request).unwrap() } else { @@ -90,6 +92,7 @@ async fn get_image( HttpResponse::NotFound().finish() } } else { + error!("Bad photos request: {}", req.path); HttpResponse::BadRequest().finish() } } @@ -102,9 +105,9 @@ async fn upload_image(_: Claims, mut payload: mp::Multipart) -> impl Responder { while let Some(Ok(mut part)) = payload.next().await { if let Some(content_type) = part.content_disposition() { - println!("{:?}", content_type); + debug!("{:?}", content_type); if let Some(filename) = content_type.get_filename() { - println!("Name: {:?}", filename); + debug!("Name: {:?}", filename); file_name = Some(filename.to_string()); while let Some(Ok(data)) = part.next().await { @@ -128,9 +131,11 @@ async fn upload_image(_: Claims, mut payload: mp::Multipart) -> impl Responder { let mut file = File::create(full_path).unwrap(); file.write_all(&file_content).unwrap(); } else { + error!("File already exists: {:?}", full_path); return HttpResponse::BadRequest().body("File already exists"); } } else { + error!("Invalid path for upload: {:?}", full_path); return HttpResponse::BadRequest().body("Path was not valid"); } } else { @@ -161,6 +166,7 @@ async fn generate_video( HttpResponse::Ok().json(playlist) } else { + error!("Unable to get file name: {:?}", filename); HttpResponse::BadRequest().finish() } } @@ -172,7 +178,7 @@ async fn stream_video( path: web::Query, ) -> impl Responder { let playlist = &path.path; - println!("Playlist: {}", playlist); + debug!("Playlist: {}", playlist); // Extract video playlist dir to dotenv if !playlist.starts_with("tmp") && is_valid_path(playlist) != None { @@ -191,11 +197,12 @@ async fn get_video_part( path: web::Path, ) -> impl Responder { let part = &path.path; - println!("Video part: {}", part); + debug!("Video part: {}", part); if let Ok(file) = NamedFile::open(String::from("tmp/") + part) { file.into_response(&request).unwrap() } else { + error!("Video part not found: tmp/{}", part); HttpResponse::NotFound().finish() } } @@ -206,6 +213,7 @@ async fn favorites(claims: Claims) -> impl Responder { .into_iter() .map(|favorite| favorite.path) .collect::>(); + HttpResponse::Ok().json(PhotosResponse { photos: &favorites, dirs: &Vec::new(), @@ -216,8 +224,10 @@ async fn favorites(claims: Claims) -> impl Responder { async fn post_add_favorite(claims: Claims, body: web::Json) -> impl Responder { if let Ok(user_id) = claims.sub.parse::() { add_favorite(user_id, body.path.clone()); + debug!("Adding favorite \"{}\" for userid: {}", user_id, body.path); HttpResponse::Ok() } else { + error!("Unable to parse sub as i32: {}", claims.sub); HttpResponse::BadRequest() } } @@ -233,8 +243,9 @@ fn create_thumbnails() { .collect::>>() .into_par_iter() .filter_map(|entry| entry.ok()) + .filter(|entry| entry.file_type().is_file()) .filter(|entry| { - println!("{:?}", entry.path()); + debug!("{:?}", entry.path()); if let Some(ext) = entry .path() .extension() @@ -245,23 +256,31 @@ fn create_thumbnails() { let thumb_path = Path::new(thumbnail_directory).join(relative_path); std::fs::create_dir_all(&thumb_path.parent().unwrap()) .expect("Error creating directory"); + + debug!("Generating video thumbnail: {:?}", thumb_path); generate_video_thumbnail(entry.path(), &thumb_path); false } else { ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "nef" } } else { + error!("Unable to get extension for file: {:?}", entry.path()); false } }) .filter(|entry| { let path = entry.path(); let relative_path = &path.strip_prefix(&images).unwrap(); - let thumb_path = Path::new(thumbnail_directory).join(dbg!(relative_path)); + let thumb_path = Path::new(thumbnail_directory).join(relative_path); !thumb_path.exists() }) .map(|entry| (image::open(entry.path()), entry.path().to_path_buf())) - .filter(|(img, _)| img.is_ok()) + .filter(|(img, _)| { + if let Err(e) = img { + error!("Unable to open image: {}", e); + } + img.is_ok() + }) .map(|(img, path)| (img.unwrap(), path)) .map(|(image, path)| (image.thumbnail(200, u32::MAX), path)) .map(|(image, path)| { @@ -269,15 +288,18 @@ fn create_thumbnails() { let thumb_path = Path::new(thumbnail_directory).join(relative_path); std::fs::create_dir_all(&thumb_path.parent().unwrap()) .expect("There was an issue creating directory"); - println!("Saving thumbnail: {:?}", thumb_path); + debug!("Saving thumbnail: {:?}", thumb_path); image.save(thumb_path).expect("Failure saving thumbnail"); }) .for_each(drop); - println!("Finished"); + debug!("Finished"); } fn main() -> std::io::Result<()> { + dotenv::dotenv().ok(); + env_logger::init(); + create_thumbnails(); std::thread::spawn(|| { diff --git a/src/video.rs b/src/video.rs index 5797103..4395e66 100644 --- a/src/video.rs +++ b/src/video.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::process::{Child, Command, ExitStatus, Stdio}; use actix::prelude::*; +use log::{debug, trace}; // ffmpeg -i test.mp4 -c:v h264 -flags +cgop -g 30 -hls_time 3 out.m3u8 // ffmpeg -i "filename.mp4" -preset veryfast -c:v libx264 -f hls -hls_list_size 100 -hls_time 2 -crf 24 -vf scale=1080:-2,setsar=1:1 attempt/vid_out.m3u8 @@ -23,11 +24,11 @@ impl Handler for StreamActor { type Result = Result; fn handle(&mut self, msg: ProcessMessage, _ctx: &mut Self::Context) -> Self::Result { - println!("Message received"); + trace!("Message received"); let mut process = msg.1; let result = process.wait(); - println!( + debug!( "Finished waiting for: {:?}. Code: {:?}", msg.0, result @@ -40,7 +41,7 @@ impl Handler for StreamActor { pub fn create_playlist(video_path: &str, playlist_file: &str) -> Result { if Path::new(playlist_file).exists() { - println!("Playlist already exists: {}", playlist_file); + debug!("Playlist already exists: {}", playlist_file); return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists)); }