initial commit
This commit is contained in:
commit
8bbb487c4b
15
.editorconfig
Normal file
15
.editorconfig
Normal 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
28
.gitignore
vendored
Normal 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
15
Cargo.toml
Normal 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
25
LICENSE.md
Normal 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
3
README.md
Normal 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
26
src/dto.rs
Normal 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
17
src/main.rs
Normal 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
67
src/server.rs
Normal 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))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user