use std::io::Write;
use axum::extract::{Path, State};
use axum::http::header;
use axum::response::{IntoResponse, Response};
use flate2::write::GzEncoder;
use crate::adapter_http_server::ServerState;
#[tracing::instrument(skip_all)]
pub async fn handler<AR>(State(state): State<ServerState<AR>>, Path(lang): Path<String>) -> Response
where
AR: crate::domain::prelude::AptRepositoryReader + Clone,
{
tracing::debug!(lang = %lang, "serving translation file");
if lang == "en" {
match state.apt_repository.translation_file().await {
Ok(content) => {
return ([(header::CONTENT_TYPE, "text/plain")], content).into_response();
}
Err(err) => {
tracing::error!(error = ?err, "unable to fetch translation file");
}
}
}
([(header::CONTENT_TYPE, "text/plain")], "").into_response()
}
#[tracing::instrument(skip_all)]
pub async fn gz_handler<AR>(
State(state): State<ServerState<AR>>,
Path(lang): Path<String>,
) -> Response
where
AR: crate::domain::prelude::AptRepositoryReader + Clone,
{
tracing::debug!(lang = %lang, "serving gzip translation file");
if lang == "en" {
match state.apt_repository.translation_file().await {
Ok(content) => {
let mut encoder = GzEncoder::new(Vec::new(), flate2::Compression::default());
if encoder.write_all(content.as_bytes()).is_ok()
&& let Ok(compressed) = encoder.finish()
{
return ([(header::CONTENT_TYPE, "application/gzip")], compressed)
.into_response();
}
tracing::error!("unable to compress translation file");
}
Err(err) => {
tracing::error!(error = ?err, "unable to fetch translation file");
}
}
}
const EMPTY_GZIP: &[u8] = &[
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
([(header::CONTENT_TYPE, "application/gzip")], EMPTY_GZIP).into_response()
}
#[tracing::instrument(skip_all)]
pub async fn bz2_handler(Path(lang): Path<String>) -> Response {
tracing::debug!(lang = %lang, "serving empty bzip2 translation file");
const EMPTY_BZ2: &[u8] = &[
0x42, 0x5a, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, ];
([(header::CONTENT_TYPE, "application/x-bzip2")], EMPTY_BZ2).into_response()
}
#[tracing::instrument(skip_all)]
pub async fn xz_handler(Path(lang): Path<String>) -> Response {
tracing::debug!(lang = %lang, "serving empty xz translation file");
const EMPTY_XZ: &[u8] = &[
0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x00, 0xff, 0x12, 0xd9, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a, ];
([(header::CONTENT_TYPE, "application/x-xz")], EMPTY_XZ).into_response()
}
#[cfg(test)]
mod tests {
use axum::extract::Path;
use axum::http::StatusCode;
use axum::response::IntoResponse;
#[tokio::test]
async fn test_bz2_translation() {
let response = super::bz2_handler(Path("en".to_string()))
.await
.into_response();
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.headers().get("content-type").unwrap(),
"application/x-bzip2"
);
}
#[tokio::test]
async fn test_xz_translation() {
let response = super::xz_handler(Path("en".to_string()))
.await
.into_response();
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.headers().get("content-type").unwrap(),
"application/x-xz"
);
}
}