Use log crate for logging instead of println
All checks were successful
Core Repos/ImageApi/pipeline/head This commit looks good
Core Repos/ImageApi/pipeline/pr-master This commit looks good

This commit is contained in:
Cameron Cordes
2021-02-24 21:26:11 -05:00
parent 8b5ba9d48c
commit f9983240df
7 changed files with 86 additions and 17 deletions

41
Cargo.lock generated
View File

@@ -390,6 +390,17 @@ dependencies = [
"syn", "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]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@@ -856,6 +867,19 @@ dependencies = [
"syn", "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]] [[package]]
name = "fake-simd" name = "fake-simd"
version = "0.1.2" version = "0.1.2"
@@ -1169,6 +1193,12 @@ version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.2.0" version = "0.2.0"
@@ -1213,10 +1243,12 @@ dependencies = [
"chrono", "chrono",
"diesel", "diesel",
"dotenv", "dotenv",
"env_logger",
"futures", "futures",
"hmac", "hmac",
"image", "image",
"jsonwebtoken", "jsonwebtoken",
"log",
"notify", "notify",
"path-absolutize", "path-absolutize",
"rayon", "rayon",
@@ -2200,6 +2232,15 @@ dependencies = [
"unicode-xid", "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]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.22" version = "1.0.22"

View File

@@ -29,3 +29,5 @@ rayon = "1.3"
notify = "4.0" notify = "4.0"
tokio = "0.2" tokio = "0.2"
path-absolutize = "3.0.6" path-absolutize = "3.0.6"
log="0.4"
env_logger="0.8"

View File

@@ -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 - `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) - `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 - `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]

View File

@@ -2,6 +2,7 @@ use actix_web::web::{HttpResponse, Json};
use actix_web::{post, Responder}; use actix_web::{post, Responder};
use chrono::{Duration, Utc}; use chrono::{Duration, Utc};
use jsonwebtoken::{encode, EncodingKey, Header}; use jsonwebtoken::{encode, EncodingKey, Header};
use log::debug;
use crate::data::LoginRequest; use crate::data::LoginRequest;
use crate::data::{secret_key, Claims, CreateAccountRequest, Token}; use crate::data::{secret_key, Claims, CreateAccountRequest, Token};
@@ -24,7 +25,7 @@ async fn register(user: Json<CreateAccountRequest>) -> impl Responder {
#[post("/login")] #[post("/login")]
async fn login(creds: Json<LoginRequest>) -> impl Responder { async fn login(creds: Json<LoginRequest>) -> impl Responder {
println!("Logging in: {}", creds.username); debug!("Logging in: {}", creds.username);
if let Some(user) = get_user(&creds.username, &creds.password) { if let Some(user) = get_user(&creds.username, &creds.password) {
let claims = Claims { let claims = Claims {
sub: user.id.to_string(), sub: user.id.to_string(),

View File

@@ -1,5 +1,7 @@
use std::str::FromStr; use std::str::FromStr;
use log::error;
use actix_web::error::ErrorUnauthorized; use actix_web::error::ErrorUnauthorized;
use actix_web::{dev, http::header, Error, FromRequest, HttpRequest}; use actix_web::{dev, http::header, Error, FromRequest, HttpRequest};
use futures::future::{err, ok, Ready}; use futures::future::{err, ok, Ready};
@@ -21,7 +23,6 @@ pub fn secret_key() -> String {
if cfg!(test) { if cfg!(test) {
String::from("test_key") String::from("test_key")
} else { } else {
println!("USING REAL KEY");
dotenv::var("SECRET_KEY").expect("SECRET_KEY env not set!") dotenv::var("SECRET_KEY").expect("SECRET_KEY env not set!")
} }
} }
@@ -39,7 +40,7 @@ impl FromStr for Claims {
) { ) {
Ok(data) => Ok(data.claims), Ok(data) => Ok(data.claims),
Err(other) => { Err(other) => {
println!("DecodeError: {}", other); error!("DecodeError: {}", other);
Err(other) Err(other)
} }
} }

View File

@@ -20,6 +20,7 @@ use rayon::prelude::*;
use serde::Serialize; use serde::Serialize;
use data::{AddFavoriteRequest, ThumbnailRequest}; use data::{AddFavoriteRequest, ThumbnailRequest};
use log::{debug, error, info};
use crate::data::Claims; use crate::data::Claims;
use crate::database::{add_favorite, get_favorites}; use crate::database::{add_favorite, get_favorites};
@@ -34,7 +35,7 @@ mod video;
#[post("/photos")] #[post("/photos")]
async fn list_photos(_claims: Claims, req: Json<ThumbnailRequest>) -> impl Responder { async fn list_photos(_claims: Claims, req: Json<ThumbnailRequest>) -> impl Responder {
println!("{}", req.path); info!("{}", req.path);
let path = &req.path; let path = &req.path;
if let Some(path) = is_valid_path(path) { if let Some(path) = is_valid_path(path) {
@@ -54,6 +55,7 @@ async fn list_photos(_claims: Claims, req: Json<ThumbnailRequest>) -> impl Respo
HttpResponse::Ok().json(PhotosResponse { photos, dirs }) HttpResponse::Ok().json(PhotosResponse { photos, dirs })
} else { } else {
error!("Bad photos request: {}", req.path);
HttpResponse::BadRequest().finish() HttpResponse::BadRequest().finish()
} }
} }
@@ -78,7 +80,7 @@ async fn get_image(
.expect("Error stripping prefix"); .expect("Error stripping prefix");
let thumb_path = Path::new(&thumbs).join(relative_path); let thumb_path = Path::new(&thumbs).join(relative_path);
println!("{:?}", thumb_path); debug!("{:?}", thumb_path);
if let Ok(file) = NamedFile::open(&thumb_path) { if let Ok(file) = NamedFile::open(&thumb_path) {
file.into_response(&request).unwrap() file.into_response(&request).unwrap()
} else { } else {
@@ -90,6 +92,7 @@ async fn get_image(
HttpResponse::NotFound().finish() HttpResponse::NotFound().finish()
} }
} else { } else {
error!("Bad photos request: {}", req.path);
HttpResponse::BadRequest().finish() 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 { while let Some(Ok(mut part)) = payload.next().await {
if let Some(content_type) = part.content_disposition() { if let Some(content_type) = part.content_disposition() {
println!("{:?}", content_type); debug!("{:?}", content_type);
if let Some(filename) = content_type.get_filename() { if let Some(filename) = content_type.get_filename() {
println!("Name: {:?}", filename); debug!("Name: {:?}", filename);
file_name = Some(filename.to_string()); file_name = Some(filename.to_string());
while let Some(Ok(data)) = part.next().await { 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(); let mut file = File::create(full_path).unwrap();
file.write_all(&file_content).unwrap(); file.write_all(&file_content).unwrap();
} else { } else {
error!("File already exists: {:?}", full_path);
return HttpResponse::BadRequest().body("File already exists"); return HttpResponse::BadRequest().body("File already exists");
} }
} else { } else {
error!("Invalid path for upload: {:?}", full_path);
return HttpResponse::BadRequest().body("Path was not valid"); return HttpResponse::BadRequest().body("Path was not valid");
} }
} else { } else {
@@ -161,6 +166,7 @@ async fn generate_video(
HttpResponse::Ok().json(playlist) HttpResponse::Ok().json(playlist)
} else { } else {
error!("Unable to get file name: {:?}", filename);
HttpResponse::BadRequest().finish() HttpResponse::BadRequest().finish()
} }
} }
@@ -172,7 +178,7 @@ async fn stream_video(
path: web::Query<ThumbnailRequest>, path: web::Query<ThumbnailRequest>,
) -> impl Responder { ) -> impl Responder {
let playlist = &path.path; let playlist = &path.path;
println!("Playlist: {}", playlist); debug!("Playlist: {}", playlist);
// Extract video playlist dir to dotenv // Extract video playlist dir to dotenv
if !playlist.starts_with("tmp") && is_valid_path(playlist) != None { if !playlist.starts_with("tmp") && is_valid_path(playlist) != None {
@@ -191,11 +197,12 @@ async fn get_video_part(
path: web::Path<ThumbnailRequest>, path: web::Path<ThumbnailRequest>,
) -> impl Responder { ) -> impl Responder {
let part = &path.path; let part = &path.path;
println!("Video part: {}", part); debug!("Video part: {}", part);
if let Ok(file) = NamedFile::open(String::from("tmp/") + part) { if let Ok(file) = NamedFile::open(String::from("tmp/") + part) {
file.into_response(&request).unwrap() file.into_response(&request).unwrap()
} else { } else {
error!("Video part not found: tmp/{}", part);
HttpResponse::NotFound().finish() HttpResponse::NotFound().finish()
} }
} }
@@ -206,6 +213,7 @@ async fn favorites(claims: Claims) -> impl Responder {
.into_iter() .into_iter()
.map(|favorite| favorite.path) .map(|favorite| favorite.path)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
HttpResponse::Ok().json(PhotosResponse { HttpResponse::Ok().json(PhotosResponse {
photos: &favorites, photos: &favorites,
dirs: &Vec::new(), dirs: &Vec::new(),
@@ -216,8 +224,10 @@ async fn favorites(claims: Claims) -> impl Responder {
async fn post_add_favorite(claims: Claims, body: web::Json<AddFavoriteRequest>) -> impl Responder { async fn post_add_favorite(claims: Claims, body: web::Json<AddFavoriteRequest>) -> impl Responder {
if let Ok(user_id) = claims.sub.parse::<i32>() { if let Ok(user_id) = claims.sub.parse::<i32>() {
add_favorite(user_id, body.path.clone()); add_favorite(user_id, body.path.clone());
debug!("Adding favorite \"{}\" for userid: {}", user_id, body.path);
HttpResponse::Ok() HttpResponse::Ok()
} else { } else {
error!("Unable to parse sub as i32: {}", claims.sub);
HttpResponse::BadRequest() HttpResponse::BadRequest()
} }
} }
@@ -233,8 +243,9 @@ fn create_thumbnails() {
.collect::<Vec<Result<_, _>>>() .collect::<Vec<Result<_, _>>>()
.into_par_iter() .into_par_iter()
.filter_map(|entry| entry.ok()) .filter_map(|entry| entry.ok())
.filter(|entry| entry.file_type().is_file())
.filter(|entry| { .filter(|entry| {
println!("{:?}", entry.path()); debug!("{:?}", entry.path());
if let Some(ext) = entry if let Some(ext) = entry
.path() .path()
.extension() .extension()
@@ -245,23 +256,31 @@ fn create_thumbnails() {
let thumb_path = Path::new(thumbnail_directory).join(relative_path); let thumb_path = Path::new(thumbnail_directory).join(relative_path);
std::fs::create_dir_all(&thumb_path.parent().unwrap()) std::fs::create_dir_all(&thumb_path.parent().unwrap())
.expect("Error creating directory"); .expect("Error creating directory");
debug!("Generating video thumbnail: {:?}", thumb_path);
generate_video_thumbnail(entry.path(), &thumb_path); generate_video_thumbnail(entry.path(), &thumb_path);
false false
} else { } else {
ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "nef" ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "nef"
} }
} else { } else {
error!("Unable to get extension for file: {:?}", entry.path());
false false
} }
}) })
.filter(|entry| { .filter(|entry| {
let path = entry.path(); let path = entry.path();
let relative_path = &path.strip_prefix(&images).unwrap(); 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() !thumb_path.exists()
}) })
.map(|entry| (image::open(entry.path()), entry.path().to_path_buf())) .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(|(img, path)| (img.unwrap(), path))
.map(|(image, path)| (image.thumbnail(200, u32::MAX), path)) .map(|(image, path)| (image.thumbnail(200, u32::MAX), path))
.map(|(image, path)| { .map(|(image, path)| {
@@ -269,15 +288,18 @@ fn create_thumbnails() {
let thumb_path = Path::new(thumbnail_directory).join(relative_path); let thumb_path = Path::new(thumbnail_directory).join(relative_path);
std::fs::create_dir_all(&thumb_path.parent().unwrap()) std::fs::create_dir_all(&thumb_path.parent().unwrap())
.expect("There was an issue creating directory"); .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"); image.save(thumb_path).expect("Failure saving thumbnail");
}) })
.for_each(drop); .for_each(drop);
println!("Finished"); debug!("Finished");
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
env_logger::init();
create_thumbnails(); create_thumbnails();
std::thread::spawn(|| { std::thread::spawn(|| {

View File

@@ -3,6 +3,7 @@ use std::path::Path;
use std::process::{Child, Command, ExitStatus, Stdio}; use std::process::{Child, Command, ExitStatus, Stdio};
use actix::prelude::*; 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 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 // 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<ProcessMessage> for StreamActor {
type Result = Result<ExitStatus>; type Result = Result<ExitStatus>;
fn handle(&mut self, msg: ProcessMessage, _ctx: &mut Self::Context) -> Self::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 mut process = msg.1;
let result = process.wait(); let result = process.wait();
println!( debug!(
"Finished waiting for: {:?}. Code: {:?}", "Finished waiting for: {:?}. Code: {:?}",
msg.0, msg.0,
result result
@@ -40,7 +41,7 @@ impl Handler<ProcessMessage> for StreamActor {
pub fn create_playlist(video_path: &str, playlist_file: &str) -> Result<Child> { pub fn create_playlist(video_path: &str, playlist_file: &str) -> Result<Child> {
if Path::new(playlist_file).exists() { 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)); return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists));
} }