|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
use once_cell::sync::OnceCell;
|
|
|
|
|
use ramhorns::{Content, Ramhorns};
|
|
|
|
|
use salvo::fs::NamedFile;
|
|
|
|
|
use salvo::hyper::header::{HOST, CONTENT_TYPE};
|
|
|
|
|
use salvo::hyper::header::{HOST};
|
|
|
|
|
use salvo::prelude::*;
|
|
|
|
|
use salvo::serve_static::{StaticDir, StaticFile};
|
|
|
|
|
use sqlx::SqlitePool;
|
|
|
|
@ -98,7 +98,7 @@ async fn serve_file(req: &mut Request, res: &mut Response) {
|
|
|
|
|
|
|
|
|
|
// Get the mimetype of the file.
|
|
|
|
|
let mimetype = db::get_mimetype(sqlconn, filename.clone()).await.unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for mime in mime_unsafe {
|
|
|
|
|
// compare each value with the mimetype.
|
|
|
|
|
if mime.clone().into_string().unwrap() == mimetype.clone() {
|
|
|
|
@ -159,14 +159,13 @@ async fn serve_file(req: &mut Request, res: &mut Response) {
|
|
|
|
|
.expect("Couldn't find 'nginx_sendfile' in config. :(");
|
|
|
|
|
|
|
|
|
|
if nginxsendfile {
|
|
|
|
|
// Add the content-type header.
|
|
|
|
|
res.add_header("Content-Type", mimetype, true).unwrap();
|
|
|
|
|
|
|
|
|
|
// Add the header, and we're done.
|
|
|
|
|
// X-Accel-Redirect lets nginx serve the file directly, instead of us doing all that hard work.
|
|
|
|
|
let xsend = "/files/".to_string() + &filename.to_string();
|
|
|
|
|
res.add_header("X-Accel-Redirect", xsend, true).unwrap();
|
|
|
|
|
|
|
|
|
|
// We don't really need to update the content-type header, since nginx handles that (TODO: Test this lol)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// If nginx sendfile is disabled, we need to render the file directly
|
|
|
|
|
let filepath = "files/".to_string() + &filename.to_string();
|
|
|
|
@ -256,7 +255,12 @@ async fn upload(req: &mut Request, res: &mut Response) {
|
|
|
|
|
|
|
|
|
|
// Grab the mimetype from the request (fallback to text/plain)
|
|
|
|
|
let filepart = file.clone();
|
|
|
|
|
let mimetype = filepart.headers().get("content-type").unwrap().to_str().unwrap_or("text/plain");
|
|
|
|
|
let mimetype = filepart
|
|
|
|
|
.headers()
|
|
|
|
|
.get("content-type")
|
|
|
|
|
.unwrap()
|
|
|
|
|
.to_str()
|
|
|
|
|
.unwrap_or("text/plain");
|
|
|
|
|
tracing::debug!("upload(mimetype): {:?}", mimetype);
|
|
|
|
|
|
|
|
|
|
// Check if the filetype is on the 'banned' list
|
|
|
|
@ -337,7 +341,7 @@ async fn upload(req: &mut Request, res: &mut Response) {
|
|
|
|
|
sqlconn,
|
|
|
|
|
filename.clone(),
|
|
|
|
|
mimetype.to_string(),
|
|
|
|
|
expiry.clone(),
|
|
|
|
|
expiry,
|
|
|
|
|
// expiry_override,
|
|
|
|
|
adminkey.clone(),
|
|
|
|
|
accessed.as_secs() as i32,
|
|
|
|
@ -385,7 +389,7 @@ async fn upload(req: &mut Request, res: &mut Response) {
|
|
|
|
|
#[handler]
|
|
|
|
|
async fn serve_static(req: &mut Request, res: &mut Response) {
|
|
|
|
|
let headers = req.headers();
|
|
|
|
|
let host = headers[HOST].to_str().unwrap_or_else(|_| "None");
|
|
|
|
|
let host = headers[HOST].to_str().unwrap_or("None");
|
|
|
|
|
match req.uri().path() {
|
|
|
|
|
"/services" => {
|
|
|
|
|
tracing::info!("New Request: /services");
|
|
|
|
@ -469,7 +473,7 @@ async fn serve_static(req: &mut Request, res: &mut Response) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[handler]
|
|
|
|
|
async fn serve_metrics(req: &mut Request, res: &mut Response) {
|
|
|
|
|
async fn serve_metrics(res: &mut Response) {
|
|
|
|
|
// Lets start timing this:
|
|
|
|
|
let start = Instant::now();
|
|
|
|
|
|
|
|
|
@ -478,6 +482,10 @@ async fn serve_metrics(req: &mut Request, res: &mut Response) {
|
|
|
|
|
// Setup the massive string of metrics
|
|
|
|
|
let mut rendered = String::new();
|
|
|
|
|
|
|
|
|
|
////
|
|
|
|
|
// General Stats
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
// Counting how many files each IP has uploaded.
|
|
|
|
|
let mut ipcount = db::get_total_uploads_ip(sqlconn).await;
|
|
|
|
|
// Loop through each IP and render it as a new line with a label for each IP
|
|
|
|
@ -490,6 +498,7 @@ async fn serve_metrics(req: &mut Request, res: &mut Response) {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Total number of files alive/dead
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}filesize_alive {}\n",
|
|
|
|
|
rendered,
|
|
|
|
@ -501,57 +510,102 @@ async fn serve_metrics(req: &mut Request, res: &mut Response) {
|
|
|
|
|
db::total_dead_filesize(sqlconn).await.unwrap()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// // Counting how many alive files have been uploaded per filetype
|
|
|
|
|
// let mut afilecount = db::total_alive_filetype(sqlconn).await;
|
|
|
|
|
// // Loop through each filetype and render it as a new line with a label for each type
|
|
|
|
|
// for afc in afilecount.as_mut().unwrap() {
|
|
|
|
|
// rendered = format!(
|
|
|
|
|
// "{}total_alive{{filetype={}}} {}\n",
|
|
|
|
|
// rendered,
|
|
|
|
|
// &afc.0.to_string(),
|
|
|
|
|
// &afc.1.to_string()
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Counting how many dead files have been uploaded per filetype
|
|
|
|
|
let mut dfilecount = db::total_dead_filetype(sqlconn).await;
|
|
|
|
|
// Loop through each filetype and render it as a new line with a label for each type
|
|
|
|
|
for dfc in dfilecount.as_mut().unwrap() {
|
|
|
|
|
////
|
|
|
|
|
// Filetype Stats
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
let mimetype_metrics = db::get_mimetype_metrics(sqlconn).await;
|
|
|
|
|
// Add a newline here so we can keep it pretty.
|
|
|
|
|
rendered = format!("{}\n", rendered);
|
|
|
|
|
|
|
|
|
|
for row in mimetype_metrics.unwrap() {
|
|
|
|
|
// Alive filescount
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}total_dead{{filetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered,
|
|
|
|
|
&dfc.0.to_string(),
|
|
|
|
|
&dfc.1.to_string()
|
|
|
|
|
"{}total_alive{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.alive_files,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Dead filescount
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}total_dead{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.dead_files,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Alive Filesize
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}filesize_alive{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.filesize_alive,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Dead Filesize
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}filesize_dead{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.filesize_dead,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Alive Filesize
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}views_alive{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.views_alive,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Dead Filesize
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}views_dead{{host=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, row.host, row.mimetype, row.views_dead,
|
|
|
|
|
);
|
|
|
|
|
// Add an extea newline to split between mimetypes and hosts
|
|
|
|
|
rendered = format!("{}\n", rendered);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////
|
|
|
|
|
// Individual Stats
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
// This is a pain, we're grabbing the individual file stats and parsing them for each file.
|
|
|
|
|
let filevec = db::get_filemetrics(sqlconn).await;
|
|
|
|
|
let filevec = db::get_file_metrics(sqlconn).await;
|
|
|
|
|
// Add a newline here so we can keep it pretty.
|
|
|
|
|
rendered = format!("{}\n", rendered);
|
|
|
|
|
// For each line in the Vec.
|
|
|
|
|
for file in filevec.unwrap() {
|
|
|
|
|
// Add the file to the rendered String :)
|
|
|
|
|
// View count per file
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}file_expiry{{filename=\"{}\", filesize=\"{}\", filetype=\"{}\", views=\"{}\"}} {}\n",
|
|
|
|
|
rendered, file.filename, file.filesize, file.mimetype, file.views, file.expiry,
|
|
|
|
|
"{}file_views{{filename=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, file.filename, file.mimetype, file.views,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Getting the number of views for all dead filetypes.
|
|
|
|
|
let mut deadfileview = db::get_dead_fileviews(sqlconn).await;
|
|
|
|
|
// Add a newline here so we can keep it pretty.
|
|
|
|
|
rendered = format!("{}\n", rendered);
|
|
|
|
|
// Loop through each filetype and render it as a new line with a label for each type
|
|
|
|
|
for dfv in deadfileview.as_mut().unwrap() {
|
|
|
|
|
// Size per file
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}views_dead{{views=\"{}\"}} {}\n",
|
|
|
|
|
rendered,
|
|
|
|
|
&dfv.0.to_string(),
|
|
|
|
|
&dfv.1.to_string()
|
|
|
|
|
"{}file_size{{filename=\"{}\", mimetype=\"{}\"}} {}\n",
|
|
|
|
|
rendered, file.filename, file.mimetype, file.filesize,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Bandwidth per file
|
|
|
|
|
// Views * filesize
|
|
|
|
|
let bandwidth = file.views * file.filesize;
|
|
|
|
|
rendered = format!(
|
|
|
|
|
"{}file_bandwidth{{filename=\"{}\", mimetype=\"{}\"}} {}\n\n",
|
|
|
|
|
rendered, file.filename, file.mimetype, bandwidth,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
////
|
|
|
|
|
// Error Stats
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
// Number of files blocked per filetype
|
|
|
|
|
|
|
|
|
|
// Number of files blocked by IP?
|
|
|
|
|
|
|
|
|
|
// Number of backend errors (by error type) (plus collision errors)
|
|
|
|
|
|
|
|
|
|
////
|
|
|
|
|
// QR Scanning Stats
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// Add how long it took to get all of those metrics to the page!
|
|
|
|
|
let end = Instant::now();
|
|
|
|
|
rendered = format!(
|
|
|
|
|