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