initial commit

This commit is contained in:
Pavel 2024-05-24 23:44:26 +03:00
commit 8bbb487c4b
8 changed files with 196 additions and 0 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
[*.rs]
indent_size = 4
indent_style = space
end_of_file_newline = lf
trim_trailing_whitespace = true
insert_spaces = true
match_opening_closing_characters = true
[*.toml]
indent_size = 2
indent_style = space
end_of_file_newline = lf
trim_trailing_whitespace = true
insert_spaces = false
match_opening_closing_characters = false

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Editor generated files
*.rs~
*.toml~
Cargo.lock
target/
# Compiler output files
out/
# Build artifacts
*.exe
*.so
*.dylib
# IDE project files
.idea/
.cproject/
.project/
# Visual Studio Code
.vscode/
# Other editor settings
.idea/private/
.idea/workspace.xml
# macOS specific files
.DS_Store

15
Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "atranscoder-rpc"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = { version = "0.7.5", features = ["macros", "multipart"] }
axum_typed_multipart = "0.11.1"
serde = { version = "1.0.202", features = ["derive"] }
tokio = { version = "1.37.0", features = ["rt-multi-thread"] }
tempfile = "3.10.1"
uuid = { version = "1.8.0", features = ["v4"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tower-http = { version = "0.5.2", features = ["trace"] }

25
LICENSE.md Normal file
View File

@ -0,0 +1,25 @@
The MIT License (MIT)
=====================
Copyright © `2024` `Pavel Kovalenko`
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# atranscoder-rpc
Audio transcoder with simple HTTP API. Work in progress, nothing is implemented yet...

26
src/dto.rs Normal file
View File

@ -0,0 +1,26 @@
use axum_typed_multipart::{FieldData, TryFromMultipart};
use serde::{Deserialize, Serialize};
use tempfile::NamedTempFile;
#[derive(Serialize, Deserialize)]
pub struct Error {
pub error: String,
}
#[derive(Serialize, Deserialize)]
pub struct TaskResponse {
pub id: Option<String>,
pub error: Option<String>,
}
#[derive(TryFromMultipart)]
#[try_from_multipart(rename_all = "camelCase")]
pub struct Task {
pub codec: String,
pub bit_rate: usize,
pub max_bit_rate: usize,
pub channel_layout: String,
#[form_data(limit = "25MiB")]
pub file: FieldData<NamedTempFile>,
}

17
src/main.rs Normal file
View File

@ -0,0 +1,17 @@
use crate::server::serve;
use std::env;
use tracing_subscriber::EnvFilter;
mod dto;
mod server;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_env("LOG_LEVEL"))
.init();
let addr = env::var("LISTEN").unwrap_or_else(|_| "0.0.0.0:8090".to_string());
serve(&addr).await.expect("Cannot bind the addr")
}

67
src/server.rs Normal file
View File

@ -0,0 +1,67 @@
use axum::extract::DefaultBodyLimit;
use axum::http::StatusCode;
use axum::routing::{get, post};
use axum::{Json, Router};
use axum_typed_multipart::TypedMultipart;
use std::path::Path;
use tokio::net::TcpListener;
use tower_http::trace::TraceLayer;
use uuid::Uuid;
use crate::dto;
use crate::dto::{Task, TaskResponse};
const CONTENT_LENGTH_LIMIT: usize = 30 * 1024 * 1024;
pub async fn serve(addr: &str) -> std::io::Result<()> {
let app = Router::new()
.route(
"/enqueue",
post(enqueue_file).layer(DefaultBodyLimit::max(CONTENT_LENGTH_LIMIT)),
)
.route("/download", get(download_file))
.layer(TraceLayer::new_for_http());
tracing::info!("listening on {addr}");
let listener = match TcpListener::bind(addr).await {
Ok(listen) => listen,
Err(err) => return Err(err),
};
axum::serve(listener, app).await
}
async fn enqueue_file(
TypedMultipart(Task { file, .. }): TypedMultipart<Task>,
) -> (StatusCode, Json<TaskResponse>) {
let task_id = Uuid::new_v4().to_string();
let path = Path::new(
std::env::temp_dir()
.to_str()
.expect("Cannot get temporary directory"),
)
.join(format!("{}.bin", task_id));
match file.contents.persist(path) {
Ok(_) => (
StatusCode::CREATED,
Json::from(TaskResponse {
id: Option::from(task_id),
error: None,
}),
),
Err(_) => (
StatusCode::CREATED,
Json::from(TaskResponse {
id: Option::from(task_id),
error: Some(String::from("Cannot save the file")),
}),
),
}
}
async fn download_file() -> (StatusCode, Json<dto::Error>) {
let resp = dto::Error {
error: String::from("Not implemented yet."),
};
(StatusCode::INTERNAL_SERVER_ERROR, Json(resp))
}