mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
Drop unneeded dependencies
This commit is contained in:
parent
a75c62bb8b
commit
e21fd29c09
11 changed files with 163 additions and 260 deletions
76
Cargo.lock
generated
76
Cargo.lock
generated
|
@ -34,20 +34,6 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "actix-fs"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "git+https://git.asonix.dog/asonix/actix-fs?branch=asonix/actix-rt-2#aef0e3c557b1365c0c1039bedd321724cd09201f"
|
|
||||||
dependencies = [
|
|
||||||
"actix-rt",
|
|
||||||
"bytes",
|
|
||||||
"futures-util",
|
|
||||||
"log",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.0.0-beta.9"
|
version = "3.0.0-beta.9"
|
||||||
|
@ -292,27 +278,6 @@ version = "1.0.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream-impl",
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream-impl"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -998,16 +963,13 @@ name = "pict-rs"
|
||||||
version = "0.3.0-alpha.23"
|
version = "0.3.0-alpha.23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-form-data",
|
"actix-form-data",
|
||||||
"actix-fs",
|
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
|
||||||
"awc",
|
"awc",
|
||||||
"base64",
|
"base64",
|
||||||
"futures",
|
"futures-core",
|
||||||
"mime",
|
"mime",
|
||||||
"num_cpus",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1018,7 +980,6 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time 0.3.2",
|
"time 0.3.2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
|
@ -1477,9 +1438,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.75"
|
version = "1.0.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
|
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1602,37 +1563,14 @@ dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"tokio-macros",
|
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-macros"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-stream"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.6.7"
|
version = "0.6.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
|
checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -1739,9 +1677,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.13.0"
|
version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-trie"
|
name = "ucd-trie"
|
||||||
|
|
|
@ -12,16 +12,13 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-form-data = "0.6.0-beta.1"
|
actix-form-data = "0.6.0-beta.1"
|
||||||
actix-fs = { git = "https://git.asonix.dog/asonix/actix-fs", branch = "asonix/actix-rt-2" }
|
|
||||||
actix-rt = "2.2.0"
|
actix-rt = "2.2.0"
|
||||||
actix-web = { version = "4.0.0-beta.8", default-features = false }
|
actix-web = { version = "4.0.0-beta.8", default-features = false }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
async-stream = "0.3.0"
|
|
||||||
awc = { version = "3.0.0-beta.7", default-features = false }
|
awc = { version = "3.0.0-beta.7", default-features = false }
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
futures = "0.3.4"
|
futures-core = "0.3.17"
|
||||||
mime = "0.3.1"
|
mime = "0.3.1"
|
||||||
num_cpus = "1"
|
|
||||||
once_cell = "1.4.0"
|
once_cell = "1.4.0"
|
||||||
rand = "0.8.0"
|
rand = "0.8.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
@ -31,8 +28,7 @@ sled = { version = "0.34.6" }
|
||||||
structopt = "0.3.14"
|
structopt = "0.3.14"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
time = { version = "0.3.0", features = ["serde"] }
|
time = { version = "0.3.0", features = ["serde"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["fs", "io-util", "macros", "process", "sync"] }
|
tokio = { version = "1", default-features = false, features = ["fs", "io-util", "process", "sync"] }
|
||||||
tokio-stream = { version = "0.1", default-features = false }
|
|
||||||
tokio-util = { version = "0.6", default-features = false, features = ["codec"] }
|
tokio-util = { version = "0.6", default-features = false, features = ["codec"] }
|
||||||
tracing = "0.1.15"
|
tracing = "0.1.15"
|
||||||
tracing-futures = "0.2.4"
|
tracing-futures = "0.2.4"
|
||||||
|
|
|
@ -18,9 +18,6 @@ pub(crate) enum UploadError {
|
||||||
#[error("Error interacting with filesystem, {0}")]
|
#[error("Error interacting with filesystem, {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("Error in filesyste, {0}")]
|
|
||||||
Fs(#[from] actix_fs::Error),
|
|
||||||
|
|
||||||
#[error("Panic in blocking operation")]
|
#[error("Panic in blocking operation")]
|
||||||
Canceled,
|
Canceled,
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,6 @@ pub(crate) enum VideoError {
|
||||||
|
|
||||||
#[error("Failed to convert file")]
|
#[error("Failed to convert file")]
|
||||||
Status,
|
Status,
|
||||||
|
|
||||||
#[error("Transcode semaphore is closed")]
|
|
||||||
Closed,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum InputFormat {
|
pub(crate) enum InputFormat {
|
||||||
|
@ -49,14 +46,6 @@ impl ThumbnailFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MAX_TRANSCODES: once_cell::sync::OnceCell<tokio::sync::Semaphore> =
|
|
||||||
once_cell::sync::OnceCell::new();
|
|
||||||
|
|
||||||
fn semaphore() -> &'static tokio::sync::Semaphore {
|
|
||||||
MAX_TRANSCODES
|
|
||||||
.get_or_init(|| tokio::sync::Semaphore::new(num_cpus::get().saturating_sub(1).max(1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn to_mp4_bytes(
|
pub(crate) fn to_mp4_bytes(
|
||||||
input: Bytes,
|
input: Bytes,
|
||||||
input_format: InputFormat,
|
input_format: InputFormat,
|
||||||
|
@ -92,8 +81,6 @@ where
|
||||||
P1: AsRef<std::path::Path>,
|
P1: AsRef<std::path::Path>,
|
||||||
P2: AsRef<std::path::Path>,
|
P2: AsRef<std::path::Path>,
|
||||||
{
|
{
|
||||||
let permit = semaphore().acquire().await?;
|
|
||||||
|
|
||||||
let mut child = Command::new("ffmpeg")
|
let mut child = Command::new("ffmpeg")
|
||||||
.arg(&"-i")
|
.arg(&"-i")
|
||||||
.arg(&from.as_ref())
|
.arg(&from.as_ref())
|
||||||
|
@ -109,7 +96,6 @@ where
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
let status = child.wait().await?;
|
let status = child.wait().await?;
|
||||||
drop(permit);
|
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(VideoError::Status);
|
return Err(VideoError::Status);
|
||||||
|
@ -117,9 +103,3 @@ where
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tokio::sync::AcquireError> for VideoError {
|
|
||||||
fn from(_: tokio::sync::AcquireError) -> VideoError {
|
|
||||||
VideoError::Closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,9 +11,6 @@ pub(crate) enum MagickError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
IO(#[from] std::io::Error),
|
IO(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("Magick semaphore is closed")]
|
|
||||||
Closed,
|
|
||||||
|
|
||||||
#[error("Invalid format")]
|
#[error("Invalid format")]
|
||||||
Format,
|
Format,
|
||||||
}
|
}
|
||||||
|
@ -32,14 +29,6 @@ pub(crate) struct Details {
|
||||||
pub(crate) height: usize,
|
pub(crate) height: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
static MAX_CONVERSIONS: once_cell::sync::OnceCell<tokio::sync::Semaphore> =
|
|
||||||
once_cell::sync::OnceCell::new();
|
|
||||||
|
|
||||||
fn semaphore() -> &'static tokio::sync::Semaphore {
|
|
||||||
MAX_CONVERSIONS
|
|
||||||
.get_or_init(|| tokio::sync::Semaphore::new(num_cpus::get().saturating_sub(1).max(1)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clear_metadata_bytes_read(input: Bytes) -> std::io::Result<impl AsyncRead + Unpin> {
|
pub(crate) fn clear_metadata_bytes_read(input: Bytes) -> std::io::Result<impl AsyncRead + Unpin> {
|
||||||
let process = Process::spawn(Command::new("magick").args(["convert", "-", "-strip", "-"]))?;
|
let process = Process::spawn(Command::new("magick").args(["convert", "-", "-strip", "-"]))?;
|
||||||
|
|
||||||
|
@ -81,16 +70,12 @@ pub(crate) async fn details<P>(file: P) -> Result<Details, MagickError>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>,
|
P: AsRef<std::path::Path>,
|
||||||
{
|
{
|
||||||
let permit = semaphore().acquire().await?;
|
|
||||||
|
|
||||||
let output = Command::new("magick")
|
let output = Command::new("magick")
|
||||||
.args([&"identify", &"-ping", &"-format", &"%w %h | %m\n"])
|
.args([&"identify", &"-ping", &"-format", &"%w %h | %m\n"])
|
||||||
.arg(&file.as_ref())
|
.arg(&file.as_ref())
|
||||||
.output()
|
.output()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
drop(permit);
|
|
||||||
|
|
||||||
let s = String::from_utf8_lossy(&output.stdout);
|
let s = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
parse_details(s)
|
parse_details(s)
|
||||||
|
@ -140,8 +125,6 @@ fn parse_details(s: std::borrow::Cow<'_, str>) -> Result<Details, MagickError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn input_type_bytes(mut input: Bytes) -> Result<ValidInputType, MagickError> {
|
pub(crate) async fn input_type_bytes(mut input: Bytes) -> Result<ValidInputType, MagickError> {
|
||||||
let permit = semaphore().acquire().await.map_err(MagickError::from)?;
|
|
||||||
|
|
||||||
let mut child = Command::new("magick")
|
let mut child = Command::new("magick")
|
||||||
.args(["identify", "-ping", "-format", "%m\n", "-"])
|
.args(["identify", "-ping", "-format", "%m\n", "-"])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
|
@ -152,13 +135,13 @@ pub(crate) async fn input_type_bytes(mut input: Bytes) -> Result<ValidInputType,
|
||||||
let mut stdout = child.stdout.take().unwrap();
|
let mut stdout = child.stdout.take().unwrap();
|
||||||
|
|
||||||
stdin.write_all_buf(&mut input).await?;
|
stdin.write_all_buf(&mut input).await?;
|
||||||
|
drop(stdin);
|
||||||
|
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
stdout.read_to_end(&mut vec).await?;
|
stdout.read_to_end(&mut vec).await?;
|
||||||
|
drop(stdout);
|
||||||
|
|
||||||
drop(stdin);
|
|
||||||
child.wait().await?;
|
child.wait().await?;
|
||||||
drop(permit);
|
|
||||||
|
|
||||||
let s = String::from_utf8_lossy(&vec);
|
let s = String::from_utf8_lossy(&vec);
|
||||||
parse_input_type(s)
|
parse_input_type(s)
|
||||||
|
@ -198,12 +181,6 @@ pub(crate) fn process_image_write_read(
|
||||||
Ok(process.write_read(input).unwrap())
|
Ok(process.write_read(input).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tokio::sync::AcquireError> for MagickError {
|
|
||||||
fn from(_: tokio::sync::AcquireError) -> MagickError {
|
|
||||||
MagickError::Closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::num::ParseIntError> for MagickError {
|
impl From<std::num::ParseIntError> for MagickError {
|
||||||
fn from(_: std::num::ParseIntError) -> MagickError {
|
fn from(_: std::num::ParseIntError) -> MagickError {
|
||||||
MagickError::Format
|
MagickError::Format
|
||||||
|
|
57
src/main.rs
57
src/main.rs
|
@ -6,11 +6,11 @@ use actix_web::{
|
||||||
web, App, HttpResponse, HttpResponseBuilder, HttpServer,
|
web, App, HttpResponse, HttpResponseBuilder, HttpServer,
|
||||||
};
|
};
|
||||||
use awc::Client;
|
use awc::Client;
|
||||||
use futures::stream::{Stream, TryStreamExt};
|
use futures_core::stream::Stream;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{collections::HashSet, path::PathBuf, pin::Pin, time::SystemTime};
|
use std::{collections::HashSet, future::ready, path::PathBuf, time::SystemTime};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tracing::{debug, error, info, instrument, Span};
|
use tracing::{debug, error, info, instrument, Span};
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ use self::{
|
||||||
config::{Config, Format},
|
config::{Config, Format},
|
||||||
error::UploadError,
|
error::UploadError,
|
||||||
middleware::{Internal, Tracing},
|
middleware::{Internal, Tracing},
|
||||||
|
stream::{once, LocalBoxStream},
|
||||||
upload_manager::{Details, UploadManager},
|
upload_manager::{Details, UploadManager},
|
||||||
validate::{image_webp, video_mp4},
|
validate::{image_webp, video_mp4},
|
||||||
};
|
};
|
||||||
|
@ -64,12 +65,12 @@ static CONFIG: Lazy<Config> = Lazy::new(Config::from_args);
|
||||||
async fn safe_move_file(from: PathBuf, to: PathBuf) -> Result<(), UploadError> {
|
async fn safe_move_file(from: PathBuf, to: PathBuf) -> Result<(), UploadError> {
|
||||||
if let Some(path) = to.parent() {
|
if let Some(path) = to.parent() {
|
||||||
debug!("Creating directory {:?}", path);
|
debug!("Creating directory {:?}", path);
|
||||||
actix_fs::create_dir_all(path.to_owned()).await?;
|
tokio::fs::create_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Checking if {:?} already exists", to);
|
debug!("Checking if {:?} already exists", to);
|
||||||
if let Err(e) = actix_fs::metadata(to.clone()).await {
|
if let Err(e) = tokio::fs::metadata(&to).await {
|
||||||
if e.kind() != Some(std::io::ErrorKind::NotFound) {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,8 +78,8 @@ async fn safe_move_file(from: PathBuf, to: PathBuf) -> Result<(), UploadError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Moving {:?} to {:?}", from, to);
|
debug!("Moving {:?} to {:?}", from, to);
|
||||||
actix_fs::copy(from.clone(), to).await?;
|
tokio::fs::copy(&from, to).await?;
|
||||||
actix_fs::remove_file(from).await?;
|
tokio::fs::remove_file(from).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ where
|
||||||
{
|
{
|
||||||
if let Some(path) = path.as_ref().parent() {
|
if let Some(path) = path.as_ref().parent() {
|
||||||
debug!("Creating directory {:?}", path);
|
debug!("Creating directory {:?}", path);
|
||||||
actix_fs::create_dir_all(path.to_owned()).await?;
|
tokio::fs::create_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -96,17 +97,17 @@ where
|
||||||
|
|
||||||
// Try writing to a file
|
// Try writing to a file
|
||||||
#[instrument(skip(bytes))]
|
#[instrument(skip(bytes))]
|
||||||
async fn safe_save_file(path: PathBuf, bytes: web::Bytes) -> Result<(), UploadError> {
|
async fn safe_save_file(path: PathBuf, mut bytes: web::Bytes) -> Result<(), UploadError> {
|
||||||
if let Some(path) = path.parent() {
|
if let Some(path) = path.parent() {
|
||||||
// create the directory for the file
|
// create the directory for the file
|
||||||
debug!("Creating directory {:?}", path);
|
debug!("Creating directory {:?}", path);
|
||||||
actix_fs::create_dir_all(path.to_owned()).await?;
|
tokio::fs::create_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only write the file if it doesn't already exist
|
// Only write the file if it doesn't already exist
|
||||||
debug!("Checking if {:?} already exists", path);
|
debug!("Checking if {:?} already exists", path);
|
||||||
if let Err(e) = actix_fs::metadata(path.clone()).await {
|
if let Err(e) = tokio::fs::metadata(&path).await {
|
||||||
if e.kind() != Some(std::io::ErrorKind::NotFound) {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,14 +116,14 @@ async fn safe_save_file(path: PathBuf, bytes: web::Bytes) -> Result<(), UploadEr
|
||||||
|
|
||||||
// Open the file for writing
|
// Open the file for writing
|
||||||
debug!("Creating {:?}", path);
|
debug!("Creating {:?}", path);
|
||||||
let file = actix_fs::file::create(path.clone()).await?;
|
let mut file = tokio::fs::File::create(&path).await?;
|
||||||
|
|
||||||
// try writing
|
// try writing
|
||||||
debug!("Writing to {:?}", path);
|
debug!("Writing to {:?}", path);
|
||||||
if let Err(e) = actix_fs::file::write(file, bytes).await {
|
if let Err(e) = file.write_all_buf(&mut bytes).await {
|
||||||
error!("Error writing {:?}, {}", path, e);
|
error!("Error writing {:?}, {}", path, e);
|
||||||
// remove file if writing failed before completion
|
// remove file if writing failed before completion
|
||||||
actix_fs::remove_file(path).await?;
|
tokio::fs::remove_file(path).await?;
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
debug!("{:?} written", path);
|
debug!("{:?} written", path);
|
||||||
|
@ -240,7 +241,7 @@ async fn download(
|
||||||
|
|
||||||
let fut = res.body().limit(CONFIG.max_file_size() * MEGABYTES);
|
let fut = res.body().limit(CONFIG.max_file_size() * MEGABYTES);
|
||||||
|
|
||||||
let stream = Box::pin(futures::stream::once(fut));
|
let stream = Box::pin(once(fut));
|
||||||
|
|
||||||
let alias = manager.upload(stream).await?;
|
let alias = manager.upload(stream).await?;
|
||||||
let delete_token = manager.delete_token(alias.clone()).await?;
|
let delete_token = manager.delete_token(alias.clone()).await?;
|
||||||
|
@ -362,8 +363,8 @@ async fn process(
|
||||||
prepare_process(query, ext.as_str(), &manager, &whitelist).await?;
|
prepare_process(query, ext.as_str(), &manager, &whitelist).await?;
|
||||||
|
|
||||||
// If the thumbnail doesn't exist, we need to create it
|
// If the thumbnail doesn't exist, we need to create it
|
||||||
let thumbnail_exists = if let Err(e) = actix_fs::metadata(thumbnail_path.clone()).await {
|
let thumbnail_exists = if let Err(e) = tokio::fs::metadata(&thumbnail_path).await {
|
||||||
if e.kind() != Some(std::io::ErrorKind::NotFound) {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
error!("Error looking up processed image, {}", e);
|
error!("Error looking up processed image, {}", e);
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
|
@ -442,7 +443,7 @@ async fn process(
|
||||||
|
|
||||||
return Ok(srv_response(
|
return Ok(srv_response(
|
||||||
HttpResponse::Ok(),
|
HttpResponse::Ok(),
|
||||||
futures::stream::once(futures::future::ready(Ok(bytes) as Result<_, UploadError>)),
|
once(ready(Ok(bytes) as Result<_, UploadError>)),
|
||||||
details.content_type(),
|
details.content_type(),
|
||||||
7 * DAYS,
|
7 * DAYS,
|
||||||
details.system_time(),
|
details.system_time(),
|
||||||
|
@ -527,9 +528,9 @@ async fn ranged_file_resp(
|
||||||
if range_header.is_empty() {
|
if range_header.is_empty() {
|
||||||
return Err(UploadError::Range);
|
return Err(UploadError::Range);
|
||||||
} else if range_header.len() == 1 {
|
} else if range_header.len() == 1 {
|
||||||
let file = actix_fs::file::open(path).await?;
|
let file = tokio::fs::File::open(path).await?;
|
||||||
|
|
||||||
let (file, meta) = actix_fs::file::metadata(file).await?;
|
let meta = file.metadata().await?;
|
||||||
|
|
||||||
let range = range_header.ranges().next().unwrap();
|
let range = range_header.ranges().next().unwrap();
|
||||||
|
|
||||||
|
@ -543,12 +544,8 @@ async fn ranged_file_resp(
|
||||||
}
|
}
|
||||||
//No Range header in the request - return the entire document
|
//No Range header in the request - return the entire document
|
||||||
None => {
|
None => {
|
||||||
let stream = actix_fs::read_to_stream(path)
|
let file = tokio::fs::File::open(path).await?;
|
||||||
.await?
|
let stream = Box::pin(crate::stream::bytes_stream(file)) as LocalBoxStream<'_, _>;
|
||||||
.faster()
|
|
||||||
.map_err(UploadError::from);
|
|
||||||
let stream: Pin<Box<dyn Stream<Item = Result<web::Bytes, UploadError>>>> =
|
|
||||||
Box::pin(stream);
|
|
||||||
(HttpResponse::Ok(), stream)
|
(HttpResponse::Ok(), stream)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -774,8 +771,8 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
.run()
|
.run()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if actix_fs::metadata(&*TMP_DIR).await.is_ok() {
|
if tokio::fs::metadata(&*TMP_DIR).await.is_ok() {
|
||||||
actix_fs::remove_dir_all(&*TMP_DIR).await?;
|
tokio::fs::remove_dir_all(&*TMP_DIR).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
use crate::stream::LocalBoxFuture;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::{Service, ServiceRequest, Transform},
|
dev::{Service, ServiceRequest, Transform},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
HttpResponse, ResponseError,
|
HttpResponse, ResponseError,
|
||||||
};
|
};
|
||||||
use futures::future::{ok, LocalBoxFuture, Ready};
|
use std::{
|
||||||
use std::task::{Context, Poll};
|
future::{ready, Ready},
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
use tracing_futures::{Instrument, Instrumented};
|
use tracing_futures::{Instrument, Instrumented};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -47,7 +50,7 @@ where
|
||||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
fn new_transform(&self, service: S) -> Self::Future {
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
ok(TracingMiddleware { inner: service })
|
ready(Ok(TracingMiddleware { inner: service }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +88,7 @@ where
|
||||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
fn new_transform(&self, service: S) -> Self::Future {
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
ok(InternalMiddleware(self.0.clone(), service))
|
ready(Ok(InternalMiddleware(self.0.clone(), service)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,7 @@ pub(crate) async fn prepare_image(
|
||||||
let jpg_path = format!("{}.jpg", original_path_str);
|
let jpg_path = format!("{}.jpg", original_path_str);
|
||||||
let jpg_path = PathBuf::from(jpg_path);
|
let jpg_path = PathBuf::from(jpg_path);
|
||||||
|
|
||||||
if actix_fs::metadata(jpg_path.clone()).await.is_ok() {
|
if tokio::fs::metadata(&jpg_path).await.is_ok() {
|
||||||
return Ok(Some((jpg_path, Exists::Exists)));
|
return Ok(Some((jpg_path, Exists::Exists)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ pub(crate) async fn prepare_image(
|
||||||
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
error!("transcode error: {:?}", e);
|
error!("transcode error: {:?}", e);
|
||||||
actix_fs::remove_file(tmpfile.clone()).await?;
|
tokio::fs::remove_file(&tmpfile).await?;
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
66
src/range.rs
66
src/range.rs
|
@ -1,4 +1,7 @@
|
||||||
use crate::UploadError;
|
use crate::{
|
||||||
|
stream::{bytes_stream, LocalBoxStream},
|
||||||
|
UploadError,
|
||||||
|
};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::Payload,
|
dev::Payload,
|
||||||
http::{
|
http::{
|
||||||
|
@ -8,9 +11,8 @@ use actix_web::{
|
||||||
web::Bytes,
|
web::Bytes,
|
||||||
FromRequest, HttpRequest,
|
FromRequest, HttpRequest,
|
||||||
};
|
};
|
||||||
use futures::stream::{Stream, StreamExt, TryStreamExt};
|
use std::{future::ready, io};
|
||||||
use std::{fs, io};
|
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||||
use std::{future::ready, pin::Pin};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Range {
|
pub(crate) enum Range {
|
||||||
|
@ -45,32 +47,25 @@ impl Range {
|
||||||
|
|
||||||
pub(crate) async fn chop_file(
|
pub(crate) async fn chop_file(
|
||||||
&self,
|
&self,
|
||||||
file: fs::File,
|
mut file: tokio::fs::File,
|
||||||
) -> Result<Pin<Box<dyn Stream<Item = Result<Bytes, UploadError>>>>, UploadError> {
|
) -> Result<LocalBoxStream<'static, Result<Bytes, UploadError>>, UploadError> {
|
||||||
match self {
|
match self {
|
||||||
Range::RangeStart(start) => {
|
Range::RangeStart(start) => {
|
||||||
let (file, _) = actix_fs::file::seek(file, io::SeekFrom::Start(*start)).await?;
|
file.seek(io::SeekFrom::Start(*start)).await?;
|
||||||
|
|
||||||
Ok(Box::pin(
|
Ok(Box::pin(bytes_stream(file)))
|
||||||
actix_fs::file::read_to_stream(file)
|
|
||||||
.await?
|
|
||||||
.faster()
|
|
||||||
.map_err(UploadError::from),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Range::SuffixLength(from_start) => {
|
Range::SuffixLength(from_start) => {
|
||||||
let (file, _) = actix_fs::file::seek(file, io::SeekFrom::Start(0)).await?;
|
file.seek(io::SeekFrom::Start(0)).await?;
|
||||||
|
let reader = file.take(*from_start);
|
||||||
|
|
||||||
Ok(Box::pin(
|
Ok(Box::pin(bytes_stream(reader)))
|
||||||
read_num_bytes_to_stream(file, *from_start as usize).await?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Range::Segment(start, end) => {
|
Range::Segment(start, end) => {
|
||||||
let (file, _) = actix_fs::file::seek(file, io::SeekFrom::Start(*start)).await?;
|
file.seek(io::SeekFrom::Start(*start)).await?;
|
||||||
|
let reader = file.take(end.saturating_sub(*start));
|
||||||
|
|
||||||
Ok(Box::pin(
|
Ok(Box::pin(bytes_stream(reader)))
|
||||||
read_num_bytes_to_stream(file, end.saturating_sub(*start) as usize).await?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,32 +170,3 @@ fn parse_range(s: &str) -> Result<Range, UploadError> {
|
||||||
Ok(Range::Segment(range_start, range_end))
|
Ok(Range::Segment(range_start, range_end))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_num_bytes_to_stream(
|
|
||||||
file: fs::File,
|
|
||||||
mut num_bytes: usize,
|
|
||||||
) -> Result<impl Stream<Item = Result<Bytes, UploadError>>, UploadError> {
|
|
||||||
let mut stream = actix_fs::file::read_to_stream(file).await?;
|
|
||||||
|
|
||||||
let stream = async_stream::stream! {
|
|
||||||
while let Some(res) = stream.next().await {
|
|
||||||
let read_bytes = res.as_ref().map(|b| b.len()).unwrap_or(0);
|
|
||||||
|
|
||||||
if read_bytes == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield res.map_err(UploadError::from).map(|bytes| {
|
|
||||||
if bytes.len() > num_bytes {
|
|
||||||
bytes.slice(0..num_bytes)
|
|
||||||
} else {
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
num_bytes = num_bytes.saturating_sub(read_bytes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(stream)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use actix_web::web::Bytes;
|
use crate::error::UploadError;
|
||||||
use futures::stream::{LocalBoxStream, Stream};
|
use actix_web::web::{Bytes, BytesMut};
|
||||||
|
use futures_core::stream::Stream;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
|
@ -7,9 +8,8 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::io::{AsyncRead, AsyncWriteExt, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncWriteExt, ReadBuf};
|
||||||
|
|
||||||
pub(crate) struct ReadAdapter<S> {
|
pub(crate) type LocalBoxStream<'a, T> = Pin<Box<dyn Stream<Item = T> + 'a>>;
|
||||||
inner: S,
|
pub(crate) type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct Process {
|
pub(crate) struct Process {
|
||||||
child: tokio::process::Child,
|
child: tokio::process::Child,
|
||||||
|
@ -21,10 +21,14 @@ pub(crate) struct ProcessRead<I> {
|
||||||
err_closed: bool,
|
err_closed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ProcessSinkStream<E> {
|
struct BytesFreezer<S>(S);
|
||||||
stream: LocalBoxStream<'static, Result<Bytes, E>>,
|
|
||||||
|
pub(crate) struct Once<T> {
|
||||||
|
inner: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Next<'a, S>(&'a mut S);
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
fn new(child: tokio::process::Child) -> Self {
|
fn new(child: tokio::process::Child) -> Self {
|
||||||
Process { child }
|
Process { child }
|
||||||
|
@ -79,28 +83,21 @@ impl Process {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E> AsyncRead for ReadAdapter<S>
|
pub(crate) fn bytes_stream(
|
||||||
where
|
input: impl AsyncRead + Unpin,
|
||||||
S: Stream<Item = Result<Bytes, E>> + Unpin,
|
) -> impl Stream<Item = Result<Bytes, UploadError>> + Unpin {
|
||||||
E: Into<Box<dyn std::error::Error + Send + Sync>>,
|
BytesFreezer(tokio_util::codec::FramedRead::new(
|
||||||
{
|
input,
|
||||||
fn poll_read(
|
tokio_util::codec::BytesCodec::new(),
|
||||||
mut self: Pin<&mut Self>,
|
))
|
||||||
cx: &mut Context<'_>,
|
}
|
||||||
buf: &mut ReadBuf<'_>,
|
|
||||||
) -> Poll<std::io::Result<()>> {
|
pub(crate) fn once<T>(input: T) -> Once<T> {
|
||||||
match Pin::new(&mut self.inner).poll_next(cx) {
|
Once { inner: Some(input) }
|
||||||
Poll::Ready(Some(Ok(bytes))) => {
|
}
|
||||||
buf.put_slice(&bytes);
|
|
||||||
Poll::Ready(Ok(()))
|
pub(crate) fn next<'a, S>(stream: &'a mut S) -> Next<'a, S> {
|
||||||
}
|
Next(stream)
|
||||||
Poll::Ready(None) => Poll::Ready(Ok(())),
|
|
||||||
Poll::Ready(Some(Err(e))) => {
|
|
||||||
Poll::Ready(Err(std::io::Error::new(std::io::ErrorKind::Other, e)))
|
|
||||||
}
|
|
||||||
Poll::Pending => Poll::Pending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> AsyncRead for ProcessRead<I>
|
impl<I> AsyncRead for ProcessRead<I>
|
||||||
|
@ -129,10 +126,48 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> Stream for ProcessSinkStream<E> {
|
impl<S> Stream for BytesFreezer<S>
|
||||||
type Item = Result<Bytes, E>;
|
where
|
||||||
|
S: Stream<Item = std::io::Result<BytesMut>> + Unpin,
|
||||||
|
{
|
||||||
|
type Item = Result<Bytes, UploadError>;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
Pin::new(&mut self.stream).poll_next(cx)
|
Pin::new(&mut self.0)
|
||||||
|
.poll_next(cx)
|
||||||
|
.map(|opt| opt.map(|res| res.map(|bytes_mut| bytes_mut.freeze())))
|
||||||
|
.map_err(UploadError::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Stream for Once<T>
|
||||||
|
where
|
||||||
|
T: Future + Unpin,
|
||||||
|
{
|
||||||
|
type Item = <T as Future>::Output;
|
||||||
|
|
||||||
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
if let Some(mut fut) = self.inner.take() {
|
||||||
|
match Pin::new(&mut fut).poll(cx) {
|
||||||
|
Poll::Ready(item) => Poll::Ready(Some(item)),
|
||||||
|
Poll::Pending => {
|
||||||
|
self.inner = Some(fut);
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Poll::Ready(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, S> Future for Next<'a, S>
|
||||||
|
where
|
||||||
|
S: Stream + Unpin,
|
||||||
|
{
|
||||||
|
type Output = Option<<S as Stream>::Item>;
|
||||||
|
|
||||||
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
Pin::new(&mut self.0).poll_next(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ use crate::{
|
||||||
config::Format,
|
config::Format,
|
||||||
error::UploadError,
|
error::UploadError,
|
||||||
migrate::{alias_id_key, alias_key, alias_key_bounds, variant_key_bounds, LatestDb},
|
migrate::{alias_id_key, alias_key, alias_key_bounds, variant_key_bounds, LatestDb},
|
||||||
|
stream::{next, LocalBoxStream},
|
||||||
to_ext,
|
to_ext,
|
||||||
};
|
};
|
||||||
use actix_web::web;
|
use actix_web::web;
|
||||||
use futures::stream::{Stream, StreamExt, TryStreamExt};
|
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -13,7 +13,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tokio::io::{AsyncRead, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncWriteExt, ReadBuf};
|
||||||
use tracing::{debug, error, info, instrument, warn, Span};
|
use tracing::{debug, error, info, instrument, warn, Span};
|
||||||
|
|
||||||
// TREE STRUCTURE
|
// TREE STRUCTURE
|
||||||
|
@ -92,7 +92,7 @@ impl std::fmt::Debug for UploadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UploadStream<E> = Pin<Box<dyn Stream<Item = Result<web::Bytes, E>>>>;
|
type UploadStream<E> = LocalBoxStream<'static, Result<web::Bytes, E>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Serde<T> {
|
pub(crate) struct Serde<T> {
|
||||||
|
@ -247,7 +247,7 @@ impl UploadManager {
|
||||||
root_dir.push("files");
|
root_dir.push("files");
|
||||||
|
|
||||||
// Ensure file dir exists
|
// Ensure file dir exists
|
||||||
actix_fs::create_dir_all(root_dir.clone()).await?;
|
tokio::fs::create_dir_all(&root_dir).await?;
|
||||||
|
|
||||||
Ok(UploadManager {
|
Ok(UploadManager {
|
||||||
inner: Arc::new(UploadManagerInner {
|
inner: Arc::new(UploadManagerInner {
|
||||||
|
@ -547,7 +547,7 @@ impl UploadManager {
|
||||||
let mut bytes_mut = actix_web::web::BytesMut::new();
|
let mut bytes_mut = actix_web::web::BytesMut::new();
|
||||||
|
|
||||||
debug!("Reading stream to memory");
|
debug!("Reading stream to memory");
|
||||||
while let Some(res) = stream.next().await {
|
while let Some(res) = next(&mut stream).await {
|
||||||
let bytes = res?;
|
let bytes = res?;
|
||||||
bytes_mut.extend_from_slice(&bytes);
|
bytes_mut.extend_from_slice(&bytes);
|
||||||
}
|
}
|
||||||
|
@ -582,7 +582,7 @@ impl UploadManager {
|
||||||
let mut bytes_mut = actix_web::web::BytesMut::new();
|
let mut bytes_mut = actix_web::web::BytesMut::new();
|
||||||
|
|
||||||
debug!("Reading stream to memory");
|
debug!("Reading stream to memory");
|
||||||
while let Some(res) = stream.next().await {
|
while let Some(res) = next(&mut stream).await {
|
||||||
let bytes = res?;
|
let bytes = res?;
|
||||||
bytes_mut.extend_from_slice(&bytes);
|
bytes_mut.extend_from_slice(&bytes);
|
||||||
}
|
}
|
||||||
|
@ -638,7 +638,7 @@ impl UploadManager {
|
||||||
|
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
debug!("Deleting {:?}", path);
|
debug!("Deleting {:?}", path);
|
||||||
if let Err(e) = actix_fs::remove_file(path).await {
|
if let Err(e) = tokio::fs::remove_file(path).await {
|
||||||
errors.push(e.into());
|
errors.push(e.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,8 +767,8 @@ impl UploadManager {
|
||||||
|
|
||||||
path.push(filename.clone());
|
path.push(filename.clone());
|
||||||
|
|
||||||
if let Err(e) = actix_fs::metadata(path).await {
|
if let Err(e) = tokio::fs::metadata(path).await {
|
||||||
if e.kind() == Some(std::io::ErrorKind::NotFound) {
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
debug!("Generated unused filename {}", filename);
|
debug!("Generated unused filename {}", filename);
|
||||||
return Ok(filename);
|
return Ok(filename);
|
||||||
}
|
}
|
||||||
|
@ -904,12 +904,12 @@ pub(crate) async fn safe_save_reader(
|
||||||
) -> Result<(), UploadError> {
|
) -> Result<(), UploadError> {
|
||||||
if let Some(path) = to.parent() {
|
if let Some(path) = to.parent() {
|
||||||
debug!("Creating directory {:?}", path);
|
debug!("Creating directory {:?}", path);
|
||||||
actix_fs::create_dir_all(path.to_owned()).await?;
|
tokio::fs::create_dir_all(path.to_owned()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Checking if {:?} already exists", to);
|
debug!("Checking if {:?} already exists", to);
|
||||||
if let Err(e) = actix_fs::metadata(to.clone()).await {
|
if let Err(e) = tokio::fs::metadata(to.clone()).await {
|
||||||
if e.kind() != Some(std::io::ErrorKind::NotFound) {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -928,7 +928,7 @@ pub(crate) async fn safe_save_reader(
|
||||||
#[instrument(skip(stream))]
|
#[instrument(skip(stream))]
|
||||||
pub(crate) async fn safe_save_stream<E>(
|
pub(crate) async fn safe_save_stream<E>(
|
||||||
to: PathBuf,
|
to: PathBuf,
|
||||||
stream: UploadStream<E>,
|
mut stream: UploadStream<E>,
|
||||||
) -> Result<(), UploadError>
|
) -> Result<(), UploadError>
|
||||||
where
|
where
|
||||||
UploadError: From<E>,
|
UploadError: From<E>,
|
||||||
|
@ -936,12 +936,12 @@ where
|
||||||
{
|
{
|
||||||
if let Some(path) = to.parent() {
|
if let Some(path) = to.parent() {
|
||||||
debug!("Creating directory {:?}", path);
|
debug!("Creating directory {:?}", path);
|
||||||
actix_fs::create_dir_all(path.to_owned()).await?;
|
tokio::fs::create_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Checking if {:?} already exists", to);
|
debug!("Checking if {:?} already exists", to);
|
||||||
if let Err(e) = actix_fs::metadata(to.clone()).await {
|
if let Err(e) = tokio::fs::metadata(&to).await {
|
||||||
if e.kind() != Some(std::io::ErrorKind::NotFound) {
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -950,16 +950,30 @@ where
|
||||||
|
|
||||||
debug!("Writing stream to {:?}", to);
|
debug!("Writing stream to {:?}", to);
|
||||||
|
|
||||||
let file = actix_fs::file::create(to).await?;
|
let to1 = to.clone();
|
||||||
|
let fut = async move {
|
||||||
|
let mut file = tokio::fs::File::create(to1).await?;
|
||||||
|
|
||||||
actix_fs::file::write_stream_faster(file, stream.map_err(UploadError::from)).await?;
|
while let Some(res) = next(&mut stream).await {
|
||||||
|
let mut bytes = res?;
|
||||||
|
file.write_all_buf(&mut bytes).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = fut.await {
|
||||||
|
error!("Failed to save file: {}", e);
|
||||||
|
let _ = tokio::fs::remove_file(to).await;
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_path(path: sled::IVec) -> Result<(), UploadError> {
|
async fn remove_path(path: sled::IVec) -> Result<(), UploadError> {
|
||||||
let path_string = String::from_utf8(path.to_vec())?;
|
let path_string = String::from_utf8(path.to_vec())?;
|
||||||
actix_fs::remove_file(path_string).await?;
|
tokio::fs::remove_file(path_string).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue