2022-10-13 20:30:31 +02:00
|
|
|
pub mod routes;
|
|
|
|
|
|
|
|
use std::{
|
2022-10-14 01:59:29 +02:00
|
|
|
cmp::max,
|
2022-10-13 20:30:31 +02:00
|
|
|
collections::VecDeque,
|
|
|
|
iter::Iterator,
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering},
|
|
|
|
Arc
|
2022-10-10 23:07:40 +02:00
|
|
|
}
|
2022-10-13 20:30:31 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
use rayon_core::ThreadPoolBuilder;
|
|
|
|
use rustracing_jaeger::Span;
|
|
|
|
|
|
|
|
use crate::metrics;
|
2022-10-10 23:07:40 +02:00
|
|
|
|
|
|
|
pub static WINDOWS_INVALID_CHARS: &str = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F<>:\"/\\|";
|
|
|
|
|
|
|
|
pub struct ZipProgressEntry {
|
|
|
|
temp_id: u64,
|
|
|
|
done: AtomicBool,
|
|
|
|
progress: AtomicU64,
|
|
|
|
total: AtomicU64,
|
|
|
|
delete_after: AtomicI64
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum CreateNodeResult {
|
|
|
|
InvalidName,
|
|
|
|
InvalidParent,
|
|
|
|
Exists(bool, i32)
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub static DELETE_POOL: Lazy<rayon_core::ThreadPool> = Lazy::new(|| {
|
|
|
|
ThreadPoolBuilder::new()
|
|
|
|
.num_threads(1)
|
|
|
|
.thread_name(|i| format!("Delete thread {}", i))
|
|
|
|
.build()
|
|
|
|
.unwrap()
|
|
|
|
});
|
|
|
|
pub static ZIP_POOL: Lazy<rayon_core::ThreadPool> = Lazy::new(|| {
|
|
|
|
ThreadPoolBuilder::new()
|
|
|
|
.num_threads(3)
|
|
|
|
.thread_name(|i| format!("Zip thread {}", i))
|
|
|
|
.build()
|
|
|
|
.unwrap()
|
|
|
|
});
|
|
|
|
pub static ZIP_TO_PROGRESS: Lazy<
|
|
|
|
parking_lot::RwLock<std::collections::HashMap<std::collections::BTreeSet<i32>, Arc<ZipProgressEntry>>>
|
|
|
|
> = Lazy::new(|| parking_lot::RwLock::new(std::collections::HashMap::new()));
|
2022-10-10 23:07:40 +02:00
|
|
|
|
|
|
|
static NEXT_TEMP_ID: AtomicU64 = AtomicU64::new(0);
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
fn cleanup_temp_zips(span: &Span) {
|
|
|
|
let _span = metrics::span("zipping - cleanup", span);
|
|
|
|
let mut existing = ZIP_TO_PROGRESS.write();
|
2022-10-10 23:07:40 +02:00
|
|
|
existing.retain(|_, v| {
|
2022-10-13 20:30:31 +02:00
|
|
|
if Arc::strong_count(v) == 1
|
|
|
|
&& v.done.load(Ordering::Relaxed)
|
|
|
|
&& v.delete_after.load(Ordering::Relaxed) <= chrono::Utc::now().timestamp()
|
|
|
|
{
|
|
|
|
std::fs::remove_file(std::path::Path::new(&format!("./temp/{}", v.temp_id)))
|
|
|
|
.expect("Failed to delete temp file");
|
2022-10-10 23:07:40 +02:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
fn get_nodes_recursive(
|
|
|
|
span: &Span,
|
|
|
|
root: crate::db::Inode,
|
|
|
|
db: &mut crate::db::DBConnection
|
|
|
|
) -> VecDeque<crate::db::Inode> {
|
|
|
|
let inner_span = metrics::span("get_nodes_recursive", span);
|
2022-10-10 23:07:40 +02:00
|
|
|
let mut nodes = VecDeque::from(vec![root.clone()]);
|
2022-10-13 20:30:31 +02:00
|
|
|
if root.is_file {
|
|
|
|
return nodes;
|
|
|
|
}
|
2022-10-10 23:07:40 +02:00
|
|
|
let mut nodes_to_check = VecDeque::from(vec![root]);
|
|
|
|
while !nodes_to_check.is_empty() {
|
|
|
|
let node = nodes_to_check.pop_front().unwrap();
|
2022-10-13 20:30:31 +02:00
|
|
|
db.get_children(&inner_span, node.id).iter().for_each(|node| {
|
2022-10-10 23:07:40 +02:00
|
|
|
nodes.push_back(node.clone());
|
2022-10-13 20:30:31 +02:00
|
|
|
if !node.is_file {
|
|
|
|
nodes_to_check.push_front(node.clone());
|
|
|
|
}
|
2022-10-10 23:07:40 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
nodes
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
fn get_node_path(span: &Span, node: crate::db::Inode, db: &mut crate::db::DBConnection) -> VecDeque<crate::db::Inode> {
|
|
|
|
let inner_span = metrics::span("get_node_path", span);
|
2022-10-10 23:07:40 +02:00
|
|
|
let mut path = VecDeque::from(vec![node.clone()]);
|
|
|
|
let mut node = node;
|
|
|
|
while let Some(parent) = node.parent_id {
|
2022-10-13 20:30:31 +02:00
|
|
|
node = db.get_node(&inner_span, parent).expect("Failed to get node parent");
|
2022-10-10 23:07:40 +02:00
|
|
|
path.push_front(node.clone());
|
|
|
|
}
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
fn get_total_size(span: &Span, node: crate::db::Inode, db: &mut crate::db::DBConnection) -> u64 {
|
|
|
|
let inner_span = metrics::span("get_total_size", span);
|
|
|
|
get_nodes_recursive(&inner_span, node, db)
|
|
|
|
.iter()
|
|
|
|
.fold(0_u64, |acc, node| acc + node.size.unwrap_or(0) as u64)
|
2022-10-10 23:07:40 +02:00
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn get_node_and_validate(
|
|
|
|
span: &Span,
|
|
|
|
user: &crate::db::User,
|
|
|
|
node: i32,
|
|
|
|
db: &mut crate::db::DBConnection
|
|
|
|
) -> Option<crate::db::Inode> {
|
|
|
|
let node = db.get_node(span, node)?;
|
2022-10-10 23:07:40 +02:00
|
|
|
if node.owner_id != user.id {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn create_node(
|
|
|
|
span: &Span,
|
|
|
|
name: String,
|
|
|
|
owner: &crate::db::User,
|
|
|
|
file: bool,
|
|
|
|
parent: Option<i32>,
|
|
|
|
force: bool,
|
|
|
|
db: &mut crate::db::DBConnection
|
|
|
|
) -> Result<crate::db::Inode, CreateNodeResult> {
|
|
|
|
let inner_span = metrics::span("create_node", span);
|
2022-10-10 23:07:40 +02:00
|
|
|
if !force && (name.is_empty() || name.starts_with(' ') || name.contains(|c| {
|
2022-10-13 20:30:31 +02:00
|
|
|
WINDOWS_INVALID_CHARS.contains(c)
|
|
|
|
} || name.ends_with(' ') || name.ends_with('.') || name == "." || name == "..")) {
|
|
|
|
return Err(CreateNodeResult::InvalidName);
|
|
|
|
}
|
2022-10-10 23:07:40 +02:00
|
|
|
|
|
|
|
if let Some(parent) = parent {
|
2022-10-13 20:30:31 +02:00
|
|
|
let parent = match get_node_and_validate(&inner_span, owner, parent, db) {
|
|
|
|
None => {
|
|
|
|
return Err(CreateNodeResult::InvalidParent);
|
|
|
|
}
|
2022-10-10 23:07:40 +02:00
|
|
|
Some(v) => v
|
|
|
|
};
|
2022-10-13 20:30:31 +02:00
|
|
|
if parent.is_file {
|
|
|
|
return Err(CreateNodeResult::InvalidParent);
|
|
|
|
}
|
|
|
|
let children = db.get_children(&inner_span, parent.id);
|
2022-10-10 23:07:40 +02:00
|
|
|
for child in children {
|
|
|
|
if child.name == name {
|
|
|
|
return Err(CreateNodeResult::Exists(child.is_file, child.id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
Ok(db.create_node(&inner_span, file, name, parent, owner.id))
|
2022-10-10 23:07:40 +02:00
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn delete_node_root(span: &Span, node: &crate::db::Inode, db: &mut crate::db::DBConnection) {
|
|
|
|
get_nodes_recursive(span, node.clone(), db).iter().rev().for_each(|node| {
|
|
|
|
db.delete_node(span, node);
|
2022-10-10 23:07:40 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn delete_node(
|
|
|
|
span: &Span,
|
|
|
|
node: &crate::db::Inode,
|
|
|
|
sender: &std::sync::mpsc::Sender<String>,
|
|
|
|
db: &mut crate::db::DBConnection
|
|
|
|
) {
|
|
|
|
if node.parent_id.is_none() {
|
|
|
|
return;
|
|
|
|
}
|
2022-10-10 23:07:40 +02:00
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
for node in get_nodes_recursive(span, node.clone(), db).iter().rev() {
|
|
|
|
sender.send(format!("Deleting {}...", generate_path(span, node, db))).unwrap();
|
|
|
|
db.delete_node(span, node);
|
|
|
|
sender.send(" Done \n".to_owned()).unwrap();
|
2022-10-10 23:07:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn generate_path(span: &Span, node: &crate::db::Inode, db: &mut crate::db::DBConnection) -> String {
|
2022-10-10 23:07:40 +02:00
|
|
|
let mut path = String::new();
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
get_node_path(span, node.clone(), db).iter().for_each(|node| {
|
2022-10-10 23:07:40 +02:00
|
|
|
if node.parent_id.is_none() {
|
|
|
|
path += "/";
|
|
|
|
} else {
|
|
|
|
path += &node.name;
|
|
|
|
if !node.is_file {
|
|
|
|
path += "/";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
pub fn generate_path_dto(
|
|
|
|
span: &Span,
|
|
|
|
node: &crate::db::Inode,
|
|
|
|
db: &mut crate::db::DBConnection
|
|
|
|
) -> crate::dto::responses::GetPath {
|
2022-10-10 23:07:40 +02:00
|
|
|
let mut get_path = crate::dto::responses::GetPath {
|
|
|
|
segments: Vec::new()
|
|
|
|
};
|
|
|
|
|
2022-10-13 20:30:31 +02:00
|
|
|
get_node_path(span, node.clone(), db).iter().for_each(|node| {
|
2022-10-10 23:07:40 +02:00
|
|
|
if node.parent_id.is_none() {
|
|
|
|
get_path.segments.push(crate::dto::responses::GetPathSegment {
|
|
|
|
path: "/".to_owned(),
|
|
|
|
node: Some(node.id)
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
get_path.segments.push(crate::dto::responses::GetPathSegment {
|
|
|
|
path: node.name.clone(),
|
|
|
|
node: Some(node.id)
|
|
|
|
});
|
|
|
|
if !node.is_file {
|
|
|
|
get_path.segments.push(crate::dto::responses::GetPathSegment {
|
|
|
|
path: "/".to_owned(),
|
|
|
|
node: None
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
get_path
|
|
|
|
}
|
2022-10-14 01:59:29 +02:00
|
|
|
|
|
|
|
fn resize_dimensions(width: u32, height: u32) -> (u32, u32) {
|
|
|
|
let wratio = 300.0 / width as f64;
|
|
|
|
let hratio = 300.0 / height as f64;
|
|
|
|
|
|
|
|
let ratio = f64::min(wratio, hratio);
|
|
|
|
|
|
|
|
(
|
|
|
|
max((width as f64 * ratio).round() as u64, 1) as u32,
|
|
|
|
max((height as f64 * ratio).round() as u64, 1) as u32
|
|
|
|
)
|
|
|
|
}
|