Compare commits

..

1 Commits

Author SHA1 Message Date
78d61e7e0c wip: json errors 2024-05-29 19:59:02 +03:00
5 changed files with 70 additions and 16 deletions

View File

@ -20,3 +20,5 @@ http = "1.1.0"
tokio-util = { version = "0.7.11", features = ["io"] } tokio-util = { version = "0.7.11", features = ["io"] }
futures-util = "0.3.30" futures-util = "0.3.30"
infer = "0.15.0" infer = "0.15.0"
tower = { version = "0.4.13", features = ["timeout"] }
tower-service = "0.3.2"

View File

@ -51,14 +51,12 @@ Mandatory fields:
- `sample_rate` - `sample_rate`
- `url` (for `/enqueue_url`) - `url` (for `/enqueue_url`)
# Configuration You can change configuration using this environment variables:
You can change configuration using these environment variables:
- `LISTEN` - change this environment variable to change TCP listen address. Default is `0.0.0.0:8090`. - `LISTEN` - change this environment variable to change TCP listen address. Default is `0.0.0.0:8090`.
- `NUM_WORKERS` - can be used to change how many threads will be used to transcode incoming files. Default is equal to logical CPUs. - `NUM_WORKERS` - can be used to change how many threads will be used to transcode incoming files. Default is equal to logical CPUs.
- `TEMP_DIR` - this can be used to change which directory should be used to store incoming downloads and transcoding results. Useful if you want to use a Docker volume for this. Default is system temp directory (`/tmp` for Linux). - `TEMP_DIR` - this can be used to change which directory should be used to store incoming downloads and transcoding results. Useful if you want to use a Docker volume for this. Default is system temp directory (`/tmp` for Linux).
- `LOG_LEVEL` - changes log verbosity, default is `info`. - `LOG_LEVEL` - changes log verbosity, default is `info`.
- `MAX_BODY_SIZE` - changes max body size for `/enqueue` and max file size for `/enqueue_url`. Default is 1GB (`file` in `/enqueue` request has an upper limit of `1GiB`). - `MAX_BODY_SIZE` - changes max body size for `/enqueue`. Default is 100MB, maximum is 1GiB (which is still *a lot* for the multipart form).
- `RESULT_TTL_SEC` - sets result ttl in seconds, minimum 60 seconds. Default is 3600 (transcoding results are being kept and can be downloaded for an hour). - `RESULT_TTL_SEC` - sets result ttl in seconds, minimum 60 seconds. Default is 3600 (transcoding results are being kept and can be downloaded for an hour).
- `FFMPEG_VERBOSE` - if set to `1` changes FFmpeg log level from quiet to trace. - `FFMPEG_VERBOSE` - if set to `1` changes FFmpeg log level from quiet to trace.

47
src/json_error.rs Normal file
View File

@ -0,0 +1,47 @@
use tower::Layer;
use crate::json_error::private::JsonErrorService;
#[derive(Debug, Clone)]
#[must_use]
pub struct JsonError;
impl<S> Layer<S> for JsonError {
type Service = JsonErrorService<S>;
fn layer(&self, inner: S) -> Self::Service {
JsonErrorService { inner }
}
}
mod private {
use std::task::Context;
use http::Request;
use tower_service::Service;
#[derive(Debug, Clone, Copy)]
pub struct JsonErrorService<S> {
pub(super) inner: S,
}
impl<B, S> Service<Request<B>> for JsonErrorService<S>
where
S: Service<Request<B>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
#[inline]
fn poll_ready(&mut self, cx: &mut Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
#[inline]
fn call(&mut self, mut req: Request<B>) -> Self::Future {
let response = self.inner.call(req);
response
}
}
}

View File

@ -11,6 +11,7 @@ mod server;
mod task; mod task;
mod thread_pool; mod thread_pool;
mod transcoder; mod transcoder;
mod json_error;
const WORK_DIR_IN_OUT_LIFETIME: u64 = 60 * 60; const WORK_DIR_IN_OUT_LIFETIME: u64 = 60 * 60;

View File

@ -1,35 +1,37 @@
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use axum::{Json, Router};
use axum::body::Body;
use axum::body::Bytes;
use axum::extract::{DefaultBodyLimit, Path, State}; use axum::extract::{DefaultBodyLimit, Path, State};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::routing::{get, post}; use axum::routing::{get, post};
use axum::{Json, Router};
use axum_typed_multipart::TypedMultipart; use axum_typed_multipart::TypedMultipart;
use futures_util::StreamExt;
use tokio::fs; use tokio::fs;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::time::interval; use tokio::time::interval;
use tokio_util::io::ReaderStream;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use tracing::{debug, error}; use tracing::{debug, error};
use uuid::Uuid; use uuid::Uuid;
use crate::dto::{ConvertRequest, ConvertResponse, ConvertURLRequest, ErrorResponse}; use crate::dto::{ConvertRequest, ConvertResponse, ConvertURLRequest, ErrorResponse};
use crate::task::{Task, TaskParams};
use crate::thread_pool::ThreadPool;
use crate::filepath; use crate::filepath;
use crate::filepath::{in_file_path, out_file_path}; use crate::filepath::{in_file_path, out_file_path};
use axum::body::Body; use crate::json_error::JsonError;
use axum::body::Bytes; use crate::task::{Task, TaskParams};
use futures_util::StreamExt; use crate::thread_pool::ThreadPool;
use std::sync::Arc;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio_util::io::ReaderStream;
const CONTENT_LENGTH_LIMIT: usize = 1024 * 1024 * 1024; // 1GB const CONTENT_LENGTH_LIMIT: usize = 100 * 1024 * 1024;
pub struct Server { pub struct Server {
thread_pool: Arc<ThreadPool>, thread_pool: Arc<ThreadPool>,
@ -73,7 +75,11 @@ impl Server {
.route("/enqueue_url", post(enqueue_url)) .route("/enqueue_url", post(enqueue_url))
.route("/get/:identifier", get(download_file)) .route("/get/:identifier", get(download_file))
.with_state(this) .with_state(this)
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http()) .layer(TraceLayer::new_for_http())
.layer(JsonError)
)
.fallback(handler_not_found); .fallback(handler_not_found);
tracing::info!("listening on {addr}"); tracing::info!("listening on {addr}");